| //===-- 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 "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 <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, SmallVectorImpl<char> &CB, | |
| 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; | |
| uint32_t getOperandBitOffset(const MCInst &MI, unsigned OpNum, | |
| 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 encoded immediate value for the OpNum operand. If it is a | |
| // symbol, add a fixup for it and return 0. | |
| template <SystemZ::FixupKind Kind> | |
| uint64_t getImmOpValue(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const; | |
| // Called by the TableGen code to get the binary encoding of a length value. | |
| // Length values are encoded by subtracting 1 from the actual value. | |
| template <SystemZ::FixupKind Kind> | |
| uint64_t getLenEncoding(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); | |
| } | |
| }; | |
| } // end anonymous namespace | |
| // | |
| static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset, | |
| const MCExpr *Value, uint16_t Kind, bool PCRel = false) { | |
| Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel)); | |
| } | |
| void SystemZMCCodeEmitter::encodeInstruction(const MCInst &MI, | |
| SmallVectorImpl<char> &CB, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| 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) { | |
| CB.push_back(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()); | |
| // SystemZAsmParser::parseAnyRegister() produces KindImm when registers are | |
| // specified as integers. | |
| if (MO.isImm()) | |
| return static_cast<uint64_t>(MO.getImm()); | |
| llvm_unreachable("Unexpected operand type!"); | |
| } | |
| template <SystemZ::FixupKind Kind> | |
| uint64_t SystemZMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| const MCOperand &MO = MI.getOperand(OpNum); | |
| if (MO.isImm()) | |
| return static_cast<uint64_t>(MO.getImm()); | |
| if (MO.isExpr()) { | |
| unsigned MIBitSize = MCII.get(MI.getOpcode()).getSize() * 8; | |
| uint32_t RawBitOffset = getOperandBitOffset(MI, OpNum, STI); | |
| unsigned OpBitSize = | |
| SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind].TargetSize; | |
| uint32_t BitOffset = MIBitSize - RawBitOffset - OpBitSize; | |
| addFixup(Fixups, BitOffset >> 3, MO.getExpr(), Kind); | |
| return 0; | |
| } | |
| llvm_unreachable("Unexpected operand type!"); | |
| } | |
| template <SystemZ::FixupKind Kind> | |
| uint64_t | |
| SystemZMCCodeEmitter::getLenEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| const MCSubtargetInfo &STI) const { | |
| return getImmOpValue<Kind>(MI, OpNum, Fixups, STI) - 1; | |
| } | |
| uint64_t | |
| SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum, | |
| SmallVectorImpl<MCFixup> &Fixups, | |
| unsigned Kind, int64_t Offset, | |
| bool AllowTLS) const { | |
| SMLoc Loc = MI.getLoc(); | |
| 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, Loc); | |
| } | |
| } | |
| addFixup(Fixups, Offset, Expr, Kind, true); | |
| // Output the fixup for the TLS marker if present. | |
| if (AllowTLS && OpNum + 1 < MI.getNumOperands()) { | |
| const MCOperand &MOTLS = MI.getOperand(OpNum + 1); | |
| addFixup(Fixups, 0, MOTLS.getExpr(), SystemZ::FK_390_TLS_CALL); | |
| } | |
| return 0; | |
| } | |
| #define GET_OPERAND_BIT_OFFSET | |
| #include "SystemZGenMCCodeEmitter.inc" | |
| MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII, | |
| MCContext &Ctx) { | |
| return new SystemZMCCodeEmitter(MCII, Ctx); | |
| } |