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