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