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 const MCSubtargetInfo &sti, MCContext &ctx) 52 : MCII(mcii), MRI(mri) { } 53 54 ~SIMCCodeEmitter() { } 55 56 /// \breif Encode the instruction and write it to the OS. 57 virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 58 SmallVectorImpl<MCFixup> &Fixups) const; 59 60 /// \returns the encoding for an MCOperand. 61 virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 62 SmallVectorImpl<MCFixup> &Fixups) const; 63 }; 64 65 } // End anonymous namespace 66 67 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 68 const MCRegisterInfo &MRI, 69 const MCSubtargetInfo &STI, 70 MCContext &Ctx) { 71 return new SIMCCodeEmitter(MCII, MRI, STI, Ctx); 72 } 73 74 bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, 75 unsigned OpNo) const { 76 77 unsigned RegClass = Desc.OpInfo[OpNo].RegClass; 78 return (AMDGPU::SSrc_32RegClassID == RegClass) || 79 (AMDGPU::SSrc_64RegClassID == RegClass) || 80 (AMDGPU::VSrc_32RegClassID == RegClass) || 81 (AMDGPU::VSrc_64RegClassID == RegClass); 82 } 83 84 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { 85 86 IntFloatUnion Imm; 87 if (MO.isImm()) 88 Imm.I = MO.getImm(); 89 else if (MO.isFPImm()) 90 Imm.F = MO.getFPImm(); 91 else 92 return ~0; 93 94 if (Imm.I >= 0 && Imm.I <= 64) 95 return 128 + Imm.I; 96 97 if (Imm.I >= -16 && Imm.I <= -1) 98 return 192 + abs(Imm.I); 99 100 if (Imm.F == 0.5f) 101 return 240; 102 103 if (Imm.F == -0.5f) 104 return 241; 105 106 if (Imm.F == 1.0f) 107 return 242; 108 109 if (Imm.F == -1.0f) 110 return 243; 111 112 if (Imm.F == 2.0f) 113 return 244; 114 115 if (Imm.F == -2.0f) 116 return 245; 117 118 if (Imm.F == 4.0f) 119 return 246; 120 121 if (Imm.F == -4.0f) 122 return 247; 123 124 return 255; 125 } 126 127 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 128 SmallVectorImpl<MCFixup> &Fixups) const { 129 130 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); 131 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 132 unsigned bytes = Desc.getSize(); 133 134 for (unsigned i = 0; i < bytes; i++) { 135 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 136 } 137 138 if (bytes > 4) 139 return; 140 141 // Check for additional literals in SRC0/1/2 (Op 1/2/3) 142 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { 143 144 // Check if this operand should be encoded as [SV]Src 145 if (!isSrcOperand(Desc, i)) 146 continue; 147 148 // Is this operand a literal immediate? 149 const MCOperand &Op = MI.getOperand(i); 150 if (getLitEncoding(Op) != 255) 151 continue; 152 153 // Yes! Encode it 154 IntFloatUnion Imm; 155 if (Op.isImm()) 156 Imm.I = Op.getImm(); 157 else 158 Imm.F = Op.getFPImm(); 159 160 for (unsigned j = 0; j < 4; j++) { 161 OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); 162 } 163 164 // Only one literal value allowed 165 break; 166 } 167 } 168 169 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 170 const MCOperand &MO, 171 SmallVectorImpl<MCFixup> &Fixups) const { 172 if (MO.isReg()) 173 return MRI.getEncodingValue(MO.getReg()); 174 175 if (MO.isExpr()) { 176 const MCExpr *Expr = MO.getExpr(); 177 MCFixupKind Kind = MCFixupKind(FK_PCRel_4); 178 Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); 179 return 0; 180 } 181 182 // Figure out the operand number, needed for isSrcOperand check 183 unsigned OpNo = 0; 184 for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { 185 if (&MO == &MI.getOperand(OpNo)) 186 break; 187 } 188 189 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 190 if (isSrcOperand(Desc, OpNo)) { 191 uint32_t Enc = getLitEncoding(MO); 192 if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) 193 return Enc; 194 195 } else if (MO.isImm()) 196 return MO.getImm(); 197 198 llvm_unreachable("Encoding of this operand type is not supported yet."); 199 return 0; 200 } 201 202