| //===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements the SystemZMCCodeEmitter class. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "MCTargetDesc/SystemZMCFixups.h" |
| #include "MCTargetDesc/SystemZMCTargetDesc.h" |
| #include "SystemZInstrInfo.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; |
| |
| // Return the displacement value for the OpNum operand. If it is a symbol, |
| // add a fixup for it and return 0. |
| uint64_t getDispOpValue(const MCInst &MI, unsigned OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| SystemZ::FixupKind Kind) 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: |
| FeatureBitset computeAvailableFeatures(const FeatureBitset &FB) const; |
| void |
| verifyInstructionPredicates(const MCInst &MI, |
| const FeatureBitset &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:: |
| getDispOpValue(const MCInst &MI, unsigned OpNum, |
| SmallVectorImpl<MCFixup> &Fixups, |
| SystemZ::FixupKind Kind) const { |
| const MCOperand &MO = MI.getOperand(OpNum); |
| if (MO.isImm()) |
| return static_cast<uint64_t>(MO.getImm()); |
| if (MO.isExpr()) { |
| // All instructions follow the pattern where the first displacement has a |
| // 2 bytes offset, and the second one 4 bytes. |
| unsigned ByteOffs = Fixups.size() == 0 ? 2 : 4; |
| Fixups.push_back(MCFixup::create(ByteOffs, MO.getExpr(), (MCFixupKind)Kind)); |
| assert(Fixups.size() <= 2 && "More than two memory operands in MI?"); |
| return 0; |
| } |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_20); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_20); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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 = getDispOpValue(MI, OpNum + 1, Fixups, SystemZ::FK_390_12); |
| 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); |
| } |