LLVM API Documentation
00001 //===- R600MCCodeEmitter.cpp - Code Emitter for R600->Cayman GPU families -===// 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 /// 00012 /// \brief The R600 code emitter produces machine code that can be executed 00013 /// directly on the GPU device. 00014 // 00015 //===----------------------------------------------------------------------===// 00016 00017 #include "R600Defines.h" 00018 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h" 00019 #include "MCTargetDesc/AMDGPUMCTargetDesc.h" 00020 #include "llvm/MC/MCCodeEmitter.h" 00021 #include "llvm/MC/MCContext.h" 00022 #include "llvm/MC/MCInst.h" 00023 #include "llvm/MC/MCInstrInfo.h" 00024 #include "llvm/MC/MCRegisterInfo.h" 00025 #include "llvm/MC/MCSubtargetInfo.h" 00026 #include "llvm/Support/raw_ostream.h" 00027 00028 using namespace llvm; 00029 00030 namespace { 00031 00032 class R600MCCodeEmitter : public AMDGPUMCCodeEmitter { 00033 R600MCCodeEmitter(const R600MCCodeEmitter &) LLVM_DELETED_FUNCTION; 00034 void operator=(const R600MCCodeEmitter &) LLVM_DELETED_FUNCTION; 00035 const MCInstrInfo &MCII; 00036 const MCRegisterInfo &MRI; 00037 00038 public: 00039 00040 R600MCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri) 00041 : MCII(mcii), MRI(mri) { } 00042 00043 /// \brief Encode the instruction and write it to the OS. 00044 void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 00045 SmallVectorImpl<MCFixup> &Fixups, 00046 const MCSubtargetInfo &STI) const override; 00047 00048 /// \returns the encoding for an MCOperand. 00049 uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 00050 SmallVectorImpl<MCFixup> &Fixups, 00051 const MCSubtargetInfo &STI) const override; 00052 private: 00053 00054 void EmitByte(unsigned int byte, raw_ostream &OS) const; 00055 00056 void Emit(uint32_t value, raw_ostream &OS) const; 00057 void Emit(uint64_t value, raw_ostream &OS) const; 00058 00059 unsigned getHWRegChan(unsigned reg) const; 00060 unsigned getHWReg(unsigned regNo) const; 00061 00062 }; 00063 00064 } // End anonymous namespace 00065 00066 enum RegElement { 00067 ELEMENT_X = 0, 00068 ELEMENT_Y, 00069 ELEMENT_Z, 00070 ELEMENT_W 00071 }; 00072 00073 enum FCInstr { 00074 FC_IF_PREDICATE = 0, 00075 FC_ELSE, 00076 FC_ENDIF, 00077 FC_BGNLOOP, 00078 FC_ENDLOOP, 00079 FC_BREAK_PREDICATE, 00080 FC_CONTINUE 00081 }; 00082 00083 MCCodeEmitter *llvm::createR600MCCodeEmitter(const MCInstrInfo &MCII, 00084 const MCRegisterInfo &MRI, 00085 const MCSubtargetInfo &STI) { 00086 return new R600MCCodeEmitter(MCII, MRI); 00087 } 00088 00089 void R600MCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 00090 SmallVectorImpl<MCFixup> &Fixups, 00091 const MCSubtargetInfo &STI) const { 00092 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 00093 if (MI.getOpcode() == AMDGPU::RETURN || 00094 MI.getOpcode() == AMDGPU::FETCH_CLAUSE || 00095 MI.getOpcode() == AMDGPU::ALU_CLAUSE || 00096 MI.getOpcode() == AMDGPU::BUNDLE || 00097 MI.getOpcode() == AMDGPU::KILL) { 00098 return; 00099 } else if (IS_VTX(Desc)) { 00100 uint64_t InstWord01 = getBinaryCodeForInstr(MI, Fixups, STI); 00101 uint32_t InstWord2 = MI.getOperand(2).getImm(); // Offset 00102 if (!(STI.getFeatureBits() & AMDGPU::FeatureCaymanISA)) { 00103 InstWord2 |= 1 << 19; // Mega-Fetch bit 00104 } 00105 00106 Emit(InstWord01, OS); 00107 Emit(InstWord2, OS); 00108 Emit((uint32_t) 0, OS); 00109 } else if (IS_TEX(Desc)) { 00110 int64_t Sampler = MI.getOperand(14).getImm(); 00111 00112 int64_t SrcSelect[4] = { 00113 MI.getOperand(2).getImm(), 00114 MI.getOperand(3).getImm(), 00115 MI.getOperand(4).getImm(), 00116 MI.getOperand(5).getImm() 00117 }; 00118 int64_t Offsets[3] = { 00119 MI.getOperand(6).getImm() & 0x1F, 00120 MI.getOperand(7).getImm() & 0x1F, 00121 MI.getOperand(8).getImm() & 0x1F 00122 }; 00123 00124 uint64_t Word01 = getBinaryCodeForInstr(MI, Fixups, STI); 00125 uint32_t Word2 = Sampler << 15 | SrcSelect[ELEMENT_X] << 20 | 00126 SrcSelect[ELEMENT_Y] << 23 | SrcSelect[ELEMENT_Z] << 26 | 00127 SrcSelect[ELEMENT_W] << 29 | Offsets[0] << 0 | Offsets[1] << 5 | 00128 Offsets[2] << 10; 00129 00130 Emit(Word01, OS); 00131 Emit(Word2, OS); 00132 Emit((uint32_t) 0, OS); 00133 } else { 00134 uint64_t Inst = getBinaryCodeForInstr(MI, Fixups, STI); 00135 if ((STI.getFeatureBits() & AMDGPU::FeatureR600ALUInst) && 00136 ((Desc.TSFlags & R600_InstFlag::OP1) || 00137 Desc.TSFlags & R600_InstFlag::OP2)) { 00138 uint64_t ISAOpCode = Inst & (0x3FFULL << 39); 00139 Inst &= ~(0x3FFULL << 39); 00140 Inst |= ISAOpCode << 1; 00141 } 00142 Emit(Inst, OS); 00143 } 00144 } 00145 00146 void R600MCCodeEmitter::EmitByte(unsigned int Byte, raw_ostream &OS) const { 00147 OS.write((uint8_t) Byte & 0xff); 00148 } 00149 00150 void R600MCCodeEmitter::Emit(uint32_t Value, raw_ostream &OS) const { 00151 for (unsigned i = 0; i < 4; i++) { 00152 OS.write((uint8_t) ((Value >> (8 * i)) & 0xff)); 00153 } 00154 } 00155 00156 void R600MCCodeEmitter::Emit(uint64_t Value, raw_ostream &OS) const { 00157 for (unsigned i = 0; i < 8; i++) { 00158 EmitByte((Value >> (8 * i)) & 0xff, OS); 00159 } 00160 } 00161 00162 unsigned R600MCCodeEmitter::getHWRegChan(unsigned reg) const { 00163 return MRI.getEncodingValue(reg) >> HW_CHAN_SHIFT; 00164 } 00165 00166 unsigned R600MCCodeEmitter::getHWReg(unsigned RegNo) const { 00167 return MRI.getEncodingValue(RegNo) & HW_REG_MASK; 00168 } 00169 00170 uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI, 00171 const MCOperand &MO, 00172 SmallVectorImpl<MCFixup> &Fixup, 00173 const MCSubtargetInfo &STI) const { 00174 if (MO.isReg()) { 00175 if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags)) 00176 return MRI.getEncodingValue(MO.getReg()); 00177 return getHWReg(MO.getReg()); 00178 } 00179 00180 assert(MO.isImm()); 00181 return MO.getImm(); 00182 } 00183 00184 #include "AMDGPUGenMCCodeEmitter.inc"