1249259Sdim//===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10249259Sdim/// \file 11249259Sdim/// \brief The SI code emitter produces machine code that can be executed 12249259Sdim/// directly on the GPU device. 13249259Sdim// 14249259Sdim//===----------------------------------------------------------------------===// 15249259Sdim 16249259Sdim#include "MCTargetDesc/AMDGPUMCTargetDesc.h" 17249259Sdim#include "MCTargetDesc/AMDGPUMCCodeEmitter.h" 18249259Sdim#include "llvm/MC/MCCodeEmitter.h" 19249259Sdim#include "llvm/MC/MCContext.h" 20249259Sdim#include "llvm/MC/MCFixup.h" 21249259Sdim#include "llvm/MC/MCInst.h" 22249259Sdim#include "llvm/MC/MCInstrInfo.h" 23249259Sdim#include "llvm/MC/MCRegisterInfo.h" 24249259Sdim#include "llvm/MC/MCSubtargetInfo.h" 25249259Sdim#include "llvm/Support/raw_ostream.h" 26249259Sdim 27249259Sdimusing namespace llvm; 28249259Sdim 29249259Sdimnamespace { 30249259Sdim 31249259Sdim/// \brief Helper type used in encoding 32249259Sdimtypedef union { 33249259Sdim int32_t I; 34249259Sdim float F; 35249259Sdim} IntFloatUnion; 36249259Sdim 37249259Sdimclass SIMCCodeEmitter : public AMDGPUMCCodeEmitter { 38249259Sdim SIMCCodeEmitter(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 39249259Sdim void operator=(const SIMCCodeEmitter &) LLVM_DELETED_FUNCTION; 40249259Sdim const MCInstrInfo &MCII; 41249259Sdim const MCRegisterInfo &MRI; 42249259Sdim 43249259Sdim /// \brief Can this operand also contain immediate values? 44249259Sdim bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const; 45249259Sdim 46249259Sdim /// \brief Encode an fp or int literal 47249259Sdim uint32_t getLitEncoding(const MCOperand &MO) const; 48249259Sdim 49249259Sdimpublic: 50249259Sdim SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri, 51249259Sdim const MCSubtargetInfo &sti, MCContext &ctx) 52249259Sdim : MCII(mcii), MRI(mri) { } 53249259Sdim 54249259Sdim ~SIMCCodeEmitter() { } 55249259Sdim 56249259Sdim /// \breif Encode the instruction and write it to the OS. 57249259Sdim virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS, 58249259Sdim SmallVectorImpl<MCFixup> &Fixups) const; 59249259Sdim 60249259Sdim /// \returns the encoding for an MCOperand. 61249259Sdim virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, 62249259Sdim SmallVectorImpl<MCFixup> &Fixups) const; 63249259Sdim}; 64249259Sdim 65249259Sdim} // End anonymous namespace 66249259Sdim 67249259SdimMCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII, 68249259Sdim const MCRegisterInfo &MRI, 69249259Sdim const MCSubtargetInfo &STI, 70249259Sdim MCContext &Ctx) { 71249259Sdim return new SIMCCodeEmitter(MCII, MRI, STI, Ctx); 72249259Sdim} 73249259Sdim 74249259Sdimbool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc, 75249259Sdim unsigned OpNo) const { 76249259Sdim 77249259Sdim unsigned RegClass = Desc.OpInfo[OpNo].RegClass; 78249259Sdim return (AMDGPU::SSrc_32RegClassID == RegClass) || 79249259Sdim (AMDGPU::SSrc_64RegClassID == RegClass) || 80249259Sdim (AMDGPU::VSrc_32RegClassID == RegClass) || 81249259Sdim (AMDGPU::VSrc_64RegClassID == RegClass); 82249259Sdim} 83249259Sdim 84249259Sdimuint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO) const { 85249259Sdim 86249259Sdim IntFloatUnion Imm; 87249259Sdim if (MO.isImm()) 88249259Sdim Imm.I = MO.getImm(); 89249259Sdim else if (MO.isFPImm()) 90249259Sdim Imm.F = MO.getFPImm(); 91249259Sdim else 92249259Sdim return ~0; 93249259Sdim 94249259Sdim if (Imm.I >= 0 && Imm.I <= 64) 95249259Sdim return 128 + Imm.I; 96249259Sdim 97249259Sdim if (Imm.I >= -16 && Imm.I <= -1) 98249259Sdim return 192 + abs(Imm.I); 99249259Sdim 100249259Sdim if (Imm.F == 0.5f) 101249259Sdim return 240; 102249259Sdim 103249259Sdim if (Imm.F == -0.5f) 104249259Sdim return 241; 105249259Sdim 106249259Sdim if (Imm.F == 1.0f) 107249259Sdim return 242; 108249259Sdim 109249259Sdim if (Imm.F == -1.0f) 110249259Sdim return 243; 111249259Sdim 112249259Sdim if (Imm.F == 2.0f) 113249259Sdim return 244; 114249259Sdim 115249259Sdim if (Imm.F == -2.0f) 116249259Sdim return 245; 117249259Sdim 118249259Sdim if (Imm.F == 4.0f) 119249259Sdim return 246; 120249259Sdim 121249259Sdim if (Imm.F == -4.0f) 122249259Sdim return 247; 123249259Sdim 124249259Sdim return 255; 125249259Sdim} 126249259Sdim 127249259Sdimvoid SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS, 128249259Sdim SmallVectorImpl<MCFixup> &Fixups) const { 129249259Sdim 130249259Sdim uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups); 131249259Sdim const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 132249259Sdim unsigned bytes = Desc.getSize(); 133249259Sdim 134249259Sdim for (unsigned i = 0; i < bytes; i++) { 135249259Sdim OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff)); 136249259Sdim } 137249259Sdim 138249259Sdim if (bytes > 4) 139249259Sdim return; 140249259Sdim 141249259Sdim // Check for additional literals in SRC0/1/2 (Op 1/2/3) 142249259Sdim for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) { 143249259Sdim 144249259Sdim // Check if this operand should be encoded as [SV]Src 145249259Sdim if (!isSrcOperand(Desc, i)) 146249259Sdim continue; 147249259Sdim 148249259Sdim // Is this operand a literal immediate? 149249259Sdim const MCOperand &Op = MI.getOperand(i); 150249259Sdim if (getLitEncoding(Op) != 255) 151249259Sdim continue; 152249259Sdim 153249259Sdim // Yes! Encode it 154249259Sdim IntFloatUnion Imm; 155249259Sdim if (Op.isImm()) 156249259Sdim Imm.I = Op.getImm(); 157249259Sdim else 158249259Sdim Imm.F = Op.getFPImm(); 159249259Sdim 160249259Sdim for (unsigned j = 0; j < 4; j++) { 161249259Sdim OS.write((uint8_t) ((Imm.I >> (8 * j)) & 0xff)); 162249259Sdim } 163249259Sdim 164249259Sdim // Only one literal value allowed 165249259Sdim break; 166249259Sdim } 167249259Sdim} 168249259Sdim 169249259Sdimuint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI, 170249259Sdim const MCOperand &MO, 171249259Sdim SmallVectorImpl<MCFixup> &Fixups) const { 172249259Sdim if (MO.isReg()) 173249259Sdim return MRI.getEncodingValue(MO.getReg()); 174249259Sdim 175249259Sdim if (MO.isExpr()) { 176249259Sdim const MCExpr *Expr = MO.getExpr(); 177249259Sdim MCFixupKind Kind = MCFixupKind(FK_PCRel_4); 178249259Sdim Fixups.push_back(MCFixup::Create(0, Expr, Kind, MI.getLoc())); 179249259Sdim return 0; 180249259Sdim } 181249259Sdim 182249259Sdim // Figure out the operand number, needed for isSrcOperand check 183249259Sdim unsigned OpNo = 0; 184249259Sdim for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) { 185249259Sdim if (&MO == &MI.getOperand(OpNo)) 186249259Sdim break; 187249259Sdim } 188249259Sdim 189249259Sdim const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 190249259Sdim if (isSrcOperand(Desc, OpNo)) { 191249259Sdim uint32_t Enc = getLitEncoding(MO); 192249259Sdim if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4)) 193249259Sdim return Enc; 194249259Sdim 195249259Sdim } else if (MO.isImm()) 196249259Sdim return MO.getImm(); 197249259Sdim 198249259Sdim llvm_unreachable("Encoding of this operand type is not supported yet."); 199249259Sdim return 0; 200249259Sdim} 201249259Sdim 202