| //===-- 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, 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 |
| |
| 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; |
| Fixups.push_back(MCFixup::create(BitOffset >> 3, MO.getExpr(), |
| (MCFixupKind)Kind, MI.getLoc())); |
| assert(Fixups.size() <= 2 && "More than two memory operands in MI?"); |
| 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); |
| } |
| } |
| Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind, Loc)); |
| |
| // 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, Loc)); |
| } |
| return 0; |
| } |
| |
| #define GET_OPERAND_BIT_OFFSET |
| #include "SystemZGenMCCodeEmitter.inc" |
| |
| MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII, |
| MCContext &Ctx) { |
| return new SystemZMCCodeEmitter(MCII, Ctx); |
| } |