18f0fd8f6SDimitry Andric //===-- SIMCCodeEmitter.cpp - SI Code Emitter -------------------------------===//
28f0fd8f6SDimitry Andric //
38f0fd8f6SDimitry Andric //                     The LLVM Compiler Infrastructure
48f0fd8f6SDimitry Andric //
58f0fd8f6SDimitry Andric // This file is distributed under the University of Illinois Open Source
68f0fd8f6SDimitry Andric // License. See LICENSE.TXT for details.
78f0fd8f6SDimitry Andric //
88f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===//
98f0fd8f6SDimitry Andric //
108f0fd8f6SDimitry Andric /// \file
118f0fd8f6SDimitry Andric /// \brief The SI code emitter produces machine code that can be executed
128f0fd8f6SDimitry Andric /// directly on the GPU device.
138f0fd8f6SDimitry Andric //
148f0fd8f6SDimitry Andric //===----------------------------------------------------------------------===//
158f0fd8f6SDimitry Andric 
168f0fd8f6SDimitry Andric #include "AMDGPU.h"
178f0fd8f6SDimitry Andric #include "MCTargetDesc/AMDGPUFixupKinds.h"
188f0fd8f6SDimitry Andric #include "MCTargetDesc/AMDGPUMCCodeEmitter.h"
198f0fd8f6SDimitry Andric #include "MCTargetDesc/AMDGPUMCTargetDesc.h"
208f0fd8f6SDimitry Andric #include "SIDefines.h"
218f0fd8f6SDimitry Andric #include "llvm/MC/MCCodeEmitter.h"
228f0fd8f6SDimitry Andric #include "llvm/MC/MCContext.h"
238f0fd8f6SDimitry Andric #include "llvm/MC/MCFixup.h"
248f0fd8f6SDimitry Andric #include "llvm/MC/MCInst.h"
258f0fd8f6SDimitry Andric #include "llvm/MC/MCInstrInfo.h"
268f0fd8f6SDimitry Andric #include "llvm/MC/MCRegisterInfo.h"
278f0fd8f6SDimitry Andric #include "llvm/MC/MCSubtargetInfo.h"
288f0fd8f6SDimitry Andric #include "llvm/Support/raw_ostream.h"
298f0fd8f6SDimitry Andric 
308f0fd8f6SDimitry Andric using namespace llvm;
318f0fd8f6SDimitry Andric 
328f0fd8f6SDimitry Andric namespace {
338f0fd8f6SDimitry Andric 
348f0fd8f6SDimitry Andric class SIMCCodeEmitter : public  AMDGPUMCCodeEmitter {
358f0fd8f6SDimitry Andric   SIMCCodeEmitter(const SIMCCodeEmitter &) = delete;
368f0fd8f6SDimitry Andric   void operator=(const SIMCCodeEmitter &) = delete;
378f0fd8f6SDimitry Andric   const MCInstrInfo &MCII;
388f0fd8f6SDimitry Andric   const MCRegisterInfo &MRI;
398f0fd8f6SDimitry Andric 
408f0fd8f6SDimitry Andric   /// \brief Can this operand also contain immediate values?
418f0fd8f6SDimitry Andric   bool isSrcOperand(const MCInstrDesc &Desc, unsigned OpNo) const;
428f0fd8f6SDimitry Andric 
438f0fd8f6SDimitry Andric   /// \brief Encode an fp or int literal
448f0fd8f6SDimitry Andric   uint32_t getLitEncoding(const MCOperand &MO, unsigned OpSize) const;
458f0fd8f6SDimitry Andric 
468f0fd8f6SDimitry Andric public:
478f0fd8f6SDimitry Andric   SIMCCodeEmitter(const MCInstrInfo &mcii, const MCRegisterInfo &mri,
488f0fd8f6SDimitry Andric                   MCContext &ctx)
497d523365SDimitry Andric     : MCII(mcii), MRI(mri) { }
508f0fd8f6SDimitry Andric 
518f0fd8f6SDimitry Andric   ~SIMCCodeEmitter() override {}
528f0fd8f6SDimitry Andric 
538f0fd8f6SDimitry Andric   /// \brief Encode the instruction and write it to the OS.
548f0fd8f6SDimitry Andric   void encodeInstruction(const MCInst &MI, raw_ostream &OS,
558f0fd8f6SDimitry Andric                          SmallVectorImpl<MCFixup> &Fixups,
568f0fd8f6SDimitry Andric                          const MCSubtargetInfo &STI) const override;
578f0fd8f6SDimitry Andric 
588f0fd8f6SDimitry Andric   /// \returns the encoding for an MCOperand.
598f0fd8f6SDimitry Andric   uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
608f0fd8f6SDimitry Andric                              SmallVectorImpl<MCFixup> &Fixups,
618f0fd8f6SDimitry Andric                              const MCSubtargetInfo &STI) const override;
628f0fd8f6SDimitry Andric 
638f0fd8f6SDimitry Andric   /// \brief Use a fixup to encode the simm16 field for SOPP branch
648f0fd8f6SDimitry Andric   ///        instructions.
658f0fd8f6SDimitry Andric   unsigned getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
668f0fd8f6SDimitry Andric                              SmallVectorImpl<MCFixup> &Fixups,
678f0fd8f6SDimitry Andric                              const MCSubtargetInfo &STI) const override;
688f0fd8f6SDimitry Andric };
698f0fd8f6SDimitry Andric 
708f0fd8f6SDimitry Andric } // End anonymous namespace
718f0fd8f6SDimitry Andric 
728f0fd8f6SDimitry Andric MCCodeEmitter *llvm::createSIMCCodeEmitter(const MCInstrInfo &MCII,
738f0fd8f6SDimitry Andric                                            const MCRegisterInfo &MRI,
748f0fd8f6SDimitry Andric                                            MCContext &Ctx) {
758f0fd8f6SDimitry Andric   return new SIMCCodeEmitter(MCII, MRI, Ctx);
768f0fd8f6SDimitry Andric }
778f0fd8f6SDimitry Andric 
788f0fd8f6SDimitry Andric bool SIMCCodeEmitter::isSrcOperand(const MCInstrDesc &Desc,
798f0fd8f6SDimitry Andric                                    unsigned OpNo) const {
808f0fd8f6SDimitry Andric   unsigned OpType = Desc.OpInfo[OpNo].OperandType;
818f0fd8f6SDimitry Andric 
828f0fd8f6SDimitry Andric   return OpType == AMDGPU::OPERAND_REG_IMM32 ||
838f0fd8f6SDimitry Andric          OpType == AMDGPU::OPERAND_REG_INLINE_C;
848f0fd8f6SDimitry Andric }
858f0fd8f6SDimitry Andric 
868f0fd8f6SDimitry Andric // Returns the encoding value to use if the given integer is an integer inline
878f0fd8f6SDimitry Andric // immediate value, or 0 if it is not.
888f0fd8f6SDimitry Andric template <typename IntTy>
898f0fd8f6SDimitry Andric static uint32_t getIntInlineImmEncoding(IntTy Imm) {
908f0fd8f6SDimitry Andric   if (Imm >= 0 && Imm <= 64)
918f0fd8f6SDimitry Andric     return 128 + Imm;
928f0fd8f6SDimitry Andric 
938f0fd8f6SDimitry Andric   if (Imm >= -16 && Imm <= -1)
948f0fd8f6SDimitry Andric     return 192 + std::abs(Imm);
958f0fd8f6SDimitry Andric 
968f0fd8f6SDimitry Andric   return 0;
978f0fd8f6SDimitry Andric }
988f0fd8f6SDimitry Andric 
998f0fd8f6SDimitry Andric static uint32_t getLit32Encoding(uint32_t Val) {
1008f0fd8f6SDimitry Andric   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int32_t>(Val));
1018f0fd8f6SDimitry Andric   if (IntImm != 0)
1028f0fd8f6SDimitry Andric     return IntImm;
1038f0fd8f6SDimitry Andric 
1048f0fd8f6SDimitry Andric   if (Val == FloatToBits(0.5f))
1058f0fd8f6SDimitry Andric     return 240;
1068f0fd8f6SDimitry Andric 
1078f0fd8f6SDimitry Andric   if (Val == FloatToBits(-0.5f))
1088f0fd8f6SDimitry Andric     return 241;
1098f0fd8f6SDimitry Andric 
1108f0fd8f6SDimitry Andric   if (Val == FloatToBits(1.0f))
1118f0fd8f6SDimitry Andric     return 242;
1128f0fd8f6SDimitry Andric 
1138f0fd8f6SDimitry Andric   if (Val == FloatToBits(-1.0f))
1148f0fd8f6SDimitry Andric     return 243;
1158f0fd8f6SDimitry Andric 
1168f0fd8f6SDimitry Andric   if (Val == FloatToBits(2.0f))
1178f0fd8f6SDimitry Andric     return 244;
1188f0fd8f6SDimitry Andric 
1198f0fd8f6SDimitry Andric   if (Val == FloatToBits(-2.0f))
1208f0fd8f6SDimitry Andric     return 245;
1218f0fd8f6SDimitry Andric 
1228f0fd8f6SDimitry Andric   if (Val == FloatToBits(4.0f))
1238f0fd8f6SDimitry Andric     return 246;
1248f0fd8f6SDimitry Andric 
1258f0fd8f6SDimitry Andric   if (Val == FloatToBits(-4.0f))
1268f0fd8f6SDimitry Andric     return 247;
1278f0fd8f6SDimitry Andric 
1288f0fd8f6SDimitry Andric   return 255;
1298f0fd8f6SDimitry Andric }
1308f0fd8f6SDimitry Andric 
1318f0fd8f6SDimitry Andric static uint32_t getLit64Encoding(uint64_t Val) {
1328f0fd8f6SDimitry Andric   uint32_t IntImm = getIntInlineImmEncoding(static_cast<int64_t>(Val));
1338f0fd8f6SDimitry Andric   if (IntImm != 0)
1348f0fd8f6SDimitry Andric     return IntImm;
1358f0fd8f6SDimitry Andric 
1368f0fd8f6SDimitry Andric   if (Val == DoubleToBits(0.5))
1378f0fd8f6SDimitry Andric     return 240;
1388f0fd8f6SDimitry Andric 
1398f0fd8f6SDimitry Andric   if (Val == DoubleToBits(-0.5))
1408f0fd8f6SDimitry Andric     return 241;
1418f0fd8f6SDimitry Andric 
1428f0fd8f6SDimitry Andric   if (Val == DoubleToBits(1.0))
1438f0fd8f6SDimitry Andric     return 242;
1448f0fd8f6SDimitry Andric 
1458f0fd8f6SDimitry Andric   if (Val == DoubleToBits(-1.0))
1468f0fd8f6SDimitry Andric     return 243;
1478f0fd8f6SDimitry Andric 
1488f0fd8f6SDimitry Andric   if (Val == DoubleToBits(2.0))
1498f0fd8f6SDimitry Andric     return 244;
1508f0fd8f6SDimitry Andric 
1518f0fd8f6SDimitry Andric   if (Val == DoubleToBits(-2.0))
1528f0fd8f6SDimitry Andric     return 245;
1538f0fd8f6SDimitry Andric 
1548f0fd8f6SDimitry Andric   if (Val == DoubleToBits(4.0))
1558f0fd8f6SDimitry Andric     return 246;
1568f0fd8f6SDimitry Andric 
1578f0fd8f6SDimitry Andric   if (Val == DoubleToBits(-4.0))
1588f0fd8f6SDimitry Andric     return 247;
1598f0fd8f6SDimitry Andric 
1608f0fd8f6SDimitry Andric   return 255;
1618f0fd8f6SDimitry Andric }
1628f0fd8f6SDimitry Andric 
1638f0fd8f6SDimitry Andric uint32_t SIMCCodeEmitter::getLitEncoding(const MCOperand &MO,
1648f0fd8f6SDimitry Andric                                          unsigned OpSize) const {
1653ca95b02SDimitry Andric 
1663ca95b02SDimitry Andric   int64_t Imm;
1673ca95b02SDimitry Andric   if (MO.isExpr()) {
1683ca95b02SDimitry Andric     const MCConstantExpr *C = dyn_cast<MCConstantExpr>(MO.getExpr());
1693ca95b02SDimitry Andric     if (!C)
1708f0fd8f6SDimitry Andric       return 255;
1718f0fd8f6SDimitry Andric 
1723ca95b02SDimitry Andric     Imm = C->getValue();
1733ca95b02SDimitry Andric   } else {
1743ca95b02SDimitry Andric 
1758f0fd8f6SDimitry Andric     assert(!MO.isFPImm());
1768f0fd8f6SDimitry Andric 
1778f0fd8f6SDimitry Andric     if (!MO.isImm())
1788f0fd8f6SDimitry Andric       return ~0;
1798f0fd8f6SDimitry Andric 
1803ca95b02SDimitry Andric     Imm = MO.getImm();
1813ca95b02SDimitry Andric   }
1823ca95b02SDimitry Andric 
1838f0fd8f6SDimitry Andric   if (OpSize == 4)
1843ca95b02SDimitry Andric     return getLit32Encoding(static_cast<uint32_t>(Imm));
1858f0fd8f6SDimitry Andric 
1868f0fd8f6SDimitry Andric   assert(OpSize == 8);
1878f0fd8f6SDimitry Andric 
1883ca95b02SDimitry Andric   return getLit64Encoding(static_cast<uint64_t>(Imm));
1898f0fd8f6SDimitry Andric }
1908f0fd8f6SDimitry Andric 
1918f0fd8f6SDimitry Andric void SIMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
1928f0fd8f6SDimitry Andric                                        SmallVectorImpl<MCFixup> &Fixups,
1938f0fd8f6SDimitry Andric                                        const MCSubtargetInfo &STI) const {
1948f0fd8f6SDimitry Andric 
1958f0fd8f6SDimitry Andric   uint64_t Encoding = getBinaryCodeForInstr(MI, Fixups, STI);
1968f0fd8f6SDimitry Andric   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
1978f0fd8f6SDimitry Andric   unsigned bytes = Desc.getSize();
1988f0fd8f6SDimitry Andric 
1998f0fd8f6SDimitry Andric   for (unsigned i = 0; i < bytes; i++) {
2008f0fd8f6SDimitry Andric     OS.write((uint8_t) ((Encoding >> (8 * i)) & 0xff));
2018f0fd8f6SDimitry Andric   }
2028f0fd8f6SDimitry Andric 
2038f0fd8f6SDimitry Andric   if (bytes > 4)
2048f0fd8f6SDimitry Andric     return;
2058f0fd8f6SDimitry Andric 
2068f0fd8f6SDimitry Andric   // Check for additional literals in SRC0/1/2 (Op 1/2/3)
2078f0fd8f6SDimitry Andric   for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
2088f0fd8f6SDimitry Andric 
2098f0fd8f6SDimitry Andric     // Check if this operand should be encoded as [SV]Src
2108f0fd8f6SDimitry Andric     if (!isSrcOperand(Desc, i))
2118f0fd8f6SDimitry Andric       continue;
2128f0fd8f6SDimitry Andric 
2138f0fd8f6SDimitry Andric     int RCID = Desc.OpInfo[i].RegClass;
2148f0fd8f6SDimitry Andric     const MCRegisterClass &RC = MRI.getRegClass(RCID);
2158f0fd8f6SDimitry Andric 
2168f0fd8f6SDimitry Andric     // Is this operand a literal immediate?
2178f0fd8f6SDimitry Andric     const MCOperand &Op = MI.getOperand(i);
2188f0fd8f6SDimitry Andric     if (getLitEncoding(Op, RC.getSize()) != 255)
2198f0fd8f6SDimitry Andric       continue;
2208f0fd8f6SDimitry Andric 
2218f0fd8f6SDimitry Andric     // Yes! Encode it
2228f0fd8f6SDimitry Andric     int64_t Imm = 0;
2238f0fd8f6SDimitry Andric 
2248f0fd8f6SDimitry Andric     if (Op.isImm())
2258f0fd8f6SDimitry Andric       Imm = Op.getImm();
2263ca95b02SDimitry Andric     else if (Op.isExpr()) {
2273ca95b02SDimitry Andric       if (const MCConstantExpr *C = dyn_cast<MCConstantExpr>(Op.getExpr()))
2283ca95b02SDimitry Andric         Imm = C->getValue();
2293ca95b02SDimitry Andric 
2303ca95b02SDimitry Andric     } else if (!Op.isExpr()) // Exprs will be replaced with a fixup value.
2318f0fd8f6SDimitry Andric       llvm_unreachable("Must be immediate or expr");
2328f0fd8f6SDimitry Andric 
2338f0fd8f6SDimitry Andric     for (unsigned j = 0; j < 4; j++) {
2348f0fd8f6SDimitry Andric       OS.write((uint8_t) ((Imm >> (8 * j)) & 0xff));
2358f0fd8f6SDimitry Andric     }
2368f0fd8f6SDimitry Andric 
2378f0fd8f6SDimitry Andric     // Only one literal value allowed
2388f0fd8f6SDimitry Andric     break;
2398f0fd8f6SDimitry Andric   }
2408f0fd8f6SDimitry Andric }
2418f0fd8f6SDimitry Andric 
2428f0fd8f6SDimitry Andric unsigned SIMCCodeEmitter::getSOPPBrEncoding(const MCInst &MI, unsigned OpNo,
2438f0fd8f6SDimitry Andric                                             SmallVectorImpl<MCFixup> &Fixups,
2448f0fd8f6SDimitry Andric                                             const MCSubtargetInfo &STI) const {
2458f0fd8f6SDimitry Andric   const MCOperand &MO = MI.getOperand(OpNo);
2468f0fd8f6SDimitry Andric 
2478f0fd8f6SDimitry Andric   if (MO.isExpr()) {
2488f0fd8f6SDimitry Andric     const MCExpr *Expr = MO.getExpr();
2498f0fd8f6SDimitry Andric     MCFixupKind Kind = (MCFixupKind)AMDGPU::fixup_si_sopp_br;
2508f0fd8f6SDimitry Andric     Fixups.push_back(MCFixup::create(0, Expr, Kind, MI.getLoc()));
2518f0fd8f6SDimitry Andric     return 0;
2528f0fd8f6SDimitry Andric   }
2538f0fd8f6SDimitry Andric 
2548f0fd8f6SDimitry Andric   return getMachineOpValue(MI, MO, Fixups, STI);
2558f0fd8f6SDimitry Andric }
2568f0fd8f6SDimitry Andric 
2578f0fd8f6SDimitry Andric uint64_t SIMCCodeEmitter::getMachineOpValue(const MCInst &MI,
2588f0fd8f6SDimitry Andric                                             const MCOperand &MO,
2598f0fd8f6SDimitry Andric                                        SmallVectorImpl<MCFixup> &Fixups,
2608f0fd8f6SDimitry Andric                                        const MCSubtargetInfo &STI) const {
2618f0fd8f6SDimitry Andric   if (MO.isReg())
2628f0fd8f6SDimitry Andric     return MRI.getEncodingValue(MO.getReg());
2638f0fd8f6SDimitry Andric 
2643ca95b02SDimitry Andric   if (MO.isExpr() && MO.getExpr()->getKind() != MCExpr::Constant) {
2653ca95b02SDimitry Andric     const MCSymbolRefExpr *Expr = dyn_cast<MCSymbolRefExpr>(MO.getExpr());
2663ca95b02SDimitry Andric     MCFixupKind Kind;
2673ca95b02SDimitry Andric     if (Expr && Expr->getSymbol().isExternal())
2683ca95b02SDimitry Andric       Kind = FK_Data_4;
2693ca95b02SDimitry Andric     else
2703ca95b02SDimitry Andric       Kind = FK_PCRel_4;
2713ca95b02SDimitry Andric     Fixups.push_back(MCFixup::create(4, MO.getExpr(), Kind, MI.getLoc()));
2728f0fd8f6SDimitry Andric   }
2738f0fd8f6SDimitry Andric 
2748f0fd8f6SDimitry Andric   // Figure out the operand number, needed for isSrcOperand check
2758f0fd8f6SDimitry Andric   unsigned OpNo = 0;
2768f0fd8f6SDimitry Andric   for (unsigned e = MI.getNumOperands(); OpNo < e; ++OpNo) {
2778f0fd8f6SDimitry Andric     if (&MO == &MI.getOperand(OpNo))
2788f0fd8f6SDimitry Andric       break;
2798f0fd8f6SDimitry Andric   }
2808f0fd8f6SDimitry Andric 
2818f0fd8f6SDimitry Andric   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
2828f0fd8f6SDimitry Andric   if (isSrcOperand(Desc, OpNo)) {
2838f0fd8f6SDimitry Andric     int RCID = Desc.OpInfo[OpNo].RegClass;
2848f0fd8f6SDimitry Andric     const MCRegisterClass &RC = MRI.getRegClass(RCID);
2858f0fd8f6SDimitry Andric 
2868f0fd8f6SDimitry Andric     uint32_t Enc = getLitEncoding(MO, RC.getSize());
2878f0fd8f6SDimitry Andric     if (Enc != ~0U && (Enc != 255 || Desc.getSize() == 4))
2888f0fd8f6SDimitry Andric       return Enc;
2898f0fd8f6SDimitry Andric 
2908f0fd8f6SDimitry Andric   } else if (MO.isImm())
2918f0fd8f6SDimitry Andric     return MO.getImm();
2928f0fd8f6SDimitry Andric 
2938f0fd8f6SDimitry Andric   llvm_unreachable("Encoding of this operand type is not supported yet.");
2948f0fd8f6SDimitry Andric   return 0;
2958f0fd8f6SDimitry Andric }
2968f0fd8f6SDimitry Andric 
297