nv50/ir/tgsi: Infer function inputs/outputs.
[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