| //===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===// | |
| // | |
| // The LLVM Compiler Infrastructure | |
| // | |
| // This file is distributed under the University of Illinois Open Source | |
| // License. See LICENSE.TXT for details. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements the SystemZMCCodeEmitter class. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "MCTargetDesc/SystemZMCFixups.h" | |
| #include "MCTargetDesc/SystemZMCTargetDesc.h" | |
| #include "llvm/ADT/SmallVector.h" | |
| #include "llvm/MC/MCCodeEmitter.h" | |
| #include "llvm/MC/MCContext.h" | |
| #include "llvm/MC/MCExpr.h" | |
| #include "llvm/MC/MCFixup.h" | |
| #include "llvm/MC/MCInst.h" | |
| #include "llvm/MC/MCInstrInfo.h" | |
| #include "llvm/MC/MCRegisterInfo.h" | |
| #include "llvm/MC/MCSubtargetInfo.h" | |
| #include "llvm/Support/ErrorHandling.h" | |
| #include "llvm/Support/raw_ostream.h" | |
| #include <cassert> | |
| #include <cstdint> | |
| using namespace llvm; | |
| #define DEBUG_TYPE "mccodeemitter" | |
| namespace { | |
| class SystemZMCCodeEmitter : public MCCodeEmitter { | |
| const MCInstrInfo &MCII; | |
| MCContext &Ctx; | |
| public: | |
| SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) | |
| : MCII(mcii), Ctx(ctx) { | |
| } | |
| ~SystemZMCCodeEmitter() override = default; | |
| // OVerride MCCodeEmitter. | |
| void encodeInstruction(const MCInst &MI, raw_ostream &OS, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const override; | |
| private: | |
| // Automatically generated by TableGen. | |
| uint64_t getBinaryCodeForInstr(const MCInst &MI, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| // Called by the TableGen code to get the binary encoding of operand | |
| // MO in MI. Fixups is the list of fixups against MI. | |
| uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| // Called by the TableGen code to get the binary encoding of an address. | |
| // The index or length, if any, is encoded first, followed by the base, | |
| // followed by the displacement. In a 20-bit displacement, | |
| // the low 12 bits are encoded before the high 8 bits. | |
| uint64_t getBDAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDAddr20Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDLAddr12Len4Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| // Operand OpNum of MI needs a PC-relative fixup of kind Kind at | |
| // Offset bytes from the start of MI. Add the fixup to Fixups | |
| // and return the in-place addend, which since we're a RELA target | |
| // is always 0. If AllowTLS is true and optional operand OpNum + 1 | |
| // is present, also emit a TLS call fixup for it. | |
| uint64_t getPCRelEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| unsigned Kind, int64_t Offset, | |
| bool AllowTLS) const; | |
| uint64_t getPC16DBLEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC16DBL, 2, false); | |
| } | |
| uint64_t getPC32DBLEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC32DBL, 2, false); | |
| } | |
| uint64_t getPC16DBLTLSEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC16DBL, 2, true); | |
| } | |
| uint64_t getPC32DBLTLSEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC32DBL, 2, true); | |
| } | |
| uint64_t getPC12DBLBPPEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC12DBL, 1, false); | |
| } | |
| uint64_t getPC16DBLBPPEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC16DBL, 4, false); | |
| } | |
| uint64_t getPC24DBLBPPEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getPCRelEncoding(MI, OpNum, Fixups, | |
| SystemZ::FK_390_PC24DBL, 3, false); | |
| } | |
| private: | |
| uint64_t computeAvailableFeatures(const FeatureBitset &FB) const; | |
| void verifyInstructionPredicates(const MCInst &MI, | |
| uint64_t AvailableFeatures) const; | |
| }; | |
| } // end anonymous namespace | |
| void SystemZMCCodeEmitter:: | |
| encodeInstruction(const MCInst &MI, raw_ostream &OS, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| verifyInstructionPredicates(MI, | |
| computeAvailableFeatures(STI.getFeatureBits())); | |
| uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI); | |
| unsigned Size = MCII.get(MI.getOpcode()).getSize(); | |
| // Big-endian insertion of Size bytes. | |
| unsigned ShiftValue = (Size * 8) - 8; | |
| for (unsigned I = 0; I != Size; ++I) { | |
| OS << uint8_t(Bits >> ShiftValue); | |
| ShiftValue -= 8; | |
| } | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getMachineOpValue(const MCInst &MI, const MCOperand &MO, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| if (MO.isReg()) | |
| return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); | |
| if (MO.isImm()) | |
| return static_cast<uint64_t>(MO.getImm()); | |
| llvm_unreachable("Unexpected operand type!"); | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp)); | |
| return (Base << 12) | Disp; | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDAddr20Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| assert(isUInt<4>(Base) && isInt<20>(Disp)); | |
| return (Base << 20) | ((Disp & 0xfff) << 8) | ((Disp & 0xff000) >> 12); | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI); | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Index)); | |
| return (Index << 16) | (Base << 12) | Disp; | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI); | |
| assert(isUInt<4>(Base) && isInt<20>(Disp) && isUInt<4>(Index)); | |
| return (Index << 24) | (Base << 20) | ((Disp & 0xfff) << 8) | |
| | ((Disp & 0xff000) >> 12); | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDLAddr12Len4Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Len = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI) - 1; | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Len)); | |
| return (Len << 16) | (Base << 12) | Disp; | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Len = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI) - 1; | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<8>(Len)); | |
| return (Len << 16) | (Base << 12) | Disp; | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Len = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI); | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Len)); | |
| return (Len << 16) | (Base << 12) | Disp; | |
| } | |
| uint64_t SystemZMCCodeEmitter:: | |
| getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI); | |
| uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI); | |
| uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI); | |
| assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<5>(Index)); | |
| return (Index << 16) | (Base << 12) | Disp; | |
| } | |
| uint64_t | |
| SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| unsigned Kind, int64_t Offset, | |
| bool AllowTLS) const { | |
| const MCOperand &MO = MI.getOperand(OpNum); | |
| const MCExpr *Expr; | |
| if (MO.isImm()) | |
| Expr = MCConstantExpr::create(MO.getImm() + Offset, Ctx); | |
| else { | |
| Expr = MO.getExpr(); | |
| if (Offset) { | |
| // The operand value is relative to the start of MI, but the fixup | |
| // is relative to the operand field itself, which is Offset bytes | |
| // into MI. Add Offset to the relocation value to cancel out | |
| // this difference. | |
| const MCExpr *OffsetExpr = MCConstantExpr::create(Offset, Ctx); | |
| Expr = MCBinaryExpr::createAdd(Expr, OffsetExpr, Ctx); | |
| } | |
| } | |
| Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind)); | |
| // Output the fixup for the TLS marker if present. | |
| if (AllowTLS && OpNum + 1 < MI.getNumOperands()) { | |
| const MCOperand &MOTLS = MI.getOperand(OpNum + 1); | |
| Fixups.push_back(MCFixup::create(0, MOTLS.getExpr(), | |
| (MCFixupKind)SystemZ::FK_390_TLS_CALL)); | |
| } | |
| return 0; | |
| } | |
| #define ENABLE_INSTR_PREDICATE_VERIFIER | |
| #include "SystemZGenMCCodeEmitter.inc" | |
| MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII, | |
| const MCRegisterInfo &MRI, | |
| MCContext &Ctx) { | |
| return new SystemZMCCodeEmitter(MCII, Ctx); | |
| } |