]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/llvm/lib/Target/R600/MCTargetDesc/R600MCCodeEmitter.cpp
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / llvm / lib / Target / R600 / MCTargetDesc / R600MCCodeEmitter.cpp
1 //===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===//
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 /// \file
11 ///
12 /// \brief The R600 code emitter produces machine code that can be executed
13 /// directly on the GPU device.
14 //
15 //===----------------------------------------------------------------------===//
16
17 #include "R600Defines.h"
18 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
19 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
20 #include "llvm/MC/MCCodeEmitter.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCInst.h"
23 #include "llvm/MC/MCInstrInfo.h"
24 #include "llvm/MC/MCRegisterInfo.h"
25 #include "llvm/MC/MCSubtargetInfo.h"
26 #include "llvm/Support/raw_ostream.h"
27 #include <stdio.h>
28
29 using namespace llvm;
30
31 namespace {
32
33 class R600MCCodeEmitter : public AMDGPUMCCodeEmitter {
34   R600MCCodeEmitter(const R600MCCodeEmitter &) LLVM_DELETED_FUNCTION;
35   void operator=(const R600MCCodeEmitter &) LLVM_DELETED_FUNCTION;
36   const MCInstrInfo &MCII;
37   const MCRegisterInfo &MRI;
38   const MCSubtargetInfo &STI;
39
40 public:
41
42   R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
43                     const MCSubtargetInfo &sti)
44     : MCII(mcii), MRI(mri), STI(sti) { }
45
46   /// \brief Encode the instruction and write it to the OS.
47   virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
48                          SmallVectorImpl<MCFixup> &Fixups) const;
49
50   /// \returns the encoding for an MCOperand.
51   virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
52                                      SmallVectorImpl<MCFixup> &Fixups) const;
53 private:
54
55   void EmitByte(unsigned int byte, raw_ostream &OS) const;
56
57   void Emit(uint32_t value, raw_ostream &OS) const;
58   void Emit(uint64_t value, raw_ostream &OS) const;
59
60   unsigned getHWRegChan(unsigned reg) const;
61   unsigned getHWReg(unsigned regNo) const;
62
63 };
64
65 } // End anonymous namespace
66
67 enum RegElement {
68   ELEMENT_X = 0,
69   ELEMENT_Y,
70   ELEMENT_Z,
71   ELEMENT_W
72 };
73
74 enum FCInstr {
75   FC_IF_PREDICATE = 0,
76   FC_ELSE,
77   FC_ENDIF,
78   FC_BGNLOOP,
79   FC_ENDLOOP,
80   FC_BREAK_PREDICATE,
81   FC_CONTINUE
82 };
83
84 enum TextureTypes {
85   TEXTURE_1D = 1,
86   TEXTURE_2D,
87   TEXTURE_3D,
88   TEXTURE_CUBE,
89   TEXTURE_RECT,
90   TEXTURE_SHADOW1D,
91   TEXTURE_SHADOW2D,
92   TEXTURE_SHADOWRECT,
93   TEXTURE_1D_ARRAY,
94   TEXTURE_2D_ARRAY,
95   TEXTURE_SHADOW1D_ARRAY,
96   TEXTURE_SHADOW2D_ARRAY
97 };
98
99 MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII,
100                                            const MCRegisterInfo &MRI,
101                                            const MCSubtargetInfo &STI) {
102   return new R600MCCodeEmitter(MCII, MRI, STI);
103 }
104
105 void R600MCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
106                                        SmallVectorImpl<MCFixup> &Fixups) const {
107   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
108   if (MI.getOpcode() == AMDGPU::RETURN ||
109     MI.getOpcode() == AMDGPU::FETCH_CLAUSE ||
110     MI.getOpcode() == AMDGPU::ALU_CLAUSE ||
111     MI.getOpcode() == AMDGPU::BUNDLE ||
112     MI.getOpcode() == AMDGPU::KILL) {
113     return;
114   } else if (IS_VTX(Desc)) {
115     uint64_t InstWord01 = getBinaryCodeForInstr(MI, Fixups);
116     uint32_t InstWord2 = MI.getOperand(2).getImm(); // Offset
117     InstWord2 |= 1 << 19;
118
119     Emit(InstWord01, OS);
120     Emit(InstWord2, OS);
121     Emit((u_int32_t) 0, OS);
122   } else if (IS_TEX(Desc)) {
123     unsigned Opcode = MI.getOpcode();
124     bool HasOffsets = (Opcode == AMDGPU::TEX_LD);
125     unsigned OpOffset = HasOffsets ? 3 : 0;
126     int64_t Sampler = MI.getOperand(OpOffset + 3).getImm();
127     int64_t TextureType = MI.getOperand(OpOffset + 4).getImm();
128
129     uint32_t SrcSelect[4] = {0, 1, 2, 3};
130     uint32_t Offsets[3] = {0, 0, 0};
131     uint64_t CoordType[4] = {1, 1, 1, 1};
132
133     if (HasOffsets)
134       for (unsigned i = 0; i < 3; i++) {
135         int SignedOffset = MI.getOperand(i + 2).getImm();
136         Offsets[i] = (SignedOffset & 0x1F);
137       }
138
139     if (TextureType == TEXTURE_RECT ||
140         TextureType == TEXTURE_SHADOWRECT) {
141       CoordType[ELEMENT_X] = 0;
142       CoordType[ELEMENT_Y] = 0;
143     }
144
145     if (TextureType == TEXTURE_1D_ARRAY ||
146         TextureType == TEXTURE_SHADOW1D_ARRAY) {
147       if (Opcode == AMDGPU::TEX_SAMPLE_C_L ||
148           Opcode == AMDGPU::TEX_SAMPLE_C_LB) {
149         CoordType[ELEMENT_Y] = 0;
150       } else {
151         CoordType[ELEMENT_Z] = 0;
152         SrcSelect[ELEMENT_Z] = ELEMENT_Y;
153       }
154     } else if (TextureType == TEXTURE_2D_ARRAY ||
155         TextureType == TEXTURE_SHADOW2D_ARRAY) {
156       CoordType[ELEMENT_Z] = 0;
157     }
158
159
160     if ((TextureType == TEXTURE_SHADOW1D ||
161         TextureType == TEXTURE_SHADOW2D ||
162         TextureType == TEXTURE_SHADOWRECT ||
163         TextureType == TEXTURE_SHADOW1D_ARRAY) &&
164         Opcode != AMDGPU::TEX_SAMPLE_C_L &&
165         Opcode != AMDGPU::TEX_SAMPLE_C_LB) {
166       SrcSelect[ELEMENT_W] = ELEMENT_Z;
167     }
168
169     uint64_t Word01 = getBinaryCodeForInstr(MI, Fixups) |
170         CoordType[ELEMENT_X] << 60 | CoordType[ELEMENT_Y] << 61 |
171         CoordType[ELEMENT_Z] << 62 | CoordType[ELEMENT_W] << 63;
172     uint32_t Word2 = Sampler << 15 | SrcSelect[ELEMENT_X] << 20 |
173         SrcSelect[ELEMENT_Y] << 23 | SrcSelect[ELEMENT_Z] << 26 |
174         SrcSelect[ELEMENT_W] << 29 | Offsets[0] << 0 | Offsets[1] << 5 |
175         Offsets[2] << 10;
176
177     Emit(Word01, OS);
178     Emit(Word2, OS);
179     Emit((u_int32_t) 0, OS);
180   } else {
181     uint64_t Inst = getBinaryCodeForInstr(MI, Fixups);
182     if ((STI.getFeatureBits() & AMDGPU::FeatureR600ALUInst) &&
183        ((Desc.TSFlags & R600_InstFlag::OP1) ||
184          Desc.TSFlags & R600_InstFlag::OP2)) {
185       uint64_t ISAOpCode = Inst & (0x3FFULL << 39);
186       Inst &= ~(0x3FFULL << 39);
187       Inst |= ISAOpCode << 1;
188     }
189     Emit(Inst, OS);
190   }
191 }
192
193 void R600MCCodeEmitter::EmitByte(unsigned int Byte, raw_ostream &OS) const {
194   OS.write((uint8_t) Byte & 0xff);
195 }
196
197 void R600MCCodeEmitter::Emit(uint32_t Value, raw_ostream &OS) const {
198   for (unsigned i = 0; i < 4; i++) {
199     OS.write((uint8_t) ((Value >> (8 * i)) & 0xff));
200   }
201 }
202
203 void R600MCCodeEmitter::Emit(uint64_t Value, raw_ostream &OS) const {
204   for (unsigned i = 0; i < 8; i++) {
205     EmitByte((Value >> (8 * i)) & 0xff, OS);
206   }
207 }
208
209 unsigned R600MCCodeEmitter::getHWRegChan(unsigned reg) const {
210   return MRI.getEncodingValue(reg) >> HW_CHAN_SHIFT;
211 }
212
213 unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const {
214   return MRI.getEncodingValue(RegNo) & HW_REG_MASK;
215 }
216
217 uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI,
218                                               const MCOperand &MO,
219                                         SmallVectorImpl<MCFixup> &Fixup) const {
220   if (MO.isReg()) {
221     if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags)) {
222       return MRI.getEncodingValue(MO.getReg());
223     } else {
224       return getHWReg(MO.getReg());
225     }
226   } else if (MO.isImm()) {
227     return MO.getImm();
228   } else {
229     assert(0);
230     return 0;
231   }
232 }
233
234 #include "AMDGPUGenMCCodeEmitter.inc"