R600MCCodeEmitter.cpp revision 256281
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 29using namespace llvm; 30 31namespace { 32 33class 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 40public: 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; 53private: 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 67enum RegElement { 68 ELEMENT_X = 0, 69 ELEMENT_Y, 70 ELEMENT_Z, 71 ELEMENT_W 72}; 73 74enum 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 84enum 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 99MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII, 100 const MCRegisterInfo &MRI, 101 const MCSubtargetInfo &STI) { 102 return new R600MCCodeEmitter(MCII, MRI, STI); 103} 104 105void 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 193void R600MCCodeEmitter::EmitByte(unsigned int Byte, raw_ostream &OS) const { 194 OS.write((uint8_t) Byte & 0xff); 195} 196 197void 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 203void 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 209unsigned R600MCCodeEmitter::getHWRegChan(unsigned reg) const { 210 return MRI.getEncodingValue(reg) >> HW_CHAN_SHIFT; 211} 212 213unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const { 214 return MRI.getEncodingValue(RegNo) & HW_REG_MASK; 215} 216 217uint64_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" 235