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 // The SI code emitter produces machine code that can be executed directly on
     11 // the GPU device.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
     16 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
     17 #include "llvm/MC/MCCodeEmitter.h"
     18 #include "llvm/MC/MCContext.h"
     19 #include "llvm/MC/MCInst.h"
     20 #include "llvm/MC/MCInstrInfo.h"
     21 #include "llvm/MC/MCRegisterInfo.h"
     22 #include "llvm/MC/MCSubtargetInfo.h"
     23 #include "llvm/Support/raw_ostream.h"
     24 
     25 #define LITERAL_REG 255
     26 #define VGPR_BIT(src_idx) (1ULL << (9 * src_idx - 1))
     27 #define SI_INSTR_FLAGS_ENCODING_MASK 0xf
     28 
     29 
     30 // These must be kept in sync with SIInstructions.td and also the
     31 // InstrEncodingInfo array in SIInstrInfo.cpp.
     32 //
     33 // NOTE: This enum is only used to identify the encoding type within LLVM,
     34 // the actual encoding type that is part of the instruction format is different
     35 namespace SIInstrEncodingType {
     36   enum Encoding {
     37     EXP = 0,
     38     LDS = 1,
     39     MIMG = 2,
     40     MTBUF = 3,
     41     MUBUF = 4,
     42     SMRD = 5,
     43     SOP1 = 6,
     44     SOP2 = 7,
     45     SOPC = 8,
     46     SOPK = 9,
     47     SOPP = 10,
     48     VINTRP = 11,
     49     VOP1 = 12,
     50     VOP2 = 13,
     51     VOP3 = 14,
     52     VOPC = 15
     53   };
     54 }
     55 
     56 using namespace llvm;
     57 
     58 namespace {
     59 class SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
     60   SIMCCodeEmitter(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
     61   void operator=(const SIMCCodeEmitter &); // DO NOT IMPLEMENT
     62   const MCInstrInfo &MCII;
     63   const MCSubtargetInfo &STI;
     64   MCContext &Ctx;
     65 
     66 public:
     67   SIMCCodeEmitter(const MCInstrInfo &mcii, const MCSubtargetInfo &sti,
     68                   MCContext &ctx)
     69     : MCII(mcii), STI(sti), Ctx(ctx) { }
     70 
     71   ~SIMCCodeEmitter() { }
     72 
     73   /// EncodeInstruction - Encode the instruction and write it to the OS.
     74   virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
     75                          SmallVectorImpl<MCFixup> &Fixups) const;
     76 
     77   /// getMachineOpValue - Reutrn the encoding for an MCOperand.
     78   virtual uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
     79                                      SmallVectorImpl<MCFixup> &Fixups) const;
     80 
     81 public:
     82 
     83   /// GPRAlign - Encode a sequence of registers with the correct alignment.
     84   unsigned GPRAlign(const MCInst &MI, unsigned OpNo, unsigned shift) const;
     85 
     86   /// GPR2AlignEncode - Encoding for when 2 consecutive registers are used
     87   virtual unsigned GPR2AlignEncode(const MCInst &MI, unsigned OpNo,
     88                                    SmallVectorImpl<MCFixup> &Fixup) const;
     89 
     90   /// GPR4AlignEncode - Encoding for when 4 consectuive registers are used
     91   virtual unsigned GPR4AlignEncode(const MCInst &MI, unsigned OpNo,
     92                                    SmallVectorImpl<MCFixup> &Fixup) const;
     93 
     94   /// i32LiteralEncode - Encode an i32 literal this is used as an operand
     95   /// for an instruction in place of a register.
     96   virtual uint64_t i32LiteralEncode(const MCInst &MI, unsigned OpNo,
     97                                    SmallVectorImpl<MCFixup> &Fixup) const;
     98 
     99   /// SMRDmemriEncode - Encoding for SMRD indexed loads
    100   virtual uint32_t SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
    101                                    SmallVectorImpl<MCFixup> &Fixup) const;
    102 
    103   /// VOPPostEncode - Post-Encoder method for VOP instructions
    104   virtual uint64_t VOPPostEncode(const MCInst &MI, uint64_t Value) const;
    105 
    106 private:
    107 
    108   ///getEncodingType =  Return this SIInstrEncodingType for this instruction.
    109   unsigned getEncodingType(const MCInst &MI) const;
    110 
    111   ///getEncodingBytes - Get then size in bytes of this instructions encoding.
    112   unsigned getEncodingBytes(const MCInst &MI) const;
    113 
    114   /// getRegBinaryCode - Returns the hardware encoding for a register
    115   unsigned getRegBinaryCode(unsigned reg) const;
    116 
    117   /// getHWRegNum - Generated function that returns the hardware encoding for
    118   /// a register
    119   unsigned getHWRegNum(unsigned reg) const;
    120 
    121 };
    122 
    123 } // End anonymous namespace
    124 
    125 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
    126                                            const MCSubtargetInfo &STI,
    127                                            MCContext &Ctx) {
    128   return new SIMCCodeEmitter(MCII, STI, Ctx);
    129 }
    130 
    131 void SIMCCodeEmitter::EncodeInstruction(const MCInst &MI, raw_ostream &OS,
    132                                        SmallVectorImpl<MCFixup> &Fixups) const {
    133   uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups);
    134   unsigned bytes = getEncodingBytes(MI);
    135   for (unsigned i = 0; i < bytes; i++) {
    136     OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
    137   }
    138 }
    139 
    140 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
    141                                             const MCOperand &MO,
    142                                        SmallVectorImpl<MCFixup> &Fixups) const {
    143   if (MO.isReg()) {
    144     return getRegBinaryCode(MO.getReg());
    145   } else if (MO.isImm()) {
    146     return MO.getImm();
    147   } else if (MO.isFPImm()) {
    148     // XXX: Not all instructions can use inline literals
    149     // XXX: We should make sure this is a 32-bit constant
    150     return LITERAL_REG;
    151   } else{
    152     llvm_unreachable("Encoding of this operand type is not supported yet.");
    153   }
    154   return 0;
    155 }
    156 
    157 //===----------------------------------------------------------------------===//
    158 // Custom Operand Encodings
    159 //===----------------------------------------------------------------------===//
    160 
    161 unsigned SIMCCodeEmitter::GPRAlign(const MCInst &MI, unsigned OpNo,
    162                                    unsigned shift) const {
    163   unsigned regCode = getRegBinaryCode(MI.getOperand(OpNo).getReg());
    164   return regCode >> shift;
    165   return 0;
    166 }
    167 unsigned SIMCCodeEmitter::GPR2AlignEncode(const MCInst &MI,
    168                                           unsigned OpNo ,
    169                                         SmallVectorImpl<MCFixup> &Fixup) const {
    170   return GPRAlign(MI, OpNo, 1);
    171 }
    172 
    173 unsigned SIMCCodeEmitter::GPR4AlignEncode(const MCInst &MI,
    174                                           unsigned OpNo,
    175                                         SmallVectorImpl<MCFixup> &Fixup) const {
    176   return GPRAlign(MI, OpNo, 2);
    177 }
    178 
    179 uint64_t SIMCCodeEmitter::i32LiteralEncode(const MCInst &MI,
    180                                            unsigned OpNo,
    181                                         SmallVectorImpl<MCFixup> &Fixup) const {
    182   return LITERAL_REG | (MI.getOperand(OpNo).getImm() << 32);
    183 }
    184 
    185 #define SMRD_OFFSET_MASK 0xff
    186 #define SMRD_IMM_SHIFT 8
    187 #define SMRD_SBASE_MASK 0x3f
    188 #define SMRD_SBASE_SHIFT 9
    189 /// SMRDmemriEncode - This function is responsibe for encoding the offset
    190 /// and the base ptr for SMRD instructions it should return a bit string in
    191 /// this format:
    192 ///
    193 /// OFFSET = bits{7-0}
    194 /// IMM    = bits{8}
    195 /// SBASE  = bits{14-9}
    196 ///
    197 uint32_t SIMCCodeEmitter::SMRDmemriEncode(const MCInst &MI, unsigned OpNo,
    198                                         SmallVectorImpl<MCFixup> &Fixup) const {
    199   uint32_t Encoding;
    200 
    201   const MCOperand &OffsetOp = MI.getOperand(OpNo + 1);
    202 
    203   //XXX: Use this function for SMRD loads with register offsets
    204   assert(OffsetOp.isImm());
    205 
    206   Encoding =
    207       (getMachineOpValue(MI, OffsetOp, Fixup) & SMRD_OFFSET_MASK)
    208     | (1 << SMRD_IMM_SHIFT) //XXX If the Offset is a register we shouldn't set this bit
    209     | ((GPR2AlignEncode(MI, OpNo, Fixup) & SMRD_SBASE_MASK) << SMRD_SBASE_SHIFT)
    210     ;
    211 
    212   return Encoding;
    213 }
    214 
    215 //===----------------------------------------------------------------------===//
    216 // Post Encoder Callbacks
    217 //===----------------------------------------------------------------------===//
    218 
    219 uint64_t SIMCCodeEmitter::VOPPostEncode(const MCInst &MI, uint64_t Value) const{
    220   unsigned encodingType = getEncodingType(MI);
    221   unsigned numSrcOps;
    222   unsigned vgprBitOffset;
    223 
    224   if (encodingType == SIInstrEncodingType::VOP3) {
    225     numSrcOps = 3;
    226     vgprBitOffset = 32;
    227   } else {
    228     numSrcOps = 1;
    229     vgprBitOffset = 0;
    230   }
    231 
    232   // Add one to skip over the destination reg operand.
    233   for (unsigned opIdx = 1; opIdx < numSrcOps + 1; opIdx++) {
    234     const MCOperand &MO = MI.getOperand(opIdx);
    235     if (MO.isReg()) {
    236       unsigned reg = MI.getOperand(opIdx).getReg();
    237       if (AMDGPUMCRegisterClasses[AMDGPU::VReg_32RegClassID].contains(reg) ||
    238           AMDGPUMCRegisterClasses[AMDGPU::VReg_64RegClassID].contains(reg)) {
    239         Value |= (VGPR_BIT(opIdx)) << vgprBitOffset;
    240       }
    241     } else if (MO.isFPImm()) {
    242       union {
    243         float f;
    244         uint32_t i;
    245       } Imm;
    246       // XXX: Not all instructions can use inline literals
    247       // XXX: We should make sure this is a 32-bit constant
    248       Imm.f = MO.getFPImm();
    249       Value |= ((uint64_t)Imm.i) << 32;
    250     }
    251   }
    252   return Value;
    253 }
    254 
    255 //===----------------------------------------------------------------------===//
    256 // Encoding helper functions
    257 //===----------------------------------------------------------------------===//
    258 
    259 unsigned SIMCCodeEmitter::getEncodingType(const MCInst &MI) const {
    260   return MCII.get(MI.getOpcode()).TSFlags & SI_INSTR_FLAGS_ENCODING_MASK;
    261 }
    262 
    263 unsigned SIMCCodeEmitter::getEncodingBytes(const MCInst &MI) const {
    264 
    265   // Instructions with literal constants are expanded to 64-bits, and
    266   // the constant is stored in bits [63:32]
    267   for (unsigned i = 0; i < MI.getNumOperands(); i++) {
    268     if (MI.getOperand(i).isFPImm()) {
    269       return 8;
    270     }
    271   }
    272 
    273   // This instruction always has a literal
    274   if (MI.getOpcode() == AMDGPU::S_MOV_IMM_I32) {
    275     return 8;
    276   }
    277 
    278   unsigned encoding_type = getEncodingType(MI);
    279   switch (encoding_type) {
    280     case SIInstrEncodingType::EXP:
    281     case SIInstrEncodingType::LDS:
    282     case SIInstrEncodingType::MUBUF:
    283     case SIInstrEncodingType::MTBUF:
    284     case SIInstrEncodingType::MIMG:
    285     case SIInstrEncodingType::VOP3:
    286       return 8;
    287     default:
    288       return 4;
    289   }
    290 }
    291 
    292 
    293 unsigned SIMCCodeEmitter::getRegBinaryCode(unsigned reg) const {
    294   switch (reg) {
    295     case AMDGPU::M0: return 124;
    296     case AMDGPU::SREG_LIT_0: return 128;
    297     default: return getHWRegNum(reg);
    298   }
    299 }
    300 
    301 #define SIRegisterInfo SIMCCodeEmitter
    302 #include "SIRegisterGetHWRegNum.inc"
    303 #undef SIRegisterInfo
    304