SIMCCodeEmitter.cpp revision 90bd1d52bbf95947955a66ec67f5f6c7dc87119a
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/AMDILMCTargetDesc.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 35namespace 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 56using namespace llvm; 57 58namespace { 59class 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 66public: 67 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti, 68 MCContext &ctx) 69 : MCII(mcii), STI(sti), Ctx(ctx) { } 70 71 ~SIMCCodeEmitter() { } 72 73 /// getBinaryCodeForInstr - Function generated by tablegen for encoding 74 /// instructions based on the *.td files. 75// virtual uint64_t getBinaryCodeForInstr(const MCInst &MI, 76// SmallVectorImpl<MCFixup> &Fixups) const; 77 78 /// EncodeInstruction - Encode the instruction and write it to the OS. 79 virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 80 SmallVectorImpl<MCFixup> &Fixups) const; 81 82 /// getMachineOpValue - Reutrn the encoding for an MCOperand. 83 virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 84 SmallVectorImpl<MCFixup> &Fixups) const; 85 86public: 87 88 /// GPRAlign - Encode a sequence of registers with the correct alignment. 89 unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const; 90 91 /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used 92 virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo, 93 SmallVectorImpl<MCFixup> &Fixup) const; 94 95 /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used 96 virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo, 97 SmallVectorImpl<MCFixup> &Fixup) const; 98 99 /// i32LiteralEncode - Encode an i32 literal this is used as an operand 100 /// for an instruction in place of a register. 101 virtual uint64_t i32LiteralEncode(const MCInst &MI, unsigned OpNo, 102 SmallVectorImpl<MCFixup> &Fixup) const; 103 104 /// SMRDmemriEncode - Encoding for SMRD indexed loads 105 virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo, 106 SmallVectorImpl<MCFixup> &Fixup) const; 107 108 /// VOPPostEncode - Post-Encoder method for VOP instructions 109 virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const; 110 111private: 112 113 ///getEncodingType = Return this SIInstrEncodingType for this instruction. 114 unsigned getEncodingType(const MCInst &MI) const; 115 116 ///getEncodingBytes - Get then size in bytes of this instructions encoding. 117 unsigned getEncodingBytes(const MCInst &MI) const; 118 119 /// getRegBinaryCode - Returns the hardware encoding for a register 120 unsigned getRegBinaryCode(unsigned reg) const; 121 122 /// getHWRegNum - Generated function that returns the hardware encoding for 123 /// a register 124 unsigned getHWRegNum(unsigned reg) const; 125 126}; 127 128} // End anonymous namespace 129 130MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 131 const MCSubtargetInfo &STI, 132 MCContext &Ctx) { 133 return new SIMCCodeEmitter(MCII, STI, Ctx); 134} 135 136void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 137 SmallVectorImpl<MCFixup> &Fixups) const { 138 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); 139 unsigned bytes = getEncodingBytes(MI); 140 for (unsigned i = 0; i < bytes; i++) { 141 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 142 } 143} 144 145uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 146 const MCOperand &MO, 147 SmallVectorImpl<MCFixup> &Fixups) const { 148 if (MO.isReg()) { 149 return getRegBinaryCode(MO.getReg()); 150 } else if (MO.isImm()) { 151 return MO.getImm(); 152 } else if (MO.isFPImm()) { 153 // XXX: Not all instructions can use inline literals 154 // XXX: We should make sure this is a 32-bit constant 155 return LITERAL_REG; 156 } else{ 157 llvm_unreachable("Encoding of this operand type is not supported yet."); 158 } 159 return 0; 160} 161 162//===----------------------------------------------------------------------===// 163// Custom Operand Encodings 164//===----------------------------------------------------------------------===// 165 166unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo, 167 unsigned shift) const { 168 unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg()); 169 return regCode >> shift; 170 return 0; 171} 172unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI, 173 unsigned OpNo , 174 SmallVectorImpl<MCFixup> &Fixup) const { 175 return GPRAlign(MI, OpNo, 1); 176} 177 178unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI, 179 unsigned OpNo, 180 SmallVectorImpl<MCFixup> &Fixup) const { 181 return GPRAlign(MI, OpNo, 2); 182} 183 184uint64_t SIMCCodeEmitter::i32LiteralEncode(const MCInst &MI, 185 unsigned OpNo, 186 SmallVectorImpl<MCFixup> &Fixup) const { 187 return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32); 188} 189 190#define SMRD_OFFSET_MASK 0xff 191#define SMRD_IMM_SHIFT 8 192#define SMRD_SBASE_MASK 0x3f 193#define SMRD_SBASE_SHIFT 9 194/// SMRDmemriEncode - This function is responsibe for encoding the offset 195/// and the base ptr for SMRD instructions it should return a bit string in 196/// this format: 197/// 198/// OFFSET = bits{7-0} 199/// IMM = bits{8} 200/// SBASE = bits{14-9} 201/// 202uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo, 203 SmallVectorImpl<MCFixup> &Fixup) const { 204 uint32_t Encoding; 205 206 const MCOperand &OffsetOp = MI.getOperand(OpNo + 1); 207 208 //XXX: Use this function for SMRD loads with register offsets 209 assert(OffsetOp.isImm()); 210 211 Encoding = 212 (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK) 213 | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit 214 | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT) 215 ; 216 217 return Encoding; 218} 219 220//===----------------------------------------------------------------------===// 221// Post Encoder Callbacks 222//===----------------------------------------------------------------------===// 223 224uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{ 225 unsigned encodingType = getEncodingType(MI); 226 unsigned numSrcOps; 227 unsigned vgprBitOffset; 228 229 if (encodingType == SIInstrEncodingType::VOP3) { 230 numSrcOps = 3; 231 vgprBitOffset = 32; 232 } else { 233 numSrcOps = 1; 234 vgprBitOffset = 0; 235 } 236 237 // Add one to skip over the destination reg operand. 238 for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) { 239 const MCOperand &MO = MI.getOperand(opIdx); 240 if (MO.isReg()) { 241 unsigned reg = MI.getOperand(opIdx).getReg(); 242 if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) || 243 AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) { 244 Value |= (VGPR_BIT(opIdx)) << vgprBitOffset; 245 } 246 } else if (MO.isFPImm()) { 247 // XXX: Not all instructions can use inline literals 248 // XXX: We should make sure this is a 32-bit constant 249 Value |= ((uint64_t)MO.getFPImm()) << 32; 250 } 251 } 252 return Value; 253} 254 255//===----------------------------------------------------------------------===// 256// Encoding helper functions 257//===----------------------------------------------------------------------===// 258 259unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const { 260 return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK; 261} 262 263unsigned 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 293unsigned 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