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 /// \file 11 /// \brief The SI code emitter produces machine code that can be executed 12 /// directly on the GPU device. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 17 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h" 18 #include "llvm/MC/MCCodeEmitter.h" 19 #include "llvm/MC/MCContext.h" 20 #include "llvm/MC/MCFixup.h" 21 #include "llvm/MC/MCInst.h" 22 #include "llvm/MC/MCInstrInfo.h" 23 #include "llvm/MC/MCRegisterInfo.h" 24 #include "llvm/MC/MCSubtargetInfo.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 using namespace llvm; 28 29 namespace { 30 31 /// \brief Helper type used in encoding 32 typedef union { 33 int32_t I; 34 float F; 35 } IntFloatUnion; 36 37 class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { 38 SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 39 void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 40 const MCInstrInfo &MCII; 41 const MCRegisterInfo &MRI; 42 43 /// \brief Can this operand also contain immediate values? 44 bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const; 45 46 /// \brief Encode an fp or int literal 47 uint32_t getLitEncoding(const MCOperand &MO) const; 48 49 public: 50 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, 51 MCContext &ctx) 52 : MCII(mcii), MRI(mri) { } 53 54 ~SIMCCodeEmitter() { } 55 56 /// \brief Encode the instruction and write it to the OS. 57 void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 58 SmallVectorImpl<MCFixup> &Fixups, 59 const MCSubtargetInfo &STI) const override; 60 61 /// \returns the encoding for an MCOperand. 62 uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 63 SmallVectorImpl<MCFixup> &Fixups, 64 const MCSubtargetInfo &STI) const override; 65 }; 66 67 } // End anonymous namespace 68 69 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 70 const MCRegisterInfo &MRI, 71 const MCSubtargetInfo &STI, 72 MCContext &Ctx) { 73 return new SIMCCodeEmitter(MCII, MRI, Ctx); 74 } 75 76 bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, 77 unsigned OpNo) const { 78 79 unsigned RegClass = Desc.OpInfo[OpNo].RegClass; 80 return (AMDGPU::SSrc_32RegClassID == RegClass) || 81 (AMDGPU::SSrc_64RegClassID == RegClass) || 82 (AMDGPU::VSrc_32RegClassID == RegClass) || 83 (AMDGPU::VSrc_64RegClassID == RegClass); 84 } 85 86 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { 87 88 IntFloatUnion Imm; 89 if (MO.isImm()) 90 Imm.I = MO.getImm(); 91 else if (MO.isFPImm()) 92 Imm.F = MO.getFPImm(); 93 else 94 return ~0; 95 96 if (Imm.I >= 0 && Imm.I <= 64) 97 return 128 + Imm.I; 98 99 if (Imm.I >= -16 && Imm.I <= -1) 100 return 192 + abs(Imm.I); 101 102 if (Imm.F == 0.5f) 103 return 240; 104 105 if (Imm.F == -0.5f) 106 return 241; 107 108 if (Imm.F == 1.0f) 109 return 242; 110 111 if (Imm.F == -1.0f) 112 return 243; 113 114 if (Imm.F == 2.0f) 115 return 244; 116 117 if (Imm.F == -2.0f) 118 return 245; 119 120 if (Imm.F == 4.0f) 121 return 246; 122 123 if (Imm.F == -4.0f) 124 return 247; 125 126 return 255; 127 } 128 129 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 130 SmallVectorImpl<MCFixup> &Fixups, 131 const MCSubtargetInfo &STI) const { 132 133 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI); 134 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 135 unsigned bytes = Desc.getSize(); 136 137 for (unsigned i = 0; i < bytes; i++) { 138 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 139 } 140 141 if (bytes > 4) 142 return; 143 144 // Check for additional literals in SRC0/1/2 (Op 1/2/3) 145 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { 146 147 // Check if this operand should be encoded as [SV]Src 148 if (!isSrcOperand(Desc, i)) 149 continue; 150 151 // Is this operand a literal immediate? 152 const MCOperand &Op = MI.getOperand(i); 153 if (getLitEncoding(Op) != 255) 154 continue; 155 156 // Yes! Encode it 157 IntFloatUnion Imm; 158 if (Op.isImm()) 159 Imm.I = Op.getImm(); 160 else 161 Imm.F = Op.getFPImm(); 162 163 for (unsigned j = 0; j < 4; j++) { 164 OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); 165 } 166 167 // Only one literal value allowed 168 break; 169 } 170 } 171 172 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 173 const MCOperand &MO, 174 SmallVectorImpl<MCFixup> &Fixups, 175 const MCSubtargetInfo &STI) const { 176 if (MO.isReg()) 177 return MRI.getEncodingValue(MO.getReg()); 178 179 if (MO.isExpr()) { 180 const MCExpr *Expr = MO.getExpr(); 181 MCFixupKind Kind = MCFixupKind(FK_PCRel_4); 182 Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); 183 return 0; 184 } 185 186 // Figure out the operand number, needed for isSrcOperand check 187 unsigned OpNo = 0; 188 for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { 189 if (&MO == &MI.getOperand(OpNo)) 190 break; 191 } 192 193 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 194 if (isSrcOperand(Desc, OpNo)) { 195 uint32_t Enc = getLitEncoding(MO); 196 if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) 197 return Enc; 198 199 } else if (MO.isImm()) 200 return MO.getImm(); 201 202 llvm_unreachable("Encoding of this operand type is not supported yet."); 203 return 0; 204 } 205 206