LLVM API Documentation
00001 //===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 /// \file 00011 /// \brief The SI code emitter produces machine code that can be executed 00012 /// directly on the GPU device. 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "AMDGPU.h" 00017 #include "SIDefines.h" 00018 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 00019 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h" 00020 #include "MCTargetDesc/AMDGPUFixupKinds.h" 00021 #include "llvm/MC/MCCodeEmitter.h" 00022 #include "llvm/MC/MCContext.h" 00023 #include "llvm/MC/MCFixup.h" 00024 #include "llvm/MC/MCInst.h" 00025 #include "llvm/MC/MCInstrInfo.h" 00026 #include "llvm/MC/MCRegisterInfo.h" 00027 #include "llvm/MC/MCSubtargetInfo.h" 00028 #include "llvm/Support/raw_ostream.h" 00029 00030 using namespace llvm; 00031 00032 namespace { 00033 00034 /// \brief Helper type used in encoding 00035 typedef union { 00036 int32_t I; 00037 float F; 00038 } IntFloatUnion; 00039 00040 class SIMCCodeEmitter : public AMDGPUMCCodeEmitter { 00041 SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 00042 void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 00043 const MCInstrInfo &MCII; 00044 const MCRegisterInfo &MRI; 00045 MCContext &Ctx; 00046 00047 /// \brief Can this operand also contain immediate values? 00048 bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const; 00049 00050 /// \brief Encode an fp or int literal 00051 uint32_t getLitEncoding(const MCOperand &MO) const; 00052 00053 public: 00054 SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, 00055 MCContext &ctx) 00056 : MCII(mcii), MRI(mri), Ctx(ctx) { } 00057 00058 ~SIMCCodeEmitter() { } 00059 00060 /// \brief Encode the instruction and write it to the OS. 00061 void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 00062 SmallVectorImpl<MCFixup> &Fixups, 00063 const MCSubtargetInfo &STI) const override; 00064 00065 /// \returns the encoding for an MCOperand. 00066 uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 00067 SmallVectorImpl<MCFixup> &Fixups, 00068 const MCSubtargetInfo &STI) const override; 00069 00070 /// \brief Use a fixup to encode the simm16 field for SOPP branch 00071 /// instructions. 00072 unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo, 00073 SmallVectorImpl<MCFixup> &Fixups, 00074 const MCSubtargetInfo &STI) const override; 00075 }; 00076 00077 } // End anonymous namespace 00078 00079 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 00080 const MCRegisterInfo &MRI, 00081 const MCSubtargetInfo &STI, 00082 MCContext &Ctx) { 00083 return new SIMCCodeEmitter(MCII, MRI, Ctx); 00084 } 00085 00086 bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, 00087 unsigned OpNo) const { 00088 // FIXME: We need a better way to figure out which operands can be immediate 00089 // values 00090 // 00091 // Some VOP* instructions like ADDC use VReg32 as the register class 00092 // for source 0, because they read VCC and can't take an SGPR as an 00093 // argument due to constant bus restrictions. 00094 if (OpNo == 1 && (Desc.TSFlags & (SIInstrFlags::VOP1 | SIInstrFlags::VOP2 | 00095 SIInstrFlags::VOPC))) 00096 return true; 00097 00098 unsigned RegClass = Desc.OpInfo[OpNo].RegClass; 00099 return (AMDGPU::SSrc_32RegClassID == RegClass) || 00100 (AMDGPU::SSrc_64RegClassID == RegClass) || 00101 (AMDGPU::VSrc_32RegClassID == RegClass) || 00102 (AMDGPU::VSrc_64RegClassID == RegClass); 00103 } 00104 00105 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { 00106 00107 IntFloatUnion Imm; 00108 if (MO.isImm()) 00109 Imm.I = MO.getImm(); 00110 else if (MO.isFPImm()) 00111 Imm.F = MO.getFPImm(); 00112 else if (MO.isExpr()) 00113 return 255; 00114 else 00115 return ~0; 00116 00117 if (Imm.I >= 0 && Imm.I <= 64) 00118 return 128 + Imm.I; 00119 00120 if (Imm.I >= -16 && Imm.I <= -1) 00121 return 192 + abs(Imm.I); 00122 00123 if (Imm.F == 0.5f) 00124 return 240; 00125 00126 if (Imm.F == -0.5f) 00127 return 241; 00128 00129 if (Imm.F == 1.0f) 00130 return 242; 00131 00132 if (Imm.F == -1.0f) 00133 return 243; 00134 00135 if (Imm.F == 2.0f) 00136 return 244; 00137 00138 if (Imm.F == -2.0f) 00139 return 245; 00140 00141 if (Imm.F == 4.0f) 00142 return 246; 00143 00144 if (Imm.F == -4.0f) 00145 return 247; 00146 00147 return 255; 00148 } 00149 00150 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 00151 SmallVectorImpl<MCFixup> &Fixups, 00152 const MCSubtargetInfo &STI) const { 00153 00154 uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI); 00155 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 00156 unsigned bytes = Desc.getSize(); 00157 00158 for (unsigned i = 0; i < bytes; i++) { 00159 OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 00160 } 00161 00162 if (bytes > 4) 00163 return; 00164 00165 // Check for additional literals in SRC0/1/2 (Op 1/2/3) 00166 for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { 00167 00168 // Check if this operand should be encoded as [SV]Src 00169 if (!isSrcOperand(Desc, i)) 00170 continue; 00171 00172 // Is this operand a literal immediate? 00173 const MCOperand &Op = MI.getOperand(i); 00174 if (getLitEncoding(Op) != 255) 00175 continue; 00176 00177 // Yes! Encode it 00178 IntFloatUnion Imm; 00179 if (Op.isImm()) 00180 Imm.I = Op.getImm(); 00181 else if (Op.isFPImm()) 00182 Imm.F = Op.getFPImm(); 00183 else { 00184 assert(Op.isExpr()); 00185 // This will be replaced with a fixup value. 00186 Imm.I = 0; 00187 } 00188 00189 for (unsigned j = 0; j < 4; j++) { 00190 OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); 00191 } 00192 00193 // Only one literal value allowed 00194 break; 00195 } 00196 } 00197 00198 unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo, 00199 SmallVectorImpl<MCFixup> &Fixups, 00200 const MCSubtargetInfo &STI) const { 00201 const MCOperand &MO = MI.getOperand(OpNo); 00202 00203 if (MO.isExpr()) { 00204 const MCExpr *Expr = MO.getExpr(); 00205 MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br; 00206 Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); 00207 return 0; 00208 } 00209 00210 return getMachineOpValue(MI, MO, Fixups, STI); 00211 } 00212 00213 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 00214 const MCOperand &MO, 00215 SmallVectorImpl<MCFixup> &Fixups, 00216 const MCSubtargetInfo &STI) const { 00217 if (MO.isReg()) 00218 return MRI.getEncodingValue(MO.getReg()); 00219 00220 if (MO.isExpr()) { 00221 const MCSymbolRefExpr *Expr = cast<MCSymbolRefExpr>(MO.getExpr()); 00222 MCFixupKind Kind; 00223 const MCSymbol *Sym = 00224 Ctx.GetOrCreateSymbol(StringRef(END_OF_TEXT_LABEL_NAME)); 00225 00226 if (&Expr->getSymbol() == Sym) { 00227 // Add the offset to the beginning of the constant values. 00228 Kind = (MCFixupKind)AMDGPU::fixup_si_end_of_text; 00229 } else { 00230 // This is used for constant data stored in .rodata. 00231 Kind = (MCFixupKind)AMDGPU::fixup_si_rodata; 00232 } 00233 Fixups.push_back(MCFixup::Create(4, Expr, Kind, MI.getLoc())); 00234 } 00235 00236 // Figure out the operand number, needed for isSrcOperand check 00237 unsigned OpNo = 0; 00238 for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { 00239 if (&MO == &MI.getOperand(OpNo)) 00240 break; 00241 } 00242 00243 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 00244 if (isSrcOperand(Desc, OpNo)) { 00245 uint32_t Enc = getLitEncoding(MO); 00246 if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) 00247 return Enc; 00248 00249 } else if (MO.isImm()) 00250 return MO.getImm(); 00251 00252 llvm_unreachable("Encoding of this operand type is not supported yet."); 00253 return 0; 00254 } 00255