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 const MCSubtargetInfo &STI; 43 MCContext &Ctx; 44 45 /// \brief Can this operand also contain immediate values? 46 bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const; 47 48 /// \brief Encode an fp or int literal 49 uint32_t getLitEncoding(const MCOperand &MO) const; 50 51 public: 52 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, 53 const MCSubtargetInfo &sti, MCContext &ctx) 54 : MCII(mcii), MRI(mri), STI(sti), Ctx(ctx) { } 55 56 ~SIMCCodeEmitter() { } 57 58 /// \breif Encode the instruction and write it to the OS. 59 virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 60 SmallVectorImpl<MCFixup> &Fixups) const; 61 62 /// \returns the encoding for an MCOperand. 63 virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 64 SmallVectorImpl<MCFixup> &Fixups) const; 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, STI, 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) const { 131 132 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); 133 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 134 unsigned bytes = Desc.getSize(); 135 136 for (unsigned i = 0; i < bytes; i++) { 137 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 138 } 139 140 if (bytes > 4) 141 return; 142 143 // Check for additional literals in SRC0/1/2 (Op 1/2/3) 144 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { 145 146 // Check if this operand should be encoded as [SV]Src 147 if (!isSrcOperand(Desc, i)) 148 continue; 149 150 // Is this operand a literal immediate? 151 const MCOperand &Op = MI.getOperand(i); 152 if (getLitEncoding(Op) != 255) 153 continue; 154 155 // Yes! Encode it 156 IntFloatUnion Imm; 157 if (Op.isImm()) 158 Imm.I = Op.getImm(); 159 else 160 Imm.F = Op.getFPImm(); 161 162 for (unsigned j = 0; j < 4; j++) { 163 OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); 164 } 165 166 // Only one literal value allowed 167 break; 168 } 169 } 170 171 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 172 const MCOperand &MO, 173 SmallVectorImpl<MCFixup> &Fixups) const { 174 if (MO.isReg()) 175 return MRI.getEncodingValue(MO.getReg()); 176 177 if (MO.isExpr()) { 178 const MCExpr *Expr = MO.getExpr(); 179 MCFixupKind Kind = MCFixupKind(FK_PCRel_4); 180 Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); 181 return 0; 182 } 183 184 // Figure out the operand number, needed for isSrcOperand check 185 unsigned OpNo = 0; 186 for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { 187 if (&MO == &MI.getOperand(OpNo)) 188 break; 189 } 190 191 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 192 if (isSrcOperand(Desc, OpNo)) { 193 uint32_t Enc = getLitEncoding(MO); 194 if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) 195 return Enc; 196 197 } else if (MO.isImm()) 198 return MO.getImm(); 199 200 llvm_unreachable("Encoding of this operand type is not supported yet."); 201 return 0; 202 } 203 204