1 //===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements the SystemZMCCodeEmitter class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MCTargetDesc/SystemZMCFixups.h"
15 #include "MCTargetDesc/SystemZMCTargetDesc.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, raw_ostream &OS,
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 
58   // Called by the TableGen code to get the binary encoding of operand
59   // MO in MI.  Fixups is the list of fixups against MI.
60   uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
61                              SmallVectorImpl<MCFixup> &Fixups,
62                              const MCSubtargetInfo &STI) const;
63 
64   // Called by the TableGen code to get the binary encoding of an address.
65   // The index or length, if any, is encoded first, followed by the base,
66   // followed by the displacement.  In a 20-bit displacement,
67   // the low 12 bits are encoded before the high 8 bits.
68   uint64_t getBDAddr12Encoding(const MCInst &MI, unsigned OpNum,
69                                SmallVectorImpl<MCFixup> &Fixups,
70                                const MCSubtargetInfo &STI) const;
71   uint64_t getBDAddr20Encoding(const MCInst &MI, unsigned OpNum,
72                                SmallVectorImpl<MCFixup> &Fixups,
73                                const MCSubtargetInfo &STI) const;
74   uint64_t getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum,
75                                 SmallVectorImpl<MCFixup> &Fixups,
76                                 const MCSubtargetInfo &STI) const;
77   uint64_t getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum,
78                                 SmallVectorImpl<MCFixup> &Fixups,
79                                 const MCSubtargetInfo &STI) const;
80   uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
81                                     SmallVectorImpl<MCFixup> &Fixups,
82                                     const MCSubtargetInfo &STI) const;
83   uint64_t getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
84                                 SmallVectorImpl<MCFixup> &Fixups,
85                                 const MCSubtargetInfo &STI) const;
86   uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
87                                 SmallVectorImpl<MCFixup> &Fixups,
88                                 const MCSubtargetInfo &STI) const;
89 
90   // Operand OpNum of MI needs a PC-relative fixup of kind Kind at
91   // Offset bytes from the start of MI.  Add the fixup to Fixups
92   // and return the in-place addend, which since we're a RELA target
93   // is always 0.  If AllowTLS is true and optional operand OpNum + 1
94   // is present, also emit a TLS call fixup for it.
95   uint64_t getPCRelEncoding(const MCInst &MI, unsigned OpNum,
96                             SmallVectorImpl<MCFixup> &Fixups,
97                             unsigned Kind, int64_t Offset,
98                             bool AllowTLS) const;
99 
100   uint64_t getPC16DBLEncoding(const MCInst &MI, unsigned OpNum,
101                               SmallVectorImpl<MCFixup> &Fixups,
102                               const MCSubtargetInfo &STI) const {
103     return getPCRelEncoding(MI, OpNum, Fixups,
104                             SystemZ::FK_390_PC16DBL, 2, false);
105   }
106   uint64_t getPC32DBLEncoding(const MCInst &MI, unsigned OpNum,
107                               SmallVectorImpl<MCFixup> &Fixups,
108                               const MCSubtargetInfo &STI) const {
109     return getPCRelEncoding(MI, OpNum, Fixups,
110                             SystemZ::FK_390_PC32DBL, 2, false);
111   }
112   uint64_t getPC16DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
113                                  SmallVectorImpl<MCFixup> &Fixups,
114                                  const MCSubtargetInfo &STI) const {
115     return getPCRelEncoding(MI, OpNum, Fixups,
116                             SystemZ::FK_390_PC16DBL, 2, true);
117   }
118   uint64_t getPC32DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
119                                  SmallVectorImpl<MCFixup> &Fixups,
120                                  const MCSubtargetInfo &STI) const {
121     return getPCRelEncoding(MI, OpNum, Fixups,
122                             SystemZ::FK_390_PC32DBL, 2, true);
123   }
124   uint64_t getPC12DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
125                                  SmallVectorImpl<MCFixup> &Fixups,
126                                  const MCSubtargetInfo &STI) const {
127     return getPCRelEncoding(MI, OpNum, Fixups,
128                             SystemZ::FK_390_PC12DBL, 1, false);
129   }
130   uint64_t getPC16DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
131                                  SmallVectorImpl<MCFixup> &Fixups,
132                                  const MCSubtargetInfo &STI) const {
133     return getPCRelEncoding(MI, OpNum, Fixups,
134                             SystemZ::FK_390_PC16DBL, 4, false);
135   }
136   uint64_t getPC24DBLBPPEncoding(const MCInst &MI, unsigned OpNum,
137                                  SmallVectorImpl<MCFixup> &Fixups,
138                                  const MCSubtargetInfo &STI) const {
139     return getPCRelEncoding(MI, OpNum, Fixups,
140                             SystemZ::FK_390_PC24DBL, 3, false);
141   }
142 
143 private:
144   uint64_t computeAvailableFeatures(const FeatureBitset &FB) const;
145   void verifyInstructionPredicates(const MCInst &MI,
146                                    uint64_t AvailableFeatures) const;
147 };
148 
149 } // end anonymous namespace
150 
151 void SystemZMCCodeEmitter::
152 encodeInstruction(const MCInst &MI, raw_ostream &OS,
153                   SmallVectorImpl<MCFixup> &Fixups,
154                   const MCSubtargetInfo &STI) const {
155   verifyInstructionPredicates(MI,
156                               computeAvailableFeatures(STI.getFeatureBits()));
157 
158   uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
159   unsigned Size = MCII.get(MI.getOpcode()).getSize();
160   // Big-endian insertion of Size bytes.
161   unsigned ShiftValue = (Size * 8) - 8;
162   for (unsigned I = 0; I != Size; ++I) {
163     OS << uint8_t(Bits >> ShiftValue);
164     ShiftValue -= 8;
165   }
166 }
167 
168 uint64_t SystemZMCCodeEmitter::
169 getMachineOpValue(const MCInst &MI, const MCOperand &MO,
170                   SmallVectorImpl<MCFixup> &Fixups,
171                   const MCSubtargetInfo &STI) const {
172   if (MO.isReg())
173     return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
174   if (MO.isImm())
175     return static_cast<uint64_t>(MO.getImm());
176   llvm_unreachable("Unexpected operand type!");
177 }
178 
179 uint64_t SystemZMCCodeEmitter::
180 getBDAddr12Encoding(const MCInst &MI, unsigned OpNum,
181                     SmallVectorImpl<MCFixup> &Fixups,
182                     const MCSubtargetInfo &STI) const {
183   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
184   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
185   assert(isUInt<4>(Base) && isUInt<12>(Disp));
186   return (Base << 12) | Disp;
187 }
188 
189 uint64_t SystemZMCCodeEmitter::
190 getBDAddr20Encoding(const MCInst &MI, unsigned OpNum,
191                     SmallVectorImpl<MCFixup> &Fixups,
192                     const MCSubtargetInfo &STI) const {
193   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
194   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
195   assert(isUInt<4>(Base) && isInt<20>(Disp));
196   return (Base << 20) | ((Disp & 0xfff) << 8) | ((Disp & 0xff000) >> 12);
197 }
198 
199 uint64_t SystemZMCCodeEmitter::
200 getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum,
201                      SmallVectorImpl<MCFixup> &Fixups,
202                      const MCSubtargetInfo &STI) const {
203   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
204   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
205   uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
206   assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Index));
207   return (Index << 16) | (Base << 12) | Disp;
208 }
209 
210 uint64_t SystemZMCCodeEmitter::
211 getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum,
212                      SmallVectorImpl<MCFixup> &Fixups,
213                      const MCSubtargetInfo &STI) const {
214   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
215   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
216   uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
217   assert(isUInt<4>(Base) && isInt<20>(Disp) && isUInt<4>(Index));
218   return (Index << 24) | (Base << 20) | ((Disp & 0xfff) << 8)
219     | ((Disp & 0xff000) >> 12);
220 }
221 
222 uint64_t SystemZMCCodeEmitter::
223 getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
224                          SmallVectorImpl<MCFixup> &Fixups,
225                          const MCSubtargetInfo &STI) const {
226   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
227   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
228   uint64_t Len  = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI) - 1;
229   assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<8>(Len));
230   return (Len << 16) | (Base << 12) | Disp;
231 }
232 
233 uint64_t SystemZMCCodeEmitter::
234 getBDRAddr12Encoding(const MCInst &MI, unsigned OpNum,
235                      SmallVectorImpl<MCFixup> &Fixups,
236                      const MCSubtargetInfo &STI) const {
237   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
238   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
239   uint64_t Len  = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
240   assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Len));
241   return (Len << 16) | (Base << 12) | Disp;
242 }
243 
244 uint64_t SystemZMCCodeEmitter::
245 getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
246                      SmallVectorImpl<MCFixup> &Fixups,
247                      const MCSubtargetInfo &STI) const {
248   uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
249   uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
250   uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
251   assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<5>(Index));
252   return (Index << 16) | (Base << 12) | Disp;
253 }
254 
255 uint64_t
256 SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
257                                        SmallVectorImpl<MCFixup> &Fixups,
258                                        unsigned Kind, int64_t Offset,
259                                        bool AllowTLS) const {
260   const MCOperand &MO = MI.getOperand(OpNum);
261   const MCExpr *Expr;
262   if (MO.isImm())
263     Expr = MCConstantExpr::create(MO.getImm() + Offset, Ctx);
264   else {
265     Expr = MO.getExpr();
266     if (Offset) {
267       // The operand value is relative to the start of MI, but the fixup
268       // is relative to the operand field itself, which is Offset bytes
269       // into MI.  Add Offset to the relocation value to cancel out
270       // this difference.
271       const MCExpr *OffsetExpr = MCConstantExpr::create(Offset, Ctx);
272       Expr = MCBinaryExpr::createAdd(Expr, OffsetExpr, Ctx);
273     }
274   }
275   Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind));
276 
277   // Output the fixup for the TLS marker if present.
278   if (AllowTLS && OpNum + 1 < MI.getNumOperands()) {
279     const MCOperand &MOTLS = MI.getOperand(OpNum + 1);
280     Fixups.push_back(MCFixup::create(0, MOTLS.getExpr(),
281                                      (MCFixupKind)SystemZ::FK_390_TLS_CALL));
282   }
283   return 0;
284 }
285 
286 #define ENABLE_INSTR_PREDICATE_VERIFIER
287 #include "SystemZGenMCCodeEmitter.inc"
288 
289 MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
290                                                 const MCRegisterInfo &MRI,
291                                                 MCContext &Ctx) {
292   return new SystemZMCCodeEmitter(MCII, Ctx);
293 }
294