1 //===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===// 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 // The SI code emitter produces machine code that can be executed directly on 11 // the GPU device. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 16 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h" 17 #include "llvm/MC/MCCodeEmitter.h" 18 #include "llvm/MC/MCContext.h" 19 #include "llvm/MC/MCInst.h" 20 #include "llvm/MC/MCInstrInfo.h" 21 #include "llvm/MC/MCRegisterInfo.h" 22 #include "llvm/MC/MCSubtargetInfo.h" 23 #include "llvm/Support/raw_ostream.h" 24 25 #define LITERAL_REG 255 26 #define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1)) 27 #define SI_INSTR_FLAGS_ENCODING_MASK 0xf 28 29 30 // These must be kept in sync with SIInstructions.td and also the 31 // InstrEncodingInfo array in SIInstrInfo.cpp. 32 // 33 // NOTE: This enum is only used to identify the encoding type within LLVM, 34 // the actual encoding type that is part of the instruction format is different 35 namespace SIInstrEncodingType { 36 enum Encoding { 37 EXP = 0, 38 LDS = 1, 39 MIMG = 2, 40 MTBUF = 3, 41 MUBUF = 4, 42 SMRD = 5, 43 SOP1 = 6, 44 SOP2 = 7, 45 SOPC = 8, 46 SOPK = 9, 47 SOPP = 10, 48 VINTRP = 11, 49 VOP1 = 12, 50 VOP2 = 13, 51 VOP3 = 14, 52 VOPC = 15 53 }; 54 } 55 56 using namespace llvm; 57 58 namespace { 59 class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { 60 SIMCCodeEmitter(const SIMCCodeEmitter &); // DO NOT IMPLEMENT 61 void operator=(const SIMCCodeEmitter &); // DO NOT IMPLEMENT 62 const MCInstrInfo &MCII; 63 const MCSubtargetInfo &STI; 64 MCContext &Ctx; 65 66 public: 67 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, 68 MCContext &ctx) 69 : MCII(mcii), STI(sti), Ctx(ctx) { } 70 71 ~SIMCCodeEmitter() { } 72 73 /// EncodeInstruction - Encode the instruction and write it to the OS. 74 virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 75 SmallVectorImpl<MCFixup> &Fixups) const; 76 77 /// getMachineOpValue - Reutrn the encoding for an MCOperand. 78 virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 79 SmallVectorImpl<MCFixup> &Fixups) const; 80 81 public: 82 83 /// GPRAlign - Encode a sequence of registers with the correct alignment. 84 unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const; 85 86 /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used 87 virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo, 88 SmallVectorImpl<MCFixup> &Fixup) const; 89 90 /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used 91 virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo, 92 SmallVectorImpl<MCFixup> &Fixup) const; 93 94 /// i32LiteralEncode - Encode an i32 literal this is used as an operand 95 /// for an instruction in place of a register. 96 virtual uint64_t i32LiteralEncode(const MCInst &MI, unsigned OpNo, 97 SmallVectorImpl<MCFixup> &Fixup) const; 98 99 /// SMRDmemriEncode - Encoding for SMRD indexed loads 100 virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo, 101 SmallVectorImpl<MCFixup> &Fixup) const; 102 103 /// VOPPostEncode - Post-Encoder method for VOP instructions 104 virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const; 105 106 private: 107 108 ///getEncodingType = Return this SIInstrEncodingType for this instruction. 109 unsigned getEncodingType(const MCInst &MI) const; 110 111 ///getEncodingBytes - Get then size in bytes of this instructions encoding. 112 unsigned getEncodingBytes(const MCInst &MI) const; 113 114 /// getRegBinaryCode - Returns the hardware encoding for a register 115 unsigned getRegBinaryCode(unsigned reg) const; 116 117 /// getHWRegNum - Generated function that returns the hardware encoding for 118 /// a register 119 unsigned getHWRegNum(unsigned reg) const; 120 121 }; 122 123 } // End anonymous namespace 124 125 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 126 const MCSubtargetInfo &STI, 127 MCContext &Ctx) { 128 return new SIMCCodeEmitter(MCII, STI, Ctx); 129 } 130 131 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 132 SmallVectorImpl<MCFixup> &Fixups) const { 133 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); 134 unsigned bytes = getEncodingBytes(MI); 135 for (unsigned i = 0; i < bytes; i++) { 136 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 137 } 138 } 139 140 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 141 const MCOperand &MO, 142 SmallVectorImpl<MCFixup> &Fixups) const { 143 if (MO.isReg()) { 144 return getRegBinaryCode(MO.getReg()); 145 } else if (MO.isImm()) { 146 return MO.getImm(); 147 } else if (MO.isFPImm()) { 148 // XXX: Not all instructions can use inline literals 149 // XXX: We should make sure this is a 32-bit constant 150 return LITERAL_REG; 151 } else{ 152 llvm_unreachable("Encoding of this operand type is not supported yet."); 153 } 154 return 0; 155 } 156 157 //===----------------------------------------------------------------------===// 158 // Custom Operand Encodings 159 //===----------------------------------------------------------------------===// 160 161 unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo, 162 unsigned shift) const { 163 unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg()); 164 return regCode >> shift; 165 return 0; 166 } 167 unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI, 168 unsigned OpNo , 169 SmallVectorImpl<MCFixup> &Fixup) const { 170 return GPRAlign(MI, OpNo, 1); 171 } 172 173 unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI, 174 unsigned OpNo, 175 SmallVectorImpl<MCFixup> &Fixup) const { 176 return GPRAlign(MI, OpNo, 2); 177 } 178 179 uint64_t SIMCCodeEmitter::i32LiteralEncode(const MCInst &MI, 180 unsigned OpNo, 181 SmallVectorImpl<MCFixup> &Fixup) const { 182 return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32); 183 } 184 185 #define SMRD_OFFSET_MASK 0xff 186 #define SMRD_IMM_SHIFT 8 187 #define SMRD_SBASE_MASK 0x3f 188 #define SMRD_SBASE_SHIFT 9 189 /// SMRDmemriEncode - This function is responsibe for encoding the offset 190 /// and the base ptr for SMRD instructions it should return a bit string in 191 /// this format: 192 /// 193 /// OFFSET = bits{7-0} 194 /// IMM = bits{8} 195 /// SBASE = bits{14-9} 196 /// 197 uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo, 198 SmallVectorImpl<MCFixup> &Fixup) const { 199 uint32_t Encoding; 200 201 const MCOperand &OffsetOp = MI.getOperand(OpNo + 1); 202 203 //XXX: Use this function for SMRD loads with register offsets 204 assert(OffsetOp.isImm()); 205 206 Encoding = 207 (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK) 208 | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit 209 | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT) 210 ; 211 212 return Encoding; 213 } 214 215 //===----------------------------------------------------------------------===// 216 // Post Encoder Callbacks 217 //===----------------------------------------------------------------------===// 218 219 uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{ 220 unsigned encodingType = getEncodingType(MI); 221 unsigned numSrcOps; 222 unsigned vgprBitOffset; 223 224 if (encodingType == SIInstrEncodingType::VOP3) { 225 numSrcOps = 3; 226 vgprBitOffset = 32; 227 } else { 228 numSrcOps = 1; 229 vgprBitOffset = 0; 230 } 231 232 // Add one to skip over the destination reg operand. 233 for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) { 234 const MCOperand &MO = MI.getOperand(opIdx); 235 if (MO.isReg()) { 236 unsigned reg = MI.getOperand(opIdx).getReg(); 237 if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) || 238 AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) { 239 Value |= (VGPR_BIT(opIdx)) << vgprBitOffset; 240 } 241 } else if (MO.isFPImm()) { 242 union { 243 float f; 244 uint32_t i; 245 } Imm; 246 // XXX: Not all instructions can use inline literals 247 // XXX: We should make sure this is a 32-bit constant 248 Imm.f = MO.getFPImm(); 249 Value |= ((uint64_t)Imm.i) << 32; 250 } 251 } 252 return Value; 253 } 254 255 //===----------------------------------------------------------------------===// 256 // Encoding helper functions 257 //===----------------------------------------------------------------------===// 258 259 unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const { 260 return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK; 261 } 262 263 unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const { 264 265 // Instructions with literal constants are expanded to 64-bits, and 266 // the constant is stored in bits [63:32] 267 for (unsigned i = 0; i < MI.getNumOperands(); i++) { 268 if (MI.getOperand(i).isFPImm()) { 269 return 8; 270 } 271 } 272 273 // This instruction always has a literal 274 if (MI.getOpcode() == AMDGPU::S_MOV_IMM_I32) { 275 return 8; 276 } 277 278 unsigned encoding_type = getEncodingType(MI); 279 switch (encoding_type) { 280 case SIInstrEncodingType::EXP: 281 case SIInstrEncodingType::LDS: 282 case SIInstrEncodingType::MUBUF: 283 case SIInstrEncodingType::MTBUF: 284 case SIInstrEncodingType::MIMG: 285 case SIInstrEncodingType::VOP3: 286 return 8; 287 default: 288 return 4; 289 } 290 } 291 292 293 unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const { 294 switch (reg) { 295 case AMDGPU::M0: return 124; 296 case AMDGPU::SREG_LIT_0: return 128; 297 default: return getHWRegNum(reg); 298 } 299 } 300 301 #define SIRegisterInfo SIMCCodeEmitter 302 #include "SIRegisterGetHWRegNum.inc" 303 #undef SIRegisterInfo 304