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 "AMDGPU.h"
     17 #include "MCTargetDesc/AMDGPUFixupKinds.h"
     18 #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
     19 #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
     20 #include "SIDefines.h"
     21 #include "llvm/MC/MCCodeEmitter.h"
     22 #include "llvm/MC/MCContext.h"
     23 #include "llvm/MC/MCFixup.h"
     24 #include "llvm/MC/MCInst.h"
     25 #include "llvm/MC/MCInstrInfo.h"
     26 #include "llvm/MC/MCRegisterInfo.h"
     27 #include "llvm/MC/MCSubtargetInfo.h"
     28 #include "llvm/Support/raw_ostream.h"
     29 
     30 using namespace llvm;
     31 
     32 namespace {
     33 
     34 class SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
     35   SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
     36   void operator=(const SIMCCodeEmitter &) = delete;
     37   const MCInstrInfo &MCII;
     38   const MCRegisterInfo &MRI;
     39 
     40   /// \brief Can this operand also contain immediate values?
     41   bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
     42 
     43   /// \brief Encode an fp or int literal
     44   uint32_t getLitEncoding(const MCOperand &MO, unsigned OpSize) const;
     45 
     46 public:
     47   SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
     48                   MCContext &ctx)
     49     : MCII(mcii), MRI(mri) { }
     50 
     51   ~SIMCCodeEmitter() override {}
     52 
     53   /// \brief Encode the instruction and write it to the OS.
     54   void encodeInstruction(const MCInst &MI, raw_ostream &OS,
     55                          SmallVectorImpl<MCFixup> &Fixups,
     56                          const MCSubtargetInfo &STI) const override;
     57 
     58   /// \returns the encoding for an MCOperand.
     59   uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
     60                              SmallVectorImpl<MCFixup> &Fixups,
     61                              const MCSubtargetInfo &STI) const override;
     62 
     63   /// \brief Use a fixup to encode the simm16 field for SOPP branch
     64   ///        instructions.
     65   unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
     66                              SmallVectorImpl<MCFixup> &Fixups,
     67                              const MCSubtargetInfo &STI) const override;
     68 };
     69 
     70 } // End anonymous namespace
     71 
     72 MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
     73                                            const MCRegisterInfo &MRI,
     74                                            MCContext &Ctx) {
     75   return new SIMCCodeEmitter(MCII, MRI, Ctx);
     76 }
     77 
     78 bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
     79                                    unsigned OpNo) const {
     80   unsigned OpType = Desc.OpInfo[OpNo].OperandType;
     81 
     82   return OpType == AMDGPU::OPERAND_REG_IMM32 ||
     83          OpType == AMDGPU::OPERAND_REG_INLINE_C;
     84 }
     85 
     86 // Returns the encoding value to use if the given integer is an integer inline
     87 // immediate value, or 0 if it is not.
     88 template <typename IntTy>
     89 static uint32_t getIntInlineImmEncoding(IntTy Imm) {
     90   if (Imm >= 0 && Imm <= 64)
     91     return 128 + Imm;
     92 
     93   if (Imm >= -16 && Imm <= -1)
     94     return 192 + std::abs(Imm);
     95 
     96   return 0;
     97 }
     98 
     99 static uint32_t getLit32Encoding(uint32_t Val) {
    100   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
    101   if (IntImm != 0)
    102     return IntImm;
    103 
    104   if (Val == FloatToBits(0.5f))
    105     return 240;
    106 
    107   if (Val == FloatToBits(-0.5f))
    108     return 241;
    109 
    110   if (Val == FloatToBits(1.0f))
    111     return 242;
    112 
    113   if (Val == FloatToBits(-1.0f))
    114     return 243;
    115 
    116   if (Val == FloatToBits(2.0f))
    117     return 244;
    118 
    119   if (Val == FloatToBits(-2.0f))
    120     return 245;
    121 
    122   if (Val == FloatToBits(4.0f))
    123     return 246;
    124 
    125   if (Val == FloatToBits(-4.0f))
    126     return 247;
    127 
    128   return 255;
    129 }
    130 
    131 static uint32_t getLit64Encoding(uint64_t Val) {
    132   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
    133   if (IntImm != 0)
    134     return IntImm;
    135 
    136   if (Val == DoubleToBits(0.5))
    137     return 240;
    138 
    139   if (Val == DoubleToBits(-0.5))
    140     return 241;
    141 
    142   if (Val == DoubleToBits(1.0))
    143     return 242;
    144 
    145   if (Val == DoubleToBits(-1.0))
    146     return 243;
    147 
    148   if (Val == DoubleToBits(2.0))
    149     return 244;
    150 
    151   if (Val == DoubleToBits(-2.0))
    152     return 245;
    153 
    154   if (Val == DoubleToBits(4.0))
    155     return 246;
    156 
    157   if (Val == DoubleToBits(-4.0))
    158     return 247;
    159 
    160   return 255;
    161 }
    162 
    163 uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
    164                                          unsigned OpSize) const {
    165 
    166   int64_t Imm;
    167   if (MO.isExpr()) {
    168     const MCConstantExpr *C = dyn_cast<MCConstantExpr>(MO.getExpr());
    169     if (!C)
    170       return 255;
    171 
    172     Imm = C->getValue();
    173   } else {
    174 
    175     assert(!MO.isFPImm());
    176 
    177     if (!MO.isImm())
    178       return ~0;
    179 
    180     Imm = MO.getImm();
    181   }
    182 
    183   if (OpSize == 4)
    184     return getLit32Encoding(static_cast<uint32_t>(Imm));
    185 
    186   assert(OpSize == 8);
    187 
    188   return getLit64Encoding(static_cast<uint64_t>(Imm));
    189 }
    190 
    191 void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
    192                                        SmallVectorImpl<MCFixup> &Fixups,
    193                                        const MCSubtargetInfo &STI) const {
    194 
    195   uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
    196   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
    197   unsigned bytes = Desc.getSize();
    198 
    199   for (unsigned i = 0; i < bytes; i++) {
    200     OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
    201   }
    202 
    203   if (bytes > 4)
    204     return;
    205 
    206   // Check for additional literals in SRC0/1/2 (Op 1/2/3)
    207   for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
    208 
    209     // Check if this operand should be encoded as [SV]Src
    210     if (!isSrcOperand(Desc, i))
    211       continue;
    212 
    213     int RCID = Desc.OpInfo[i].RegClass;
    214     const MCRegisterClass &RC = MRI.getRegClass(RCID);
    215 
    216     // Is this operand a literal immediate?
    217     const MCOperand &Op = MI.getOperand(i);
    218     if (getLitEncoding(Op, RC.getSize()) != 255)
    219       continue;
    220 
    221     // Yes! Encode it
    222     int64_t Imm = 0;
    223 
    224     if (Op.isImm())
    225       Imm = Op.getImm();
    226     else if (Op.isExpr()) {
    227       if (const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
    228         Imm = C->getValue();
    229 
    230     } else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
    231       llvm_unreachable("Must be immediate or expr");
    232 
    233     for (unsigned j = 0; j < 4; j++) {
    234       OS.write((uint8_t) ((Imm >> (8 * j)) & 0xff));
    235     }
    236 
    237     // Only one literal value allowed
    238     break;
    239   }
    240 }
    241 
    242 unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
    243                                             SmallVectorImpl<MCFixup> &Fixups,
    244                                             const MCSubtargetInfo &STI) const {
    245   const MCOperand &MO = MI.getOperand(OpNo);
    246 
    247   if (MO.isExpr()) {
    248     const MCExpr *Expr = MO.getExpr();
    249     MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
    250     Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
    251     return 0;
    252   }
    253 
    254   return getMachineOpValue(MI, MO, Fixups, STI);
    255 }
    256 
    257 uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
    258                                             const MCOperand &MO,
    259                                        SmallVectorImpl<MCFixup> &Fixups,
    260                                        const MCSubtargetInfo &STI) const {
    261   if (MO.isReg())
    262     return MRI.getEncodingValue(MO.getReg());
    263 
    264   if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
    265     const MCSymbolRefExpr *Expr = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
    266     MCFixupKind Kind;
    267     if (Expr && Expr->getSymbol().isExternal())
    268       Kind = FK_Data_4;
    269     else
    270       Kind = FK_PCRel_4;
    271     Fixups.push_back(MCFixup::create(4, MO.getExpr(), Kind, MI.getLoc()));
    272   }
    273 
    274   // Figure out the operand number, needed for isSrcOperand check
    275   unsigned OpNo = 0;
    276   for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
    277     if (&MO == &MI.getOperand(OpNo))
    278       break;
    279   }
    280 
    281   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
    282   if (isSrcOperand(Desc, OpNo)) {
    283     int RCID = Desc.OpInfo[OpNo].RegClass;
    284     const MCRegisterClass &RC = MRI.getRegClass(RCID);
    285 
    286     uint32_t Enc = getLitEncoding(MO, RC.getSize());
    287     if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
    288       return Enc;
    289 
    290   } else if (MO.isImm())
    291     return MO.getImm();
    292 
    293   llvm_unreachable("Encoding of this operand type is not supported yet.");
    294   return 0;
    295 }
    296 
    297