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