OSDN Git Service

radeonsi: initial WIP SI code
[android-x86/external-mesa.git] / src / gallium / drivers / radeon / R600CodeEmitter.cpp
1 //===-- R600CodeEmitter.cpp - TODO: Add brief description -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // TODO: Add full description
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "AMDGPU.h"
15 #include "AMDGPUUtil.h"
16 #include "AMDILCodeEmitter.h"
17 #include "AMDILInstrInfo.h"
18 #include "AMDILMachineFunctionInfo.h"
19 #include "AMDILUtilityFunctions.h"
20 #include "R600RegisterInfo.h"
21 #include "llvm/CodeGen/MachineFunctionPass.h"
22 #include "llvm/CodeGen/MachineInstrBuilder.h"
23 #include "llvm/CodeGen/MachineRegisterInfo.h"
24 #include "llvm/Support/DataTypes.h"
25 #include "llvm/Support/FormattedStream.h"
26 #include "llvm/Target/TargetMachine.h"
27
28 #include <stdio.h>
29
30 #define SRC_BYTE_COUNT 11
31 #define DST_BYTE_COUNT 5
32
33 using namespace llvm;
34
35 namespace {
36
37   class R600CodeEmitter : public MachineFunctionPass, public AMDILCodeEmitter {
38
39   private:
40
41   static char ID;
42   formatted_raw_ostream &_OS;
43   const TargetMachine * TM;
44   const MachineRegisterInfo * MRI;
45   AMDILMachineFunctionInfo * MFI;
46   const R600RegisterInfo * TRI;
47   bool evergreenEncoding;
48
49   bool isReduction;
50   unsigned reductionElement;
51   bool isLast;
52
53   unsigned section_start;
54
55   public:
56
57   R600CodeEmitter(formatted_raw_ostream &OS) : MachineFunctionPass(ID),
58       _OS(OS), TM(NULL), evergreenEncoding(false), isReduction(false),
59       isLast(true) { }
60
61   const char *getPassName() const { return "AMDGPU Machine Code Emitter"; }
62
63   bool runOnMachineFunction(MachineFunction &MF);
64   virtual uint64_t getMachineOpValue(const MachineInstr &MI,
65                                      const MachineOperand &MO) const;
66
67   private:
68
69   void emitALUInstr(MachineInstr  &MI);
70   void emitSrc(const MachineOperand & MO);
71   void emitDst(const MachineOperand & MO);
72   void emitALU(MachineInstr &MI, unsigned numSrc);
73   void emitTexInstr(MachineInstr &MI);
74   void emitFCInstr(MachineInstr &MI);
75
76   unsigned int getHWInst(const MachineInstr &MI);
77
78   void emitNullBytes(unsigned int byteCount);
79
80   void emitByte(unsigned int byte);
81
82   void emitTwoBytes(uint32_t bytes);
83
84   void emit(uint32_t value);
85   void emit(uint64_t value);
86
87   unsigned getHWReg(unsigned regNo) const;
88
89   unsigned getElement(unsigned regNo);
90
91 };
92
93 } /* End anonymous namespace */
94
95 #define WRITE_MASK_X 0x1
96 #define WRITE_MASK_Y 0x2
97 #define WRITE_MASK_Z 0x4
98 #define WRITE_MASK_W 0x8
99
100 enum RegElement {
101   ELEMENT_X = 0,
102   ELEMENT_Y,
103   ELEMENT_Z,
104   ELEMENT_W
105 };
106
107 enum InstrTypes {
108   INSTR_ALU = 0,
109   INSTR_TEX,
110   INSTR_FC,
111   INSTR_NATIVE,
112   INSTR_VTX
113 };
114
115 enum FCInstr {
116   FC_IF = 0,
117   FC_ELSE,
118   FC_ENDIF,
119   FC_BGNLOOP,
120   FC_ENDLOOP,
121   FC_BREAK,
122   FC_BREAK_NZ_INT,
123   FC_CONTINUE,
124   FC_BREAK_Z_INT
125 };
126
127 enum TextureTypes {
128   TEXTURE_1D = 1,
129   TEXTURE_2D, 
130   TEXTURE_3D,
131   TEXTURE_CUBE,
132   TEXTURE_RECT,
133   TEXTURE_SHADOW1D,
134   TEXTURE_SHADOW2D,
135   TEXTURE_SHADOWRECT,     
136   TEXTURE_1D_ARRAY,       
137   TEXTURE_2D_ARRAY,
138   TEXTURE_SHADOW1D_ARRAY,
139   TEXTURE_SHADOW2D_ARRAY
140 };
141
142 char R600CodeEmitter::ID = 0;
143
144 FunctionPass *llvm::createR600CodeEmitterPass(formatted_raw_ostream &OS) {
145   return new R600CodeEmitter(OS);
146 }
147
148 bool R600CodeEmitter::runOnMachineFunction(MachineFunction &MF) {
149
150   TM = &MF.getTarget();
151   MRI = &MF.getRegInfo();
152   MFI = MF.getInfo<AMDILMachineFunctionInfo>();
153   TRI = static_cast<const R600RegisterInfo *>(TM->getRegisterInfo());
154   const AMDILSubtarget &STM = TM->getSubtarget<AMDILSubtarget>();
155   std::string gpu = STM.getDeviceName();
156   if (!gpu.compare(0,3, "rv7")) {
157     evergreenEncoding = false;
158   } else {
159     evergreenEncoding = true;
160   }
161   const AMDGPUTargetMachine *amdtm =
162     static_cast<const AMDGPUTargetMachine *>(&MF.getTarget());
163
164   if (amdtm->shouldDumpCode()) {
165     MF.dump();
166   }
167
168   for (MachineFunction::iterator BB = MF.begin(), BB_E = MF.end();
169                                                   BB != BB_E; ++BB) {
170      MachineBasicBlock &MBB = *BB;
171      for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end();
172                                                        I != E; ++I) {
173           MachineInstr &MI = *I;
174           if (MI.getNumOperands() > 1 && MI.getOperand(0).isReg() && MI.getOperand(0).isDead()) {
175             continue;
176           }
177           if (isTexOp(MI.getOpcode())) {
178             emitTexInstr(MI);
179           } else if (isFCOp(MI.getOpcode())){
180             emitFCInstr(MI);
181           } else if (isReductionOp(MI.getOpcode())) {
182             isReduction = true;
183             isLast = false;
184             for (reductionElement = 0; reductionElement < 4; reductionElement++) {
185               isLast = (reductionElement == 3);
186               emitALUInstr(MI);
187             }
188             isReduction = false;
189           } else if (MI.getOpcode() == AMDIL::RETURN) {
190             continue;
191           } else {
192             switch(MI.getOpcode()) {
193             case AMDIL::RAT_WRITE_CACHELESS_eg:
194               {
195                 /* XXX: Support for autoencoding 64-bit instructions was added
196                  * in LLVM 3.1.  Until we drop support for 3.0, we will use Magic
197                  * numbers for the high bits. */
198                   uint64_t high = 0x95c0100000000000;
199                   uint64_t inst = getBinaryCodeForInstr(MI);
200                   inst |= high;
201                 /* Set End Of Program bit */
202                 /* XXX: Need better check of end of program.  EOP should be
203                  * encoded in one of the operands of the MI, and it should be
204                  * set in a prior pass. */
205                 MachineBasicBlock::iterator NextI = llvm::next(I);
206                 MachineInstr &NextMI = *NextI;
207                 if (NextMI.getOpcode() == AMDIL::RETURN) {
208                   inst |= (((uint64_t)1) << 53);
209                 }
210                 emitByte(INSTR_NATIVE);
211                 emit(inst);
212                 break;
213               }
214             case AMDIL::VTX_READ_eg:
215               {
216                 emitByte(INSTR_VTX);
217                 /* inst */
218                 emitByte(0);
219
220                 /* fetch_type */
221                 emitByte(2);
222
223                 /* buffer_id */
224                 emitByte(MI.getOperand(2).getImm());
225
226                 /* src_gpr */
227                 emitByte(getHWReg(MI.getOperand(1).getReg()));
228
229                 /* src_sel_x */
230                 emitByte(TRI->getHWRegChan(MI.getOperand(1).getReg()));
231
232                 /* mega_fetch_count */
233                 emitByte(3);
234
235                 /* dst_gpr */
236                 emitByte(getHWReg(MI.getOperand(0).getReg()));
237
238                 /* dst_sel_x */
239                 emitByte(0);
240
241                 /* dst_sel_y */
242                 emitByte(7);
243
244                 /* dst_sel_z */
245                 emitByte(7);
246
247                 /* dst_sel_w */
248                 emitByte(7);
249
250                 /* use_const_fields */
251                 emitByte(1);
252
253                 /* data_format */
254                 emitByte(0);
255
256                 /* num_format_all */
257                 emitByte(0);
258
259                 /* format_comp_all */
260                 emitByte(0);
261
262                 /* srf_mode_all */
263                 emitByte(0);
264
265                 /* offset */
266                 emitByte(0);
267
268                 /* endian */
269                 emitByte(0);
270                 break;
271               }
272
273             default:
274               emitALUInstr(MI);
275               break;
276           }
277         }
278     }
279   }
280   return false;
281 }
282
283 void R600CodeEmitter::emitALUInstr(MachineInstr &MI)
284 {
285
286   unsigned numOperands = MI.getNumOperands();
287
288    /* Some instructions are just place holder instructions that represent
289     * operations that the GPU does automatically.  They should be ignored. */
290   if (isPlaceHolderOpcode(MI.getOpcode())) {
291     return;
292   }
293
294   /* We need to handle some opcodes differently */
295   switch (MI.getOpcode()) {
296     default: break;
297
298     /* Custom swizzle instructions, ignore the last two operands */
299     case AMDIL::SET_CHAN:
300       numOperands = 2;
301       break;
302
303     case AMDIL::VEXTRACT_v4f32:
304       numOperands = 2;
305       break;
306
307     /* XXX: Temp Hack */
308     case AMDIL::STORE_OUTPUT:
309       numOperands = 2;
310       break;
311   }
312
313   /* XXX Check if instruction writes a result */
314   if (numOperands < 1) {
315     return;
316   }
317   const MachineOperand dstOp = MI.getOperand(0);
318
319   /* Emit instruction type */
320   emitByte(0);
321
322   unsigned int opIndex;
323   for (opIndex = 1; opIndex < numOperands; opIndex++) {
324     /* Literal constants are always stored as the last operand. */
325     if (MI.getOperand(opIndex).isImm() || MI.getOperand(opIndex).isFPImm()) {
326       break;
327     }
328     emitSrc(MI.getOperand(opIndex));
329   }
330
331     /* Emit zeros for unused sources */
332   for ( ; opIndex < 4; opIndex++) {
333     emitNullBytes(SRC_BYTE_COUNT);
334   }
335
336   emitDst(dstOp);
337
338   emitALU(MI, numOperands - 1);
339 }
340
341 void R600CodeEmitter::emitSrc(const MachineOperand & MO)
342 {
343   uint32_t value = 0;
344   /* Emit the source select (2 bytes).  For GPRs, this is the register index.
345    * For other potential instruction operands, (e.g. constant registers) the
346    * value of the source select is defined in the r600isa docs. */
347   if (MO.isReg()) {
348     unsigned reg = MO.getReg();
349     emitTwoBytes(getHWReg(reg));
350     if (reg == AMDIL::ALU_LITERAL_X) {
351       const MachineInstr * parent = MO.getParent();
352       unsigned immOpIndex = parent->getNumOperands() - 1;
353       MachineOperand immOp = parent->getOperand(immOpIndex);
354       if (immOp.isFPImm()) {
355         value = immOp.getFPImm()->getValueAPF().bitcastToAPInt().getZExtValue();
356       } else {
357         assert(immOp.isImm());
358         value = immOp.getImm();
359       }
360     }
361   } else {
362     /* XXX: Handle other operand types. */
363     emitTwoBytes(0);
364   }
365
366   /* Emit the source channel (1 byte) */
367   if (isReduction) {
368     emitByte(reductionElement);
369   } else if (MO.isReg()) {
370     const MachineInstr * parent = MO.getParent();
371     /* The source channel for EXTRACT is stored in operand 2. */
372     if (parent->getOpcode() == AMDIL::VEXTRACT_v4f32) {
373       emitByte(parent->getOperand(2).getImm());
374     } else {
375       emitByte(TRI->getHWRegChan(MO.getReg()));
376     }
377   } else {
378     emitByte(0);
379   }
380
381   /* XXX: Emit isNegated (1 byte) */
382   if ((!(MO.getTargetFlags() & MO_FLAG_ABS))
383       && (MO.getTargetFlags() & MO_FLAG_NEG ||
384      (MO.isReg() &&
385       (MO.getReg() == AMDIL::NEG_ONE || MO.getReg() == AMDIL::NEG_HALF)))){
386     emitByte(1);
387   } else {
388     emitByte(0);
389   }
390
391   /* Emit isAbsolute (1 byte) */
392   if (MO.getTargetFlags() & MO_FLAG_ABS) {
393     emitByte(1);
394   } else {
395     emitByte(0);
396   }
397
398   /* XXX: Emit relative addressing mode (1 byte) */
399   emitByte(0);
400
401   /* Emit kc_bank, This will be adjusted later by r600_asm */
402   emitByte(0);
403
404   /* Emit the literal value, if applicable (4 bytes).  */
405   emit(value);
406
407 }
408
409 void R600CodeEmitter::emitDst(const MachineOperand & MO)
410 {
411   if (MO.isReg()) {
412     /* Emit the destination register index (1 byte) */
413     emitByte(getHWReg(MO.getReg()));
414
415     /* Emit the element of the destination register (1 byte)*/
416     const MachineInstr * parent = MO.getParent();
417     if (isReduction) {
418       emitByte(reductionElement);
419
420     /* The destination element for SET_CHAN is stored in the 3rd operand. */
421     } else if (parent->getOpcode() == AMDIL::SET_CHAN) {
422       emitByte(parent->getOperand(2).getImm());
423     } else if (parent->getOpcode() == AMDIL::VCREATE_v4f32) {
424       emitByte(ELEMENT_X);
425     } else {
426       emitByte(TRI->getHWRegChan(MO.getReg()));
427     }
428
429     /* Emit isClamped (1 byte) */
430     if (MO.getTargetFlags() & MO_FLAG_CLAMP) {
431       emitByte(1);
432     } else {
433       emitByte(0);
434     }
435
436     /* Emit writemask (1 byte).  */
437     if ((isReduction && reductionElement != TRI->getHWRegChan(MO.getReg()))
438          || MO.getTargetFlags() & MO_FLAG_MASK) {
439       emitByte(0);
440     } else {
441       emitByte(1);
442     }
443
444     /* XXX: Emit relative addressing mode */
445     emitByte(0);
446   } else {
447     /* XXX: Handle other operand types.  Are there any for destination regs? */
448     emitNullBytes(DST_BYTE_COUNT);
449   }
450 }
451
452 void R600CodeEmitter::emitALU(MachineInstr &MI, unsigned numSrc)
453 {
454   /* Emit the instruction (2 bytes) */
455   emitTwoBytes(getHWInst(MI));
456
457   /* Emit isLast (for this instruction group) (1 byte) */
458   if (isLast) {
459     emitByte(1);
460   } else {
461     emitByte(0);
462   }
463   /* Emit isOp3 (1 byte) */
464   if (numSrc == 3) {
465     emitByte(1);
466   } else {
467     emitByte(0);
468   }
469
470   /* XXX: Emit predicate (1 byte) */
471   emitByte(0);
472
473   /* XXX: Emit bank swizzle. (1 byte)  Do we need this?  It looks like
474    * r600_asm.c sets it. */
475   emitByte(0);
476
477   /* XXX: Emit bank_swizzle_force (1 byte) Not sure what this is for. */
478   emitByte(0);
479
480   /* XXX: Emit OMOD (1 byte) Not implemented. */
481   emitByte(0);
482
483   /* XXX: Emit index_mode.  I think this is for indirect addressing, so we
484    * don't need to worry about it. */
485   emitByte(0);
486 }
487
488 void R600CodeEmitter::emitTexInstr(MachineInstr &MI)
489 {
490
491   int64_t sampler = MI.getOperand(2).getImm();
492   int64_t textureType = MI.getOperand(3).getImm();
493   unsigned opcode = MI.getOpcode();
494   unsigned srcSelect[4] = {0, 1, 2, 3};
495
496   /* Emit instruction type */
497   emitByte(1);
498
499   /* Emit instruction */
500   emitByte(getHWInst(MI));
501
502   /* XXX: Emit resource id r600_shader.c uses sampler + 1.  Why? */
503   emitByte(sampler + 1 + 1);
504
505   /* Emit source register */
506   emitByte(getHWReg(MI.getOperand(1).getReg()));
507
508   /* XXX: Emit src isRelativeAddress */
509   emitByte(0);
510
511   /* Emit destination register */
512   emitByte(getHWReg(MI.getOperand(0).getReg()));
513
514   /* XXX: Emit dst isRealtiveAddress */
515   emitByte(0);
516
517   /* XXX: Emit dst select */
518   emitByte(0); /* X */
519   emitByte(1); /* Y */
520   emitByte(2); /* Z */
521   emitByte(3); /* W */
522
523   /* XXX: Emit lod bias */
524   emitByte(0);
525
526   /* XXX: Emit coord types */
527   unsigned coordType[4] = {1, 1, 1, 1};
528
529   if (textureType == TEXTURE_RECT
530       || textureType == TEXTURE_SHADOWRECT) {
531     coordType[ELEMENT_X] = 0;
532     coordType[ELEMENT_Y] = 0;
533   }
534
535   if (textureType == TEXTURE_1D_ARRAY
536       || textureType == TEXTURE_SHADOW1D_ARRAY) {
537     if (opcode == AMDIL::TEX_SAMPLE_C_L || opcode == AMDIL::TEX_SAMPLE_C_LB) {
538       coordType[ELEMENT_Y] = 0;
539     } else {
540       coordType[ELEMENT_Z] = 0;
541       srcSelect[ELEMENT_Z] = ELEMENT_Y;
542     }
543   } else if (textureType == TEXTURE_2D_ARRAY
544              || textureType == TEXTURE_SHADOW2D_ARRAY) {
545     coordType[ELEMENT_Z] = 0;
546   }
547
548   for (unsigned i = 0; i < 4; i++) {
549     emitByte(coordType[i]);
550   }
551
552   /* XXX: Emit offsets */
553   emitByte(0); /* X */
554   emitByte(0); /* Y */
555   emitByte(0); /* Z */
556   /* There is no OFFSET_W */
557
558   /* Emit sampler id */
559   emitByte(sampler);
560
561   /* XXX:Emit source select */
562   if ((textureType == TEXTURE_SHADOW1D
563       || textureType == TEXTURE_SHADOW2D
564       || textureType == TEXTURE_SHADOWRECT
565       || textureType == TEXTURE_SHADOW1D_ARRAY)
566       && opcode != AMDIL::TEX_SAMPLE_C_L
567       && opcode != AMDIL::TEX_SAMPLE_C_LB) {
568     srcSelect[ELEMENT_W] = ELEMENT_Z;
569   }
570
571   for (unsigned i = 0; i < 4; i++) {
572     emitByte(srcSelect[i]);
573   }
574 }
575
576 void R600CodeEmitter::emitFCInstr(MachineInstr &MI)
577 {
578   /* Emit instruction type */
579   emitByte(INSTR_FC);
580
581   /* Emit SRC */
582   unsigned numOperands = MI.getNumOperands();
583   if (numOperands > 0) {
584     assert(numOperands == 1);
585     emitSrc(MI.getOperand(0));
586   } else {
587     emitNullBytes(SRC_BYTE_COUNT);
588   }
589
590   /* Emit FC Instruction */
591   enum FCInstr instr;
592   switch (MI.getOpcode()) {
593   case AMDIL::BREAK_LOGICALZ_f32:
594     instr = FC_BREAK;
595     break;
596   case AMDIL::BREAK_LOGICALNZ_i32:
597     instr = FC_BREAK_NZ_INT;
598     break;
599   case AMDIL::BREAK_LOGICALZ_i32:
600     instr = FC_BREAK_Z_INT;
601     break;
602   case AMDIL::CONTINUE_LOGICALNZ_f32:
603     instr = FC_CONTINUE;
604     break;
605   /* XXX: This assumes that all IFs will be if (x != 0).  If we add
606    * optimizations this might not be the case */
607   case AMDIL::IF_LOGICALNZ_f32:
608   case AMDIL::IF_LOGICALNZ_i32:
609     instr = FC_IF;
610     break;
611   case AMDIL::IF_LOGICALZ_f32:
612     abort();
613     break;
614   case AMDIL::ELSE:
615     instr = FC_ELSE;
616     break;
617   case AMDIL::ENDIF:
618     instr = FC_ENDIF;
619     break;
620   case AMDIL::ENDLOOP:
621     instr = FC_ENDLOOP;
622     break;
623   case AMDIL::WHILELOOP:
624     instr = FC_BGNLOOP;
625     break;
626   default:
627     abort();
628     break;
629   }
630   emitByte(instr);
631 }
632
633 #define INSTR_FLOAT2_V(inst, hw) \
634   case AMDIL:: inst##_v4f32: \
635   case AMDIL:: inst##_v2f32: return HW_INST2(hw);
636
637 #define INSTR_FLOAT2_S(inst, hw) \
638   case AMDIL:: inst##_f32: return HW_INST2(hw);
639
640 #define INSTR_FLOAT2(inst, hw) \
641   INSTR_FLOAT2_V(inst, hw) \
642   INSTR_FLOAT2_S(inst, hw)
643
644 unsigned int R600CodeEmitter::getHWInst(const MachineInstr &MI)
645 {
646
647   /* XXX: Lower these to MOV before the code emitter. */
648   switch (MI.getOpcode()) {
649     case AMDIL::STORE_OUTPUT:
650     case AMDIL::VCREATE_v4i32:
651     case AMDIL::VCREATE_v4f32:
652     case AMDIL::VEXTRACT_v4f32:
653     case AMDIL::VINSERT_v4f32:
654     case AMDIL::LOADCONST_i32:
655     case AMDIL::LOADCONST_f32:
656     case AMDIL::MOVE_v4i32:
657     case AMDIL::SET_CHAN:
658     /* Instructons to reinterpret bits as ... */
659     case AMDIL::IL_ASINT_f32:
660     case AMDIL::IL_ASINT_i32:
661     case AMDIL::IL_ASFLOAT_f32:
662     case AMDIL::IL_ASFLOAT_i32:
663       return 0x19;
664
665   default:
666     return getBinaryCodeForInstr(MI);
667   }
668 }
669
670 void R600CodeEmitter::emitNullBytes(unsigned int byteCount)
671 {
672   for (unsigned int i = 0; i < byteCount; i++) {
673     emitByte(0);
674   }
675 }
676
677 void R600CodeEmitter::emitByte(unsigned int byte)
678 {
679   _OS.write((uint8_t) byte & 0xff);
680 }
681 void R600CodeEmitter::emitTwoBytes(unsigned int bytes)
682 {
683   _OS.write((uint8_t) (bytes & 0xff));
684   _OS.write((uint8_t) ((bytes >> 8) & 0xff));
685 }
686
687 void R600CodeEmitter::emit(uint32_t value)
688 {
689   for (unsigned i = 0; i < 4; i++) {
690     _OS.write((uint8_t) ((value >> (8 * i)) & 0xff));
691   }
692 }
693
694 void R600CodeEmitter::emit(uint64_t value)
695 {
696   for (unsigned i = 0; i < 8; i++) {
697     emitByte((value >> (8 * i)) & 0xff);
698   }
699 }
700
701 unsigned R600CodeEmitter::getHWReg(unsigned regNo) const
702 {
703   unsigned hwReg;
704
705   hwReg = TRI->getHWRegIndex(regNo);
706   if (AMDIL::R600_CReg32RegClass.contains(regNo)) {
707     hwReg += 512;
708   }
709   return hwReg;
710 }
711
712 uint64_t R600CodeEmitter::getMachineOpValue(const MachineInstr &MI,
713                                             const MachineOperand &MO) const
714 {
715   if (MO.isReg()) {
716     return getHWReg(MO.getReg());
717   } else {
718     return MO.getImm();
719   }
720 }
721
722
723 RegElement maskBitToElement(unsigned int maskBit)
724 {
725   switch (maskBit) {
726     case WRITE_MASK_X: return ELEMENT_X;
727     case WRITE_MASK_Y: return ELEMENT_Y;
728     case WRITE_MASK_Z: return ELEMENT_Z;
729     case WRITE_MASK_W: return ELEMENT_W;
730     default:
731       assert("Invalid maskBit");
732       return ELEMENT_X;
733   }
734 }
735
736 unsigned int dstSwizzleToWriteMask(unsigned swizzle)
737 {
738   switch(swizzle) {
739   default:
740   case AMDIL_DST_SWIZZLE_DEFAULT:
741     return WRITE_MASK_X | WRITE_MASK_Y | WRITE_MASK_Z | WRITE_MASK_W;
742   case AMDIL_DST_SWIZZLE_X___:
743     return WRITE_MASK_X;
744   case AMDIL_DST_SWIZZLE_XY__:
745     return WRITE_MASK_X | WRITE_MASK_Y;
746   case AMDIL_DST_SWIZZLE_XYZ_:
747     return WRITE_MASK_X | WRITE_MASK_Y | WRITE_MASK_Z;
748   case AMDIL_DST_SWIZZLE_XYZW:
749     return WRITE_MASK_X | WRITE_MASK_Y | WRITE_MASK_Z | WRITE_MASK_W;
750   case AMDIL_DST_SWIZZLE__Y__:
751     return WRITE_MASK_Y;
752   case AMDIL_DST_SWIZZLE__YZ_:
753     return WRITE_MASK_Y | WRITE_MASK_Z;
754   case AMDIL_DST_SWIZZLE__YZW:
755     return WRITE_MASK_Y | WRITE_MASK_Z | WRITE_MASK_W;
756   case AMDIL_DST_SWIZZLE___Z_:
757     return WRITE_MASK_Z;
758   case AMDIL_DST_SWIZZLE___ZW:
759     return WRITE_MASK_Z | WRITE_MASK_W;
760   case AMDIL_DST_SWIZZLE____W:
761     return WRITE_MASK_W;
762   case AMDIL_DST_SWIZZLE_X_ZW:
763     return WRITE_MASK_X | WRITE_MASK_Z | WRITE_MASK_W;
764   case AMDIL_DST_SWIZZLE_XY_W:
765     return WRITE_MASK_X | WRITE_MASK_Y | WRITE_MASK_W;
766   case AMDIL_DST_SWIZZLE_X_Z_:
767     return WRITE_MASK_X | WRITE_MASK_Z;
768   case AMDIL_DST_SWIZZLE_X__W:
769     return WRITE_MASK_X | WRITE_MASK_W;
770   case AMDIL_DST_SWIZZLE__Y_W:
771     return WRITE_MASK_Y | WRITE_MASK_W;
772   }
773 }
774
775 #include "AMDILGenCodeEmitter.inc"
776