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