1//===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements the SystemZMCCodeEmitter class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "MCTargetDesc/SystemZMCFixups.h"
14#include "MCTargetDesc/SystemZMCTargetDesc.h"
15#include "llvm/ADT/SmallVector.h"
16#include "llvm/MC/MCCodeEmitter.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCExpr.h"
19#include "llvm/MC/MCFixup.h"
20#include "llvm/MC/MCInst.h"
21#include "llvm/MC/MCInstrInfo.h"
22#include "llvm/MC/MCRegisterInfo.h"
23#include "llvm/MC/MCSubtargetInfo.h"
24#include <cassert>
25#include <cstdint>
26
27using namespace llvm;
28
29#define DEBUG_TYPE "mccodeemitter"
30
31namespace {
32
33class SystemZMCCodeEmitter : public MCCodeEmitter {
34 const MCInstrInfo &MCII;
35 MCContext &Ctx;
36
37public:
38 SystemZMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx)
39 : MCII(MCII), Ctx(Ctx) {}
40
41 ~SystemZMCCodeEmitter() override = default;
42
43 // OVerride MCCodeEmitter.
44 void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
45 SmallVectorImpl<MCFixup> &Fixups,
46 const MCSubtargetInfo &STI) const override;
47
48private:
49 // Automatically generated by TableGen.
50 uint64_t getBinaryCodeForInstr(const MCInst &MI,
51 SmallVectorImpl<MCFixup> &Fixups,
52 const MCSubtargetInfo &STI) const;
53 uint32_t getOperandBitOffset(const MCInst &MI, unsigned OpNum,
54 const MCSubtargetInfo &STI) const;
55
56 // Called by the TableGen code to get the binary encoding of operand
57 // MO in MI. Fixups is the list of fixups against MI.
58 uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
59 SmallVectorImpl<MCFixup> &Fixups,
60 const MCSubtargetInfo &STI) const;
61
62 // Return the encoded immediate value for the OpNum operand. If it is a
63 // symbol, add a fixup for it and return 0.
64 template <SystemZ::FixupKind Kind>
65 uint64_t getImmOpValue(const MCInst &MI, unsigned OpNum,
66 SmallVectorImpl<MCFixup> &Fixups,
67 const MCSubtargetInfo &STI) const;
68
69 // Called by the TableGen code to get the binary encoding of a length value.
70 // Length values are encoded by subtracting 1 from the actual value.
71 template <SystemZ::FixupKind Kind>
72 uint64_t getLenEncoding(const MCInst &MI, unsigned OpNum,
73 SmallVectorImpl<MCFixup> &Fixups,
74 const MCSubtargetInfo &STI) const;
75
76 // Operand OpNum of MI needs a PC-relative fixup of kind Kind at
77 // Offset bytes from the start of MI. Add the fixup to Fixups
78 // and return the in-place addend, which since we're a RELA target
79 // is always 0. If AllowTLS is true and optional operand OpNum + 1
80 // is present, also emit a TLS call fixup for it.
81 uint64_t getPCRelEncoding(const MCInst &MI, unsigned OpNum,
82 SmallVectorImpl<MCFixup> &Fixups,
83 unsigned Kind, int64_t Offset,
84 bool AllowTLS) const;
85
86 uint64_t getPC16DBLEncoding(const MCInst &MI, unsigned OpNum,
87 SmallVectorImpl<MCFixup> &Fixups,
88 const MCSubtargetInfo &STI) const {
89 return getPCRelEncoding(MI, OpNum, Fixups,
90 Kind: SystemZ::FK_390_PC16DBL, Offset: 2, AllowTLS: false);
91 }
92 uint64_t getPC32DBLEncoding(const MCInst &MI, unsigned OpNum,
93 SmallVectorImpl<MCFixup> &Fixups,
94 const MCSubtargetInfo &STI) const {
95 return getPCRelEncoding(MI, OpNum, Fixups,
96 Kind: SystemZ::FK_390_PC32DBL, Offset: 2, AllowTLS: false);
97 }
98 uint64_t getPC16DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
99 SmallVectorImpl<MCFixup> &Fixups,
100 const MCSubtargetInfo &STI) const {
101 return getPCRelEncoding(MI, OpNum, Fixups,
102 Kind: SystemZ::FK_390_PC16DBL, Offset: 2, AllowTLS: true);
103 }
104 uint64_t getPC32DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
105 SmallVectorImpl<MCFixup> &Fixups,
106 const MCSubtargetInfo &STI) const {
107 return getPCRelEncoding(MI, OpNum, Fixups,
108 Kind: SystemZ::FK_390_PC32DBL, Offset: 2, AllowTLS: true);
109 }
110 uint64_t getPC12DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
111 SmallVectorImpl<MCFixup> &Fixups,
112 const MCSubtargetInfo &STI) const {
113 return getPCRelEncoding(MI, OpNum, Fixups,
114 Kind: SystemZ::FK_390_PC12DBL, Offset: 1, AllowTLS: false);
115 }
116 uint64_t getPC16DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
117 SmallVectorImpl<MCFixup> &Fixups,
118 const MCSubtargetInfo &STI) const {
119 return getPCRelEncoding(MI, OpNum, Fixups,
120 Kind: SystemZ::FK_390_PC16DBL, Offset: 4, AllowTLS: false);
121 }
122 uint64_t getPC24DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
123 SmallVectorImpl<MCFixup> &Fixups,
124 const MCSubtargetInfo &STI) const {
125 return getPCRelEncoding(MI, OpNum, Fixups,
126 Kind: SystemZ::FK_390_PC24DBL, Offset: 3, AllowTLS: false);
127 }
128};
129
130} // end anonymous namespace
131 //
132static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,
133 const MCExpr *Value, uint16_t Kind, bool PCRel = false) {
134 Fixups.push_back(Elt: MCFixup::create(Offset, Value, Kind, PCRel));
135}
136
137void SystemZMCCodeEmitter::encodeInstruction(const MCInst &MI,
138 SmallVectorImpl<char> &CB,
139 SmallVectorImpl<MCFixup> &Fixups,
140 const MCSubtargetInfo &STI) const {
141 uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
142 unsigned Size = MCII.get(Opcode: MI.getOpcode()).getSize();
143 // Big-endian insertion of Size bytes.
144 unsigned ShiftValue = (Size * 8) - 8;
145 for (unsigned I = 0; I != Size; ++I) {
146 CB.push_back(Elt: uint8_t(Bits >> ShiftValue));
147 ShiftValue -= 8;
148 }
149}
150
151uint64_t SystemZMCCodeEmitter::
152getMachineOpValue(const MCInst &MI, const MCOperand &MO,
153 SmallVectorImpl<MCFixup> &Fixups,
154 const MCSubtargetInfo &STI) const {
155 if (MO.isReg())
156 return Ctx.getRegisterInfo()->getEncodingValue(Reg: MO.getReg());
157 // SystemZAsmParser::parseAnyRegister() produces KindImm when registers are
158 // specified as integers.
159 if (MO.isImm())
160 return static_cast<uint64_t>(MO.getImm());
161 llvm_unreachable("Unexpected operand type!");
162}
163
164template <SystemZ::FixupKind Kind>
165uint64_t SystemZMCCodeEmitter::getImmOpValue(const MCInst &MI, unsigned OpNum,
166 SmallVectorImpl<MCFixup> &Fixups,
167 const MCSubtargetInfo &STI) const {
168 const MCOperand &MO = MI.getOperand(i: OpNum);
169 if (MO.isImm())
170 return static_cast<uint64_t>(MO.getImm());
171 if (MO.isExpr()) {
172 unsigned MIBitSize = MCII.get(Opcode: MI.getOpcode()).getSize() * 8;
173 uint32_t RawBitOffset = getOperandBitOffset(MI, OpNum, STI);
174 unsigned OpBitSize =
175 SystemZ::MCFixupKindInfos[Kind - FirstTargetFixupKind].TargetSize;
176 uint32_t BitOffset = MIBitSize - RawBitOffset - OpBitSize;
177 addFixup(Fixups, Offset: BitOffset >> 3, Value: MO.getExpr(), Kind);
178 return 0;
179 }
180 llvm_unreachable("Unexpected operand type!");
181}
182
183template <SystemZ::FixupKind Kind>
184uint64_t
185SystemZMCCodeEmitter::getLenEncoding(const MCInst &MI, unsigned OpNum,
186 SmallVectorImpl<MCFixup> &Fixups,
187 const MCSubtargetInfo &STI) const {
188 return getImmOpValue<Kind>(MI, OpNum, Fixups, STI) - 1;
189}
190
191uint64_t
192SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
193 SmallVectorImpl<MCFixup> &Fixups,
194 unsigned Kind, int64_t Offset,
195 bool AllowTLS) const {
196 SMLoc Loc = MI.getLoc();
197 const MCOperand &MO = MI.getOperand(i: OpNum);
198 const MCExpr *Expr;
199 if (MO.isImm())
200 Expr = MCConstantExpr::create(Value: MO.getImm() + Offset, Ctx);
201 else {
202 Expr = MO.getExpr();
203 if (Offset) {
204 // The operand value is relative to the start of MI, but the fixup
205 // is relative to the operand field itself, which is Offset bytes
206 // into MI. Add Offset to the relocation value to cancel out
207 // this difference.
208 const MCExpr *OffsetExpr = MCConstantExpr::create(Value: Offset, Ctx);
209 Expr = MCBinaryExpr::createAdd(LHS: Expr, RHS: OffsetExpr, Ctx, Loc);
210 }
211 }
212 addFixup(Fixups, Offset, Value: Expr, Kind, PCRel: true);
213
214 // Output the fixup for the TLS marker if present.
215 if (AllowTLS && OpNum + 1 < MI.getNumOperands()) {
216 const MCOperand &MOTLS = MI.getOperand(i: OpNum + 1);
217 addFixup(Fixups, Offset: 0, Value: MOTLS.getExpr(), Kind: SystemZ::FK_390_TLS_CALL);
218 }
219 return 0;
220}
221
222#define GET_OPERAND_BIT_OFFSET
223#include "SystemZGenMCCodeEmitter.inc"
224
225MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
226 MCContext &Ctx) {
227 return new SystemZMCCodeEmitter(MCII, Ctx);
228}
229