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/SystemZMCTargetDesc.h"
15#include "MCTargetDesc/SystemZMCFixups.h"
16#include "llvm/MC/MCCodeEmitter.h"
17#include "llvm/MC/MCContext.h"
18#include "llvm/MC/MCExpr.h"
19#include "llvm/MC/MCInst.h"
20#include "llvm/MC/MCInstrInfo.h"
21#include "llvm/MC/MCRegisterInfo.h"
22
23using namespace llvm;
24
25#define DEBUG_TYPE "mccodeemitter"
26
27namespace {
28class SystemZMCCodeEmitter : public MCCodeEmitter {
29  const MCInstrInfo &MCII;
30  MCContext &Ctx;
31
32public:
33  SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
34    : MCII(mcii), Ctx(ctx) {
35  }
36
37  ~SystemZMCCodeEmitter() override {}
38
39  // OVerride MCCodeEmitter.
40  void encodeInstruction(const MCInst &MI, raw_ostream &OS,
41                         SmallVectorImpl<MCFixup> &Fixups,
42                         const MCSubtargetInfo &STI) const override;
43
44private:
45  // Automatically generated by TableGen.
46  uint64_t getBinaryCodeForInstr(const MCInst &MI,
47                                 SmallVectorImpl<MCFixup> &Fixups,
48                                 const MCSubtargetInfo &STI) const;
49
50  // Called by the TableGen code to get the binary encoding of operand
51  // MO in MI.  Fixups is the list of fixups against MI.
52  uint64_t getMachineOpValue(const MCInst &MI, const MCOperand &MO,
53                             SmallVectorImpl<MCFixup> &Fixups,
54                             const MCSubtargetInfo &STI) const;
55
56  // Called by the TableGen code to get the binary encoding of an address.
57  // The index or length, if any, is encoded first, followed by the base,
58  // followed by the displacement.  In a 20-bit displacement,
59  // the low 12 bits are encoded before the high 8 bits.
60  uint64_t getBDAddr12Encoding(const MCInst &MI, unsigned OpNum,
61                               SmallVectorImpl<MCFixup> &Fixups,
62                               const MCSubtargetInfo &STI) const;
63  uint64_t getBDAddr20Encoding(const MCInst &MI, unsigned OpNum,
64                               SmallVectorImpl<MCFixup> &Fixups,
65                               const MCSubtargetInfo &STI) const;
66  uint64_t getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum,
67                                SmallVectorImpl<MCFixup> &Fixups,
68                                const MCSubtargetInfo &STI) const;
69  uint64_t getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum,
70                                SmallVectorImpl<MCFixup> &Fixups,
71                                const MCSubtargetInfo &STI) const;
72  uint64_t getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
73                                    SmallVectorImpl<MCFixup> &Fixups,
74                                    const MCSubtargetInfo &STI) const;
75  uint64_t getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
76                                SmallVectorImpl<MCFixup> &Fixups,
77                                const MCSubtargetInfo &STI) const;
78
79  // Operand OpNum of MI needs a PC-relative fixup of kind Kind at
80  // Offset bytes from the start of MI.  Add the fixup to Fixups
81  // and return the in-place addend, which since we're a RELA target
82  // is always 0.  If AllowTLS is true and optional operand OpNum + 1
83  // is present, also emit a TLS call fixup for it.
84  uint64_t getPCRelEncoding(const MCInst &MI, unsigned OpNum,
85                            SmallVectorImpl<MCFixup> &Fixups,
86                            unsigned Kind, int64_t Offset,
87                            bool AllowTLS) const;
88
89  uint64_t getPC16DBLEncoding(const MCInst &MI, unsigned OpNum,
90                              SmallVectorImpl<MCFixup> &Fixups,
91                              const MCSubtargetInfo &STI) const {
92    return getPCRelEncoding(MI, OpNum, Fixups,
93                            SystemZ::FK_390_PC16DBL, 2, false);
94  }
95  uint64_t getPC32DBLEncoding(const MCInst &MI, unsigned OpNum,
96                              SmallVectorImpl<MCFixup> &Fixups,
97                              const MCSubtargetInfo &STI) const {
98    return getPCRelEncoding(MI, OpNum, Fixups,
99                            SystemZ::FK_390_PC32DBL, 2, false);
100  }
101  uint64_t getPC16DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
102                                 SmallVectorImpl<MCFixup> &Fixups,
103                                 const MCSubtargetInfo &STI) const {
104    return getPCRelEncoding(MI, OpNum, Fixups,
105                            SystemZ::FK_390_PC16DBL, 2, true);
106  }
107  uint64_t getPC32DBLTLSEncoding(const MCInst &MI, unsigned OpNum,
108                                 SmallVectorImpl<MCFixup> &Fixups,
109                                 const MCSubtargetInfo &STI) const {
110    return getPCRelEncoding(MI, OpNum, Fixups,
111                            SystemZ::FK_390_PC32DBL, 2, true);
112  }
113};
114} // end anonymous namespace
115
116MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
117                                                const MCRegisterInfo &MRI,
118                                                MCContext &Ctx) {
119  return new SystemZMCCodeEmitter(MCII, Ctx);
120}
121
122void SystemZMCCodeEmitter::
123encodeInstruction(const MCInst &MI, raw_ostream &OS,
124                  SmallVectorImpl<MCFixup> &Fixups,
125                  const MCSubtargetInfo &STI) const {
126  uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);
127  unsigned Size = MCII.get(MI.getOpcode()).getSize();
128  // Big-endian insertion of Size bytes.
129  unsigned ShiftValue = (Size * 8) - 8;
130  for (unsigned I = 0; I != Size; ++I) {
131    OS << uint8_t(Bits >> ShiftValue);
132    ShiftValue -= 8;
133  }
134}
135
136uint64_t SystemZMCCodeEmitter::
137getMachineOpValue(const MCInst &MI, const MCOperand &MO,
138                  SmallVectorImpl<MCFixup> &Fixups,
139                  const MCSubtargetInfo &STI) const {
140  if (MO.isReg())
141    return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
142  if (MO.isImm())
143    return static_cast<uint64_t>(MO.getImm());
144  llvm_unreachable("Unexpected operand type!");
145}
146
147uint64_t SystemZMCCodeEmitter::
148getBDAddr12Encoding(const MCInst &MI, unsigned OpNum,
149                    SmallVectorImpl<MCFixup> &Fixups,
150                    const MCSubtargetInfo &STI) const {
151  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
152  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
153  assert(isUInt<4>(Base) && isUInt<12>(Disp));
154  return (Base << 12) | Disp;
155}
156
157uint64_t SystemZMCCodeEmitter::
158getBDAddr20Encoding(const MCInst &MI, unsigned OpNum,
159                    SmallVectorImpl<MCFixup> &Fixups,
160                    const MCSubtargetInfo &STI) const {
161  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
162  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
163  assert(isUInt<4>(Base) && isInt<20>(Disp));
164  return (Base << 20) | ((Disp & 0xfff) << 8) | ((Disp & 0xff000) >> 12);
165}
166
167uint64_t SystemZMCCodeEmitter::
168getBDXAddr12Encoding(const MCInst &MI, unsigned OpNum,
169                     SmallVectorImpl<MCFixup> &Fixups,
170                     const MCSubtargetInfo &STI) const {
171  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
172  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
173  uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
174  assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<4>(Index));
175  return (Index << 16) | (Base << 12) | Disp;
176}
177
178uint64_t SystemZMCCodeEmitter::
179getBDXAddr20Encoding(const MCInst &MI, unsigned OpNum,
180                     SmallVectorImpl<MCFixup> &Fixups,
181                     const MCSubtargetInfo &STI) const {
182  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
183  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
184  uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
185  assert(isUInt<4>(Base) && isInt<20>(Disp) && isUInt<4>(Index));
186  return (Index << 24) | (Base << 20) | ((Disp & 0xfff) << 8)
187    | ((Disp & 0xff000) >> 12);
188}
189
190uint64_t SystemZMCCodeEmitter::
191getBDLAddr12Len8Encoding(const MCInst &MI, unsigned OpNum,
192                         SmallVectorImpl<MCFixup> &Fixups,
193                         const MCSubtargetInfo &STI) const {
194  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
195  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
196  uint64_t Len  = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI) - 1;
197  assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<8>(Len));
198  return (Len << 16) | (Base << 12) | Disp;
199}
200
201uint64_t SystemZMCCodeEmitter::
202getBDVAddr12Encoding(const MCInst &MI, unsigned OpNum,
203                     SmallVectorImpl<MCFixup> &Fixups,
204                     const MCSubtargetInfo &STI) const {
205  uint64_t Base = getMachineOpValue(MI, MI.getOperand(OpNum), Fixups, STI);
206  uint64_t Disp = getMachineOpValue(MI, MI.getOperand(OpNum + 1), Fixups, STI);
207  uint64_t Index = getMachineOpValue(MI, MI.getOperand(OpNum + 2), Fixups, STI);
208  assert(isUInt<4>(Base) && isUInt<12>(Disp) && isUInt<5>(Index));
209  return (Index << 16) | (Base << 12) | Disp;
210}
211
212uint64_t
213SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned OpNum,
214                                       SmallVectorImpl<MCFixup> &Fixups,
215                                       unsigned Kind, int64_t Offset,
216                                       bool AllowTLS) const {
217  const MCOperand &MO = MI.getOperand(OpNum);
218  const MCExpr *Expr;
219  if (MO.isImm())
220    Expr = MCConstantExpr::create(MO.getImm() + Offset, Ctx);
221  else {
222    Expr = MO.getExpr();
223    if (Offset) {
224      // The operand value is relative to the start of MI, but the fixup
225      // is relative to the operand field itself, which is Offset bytes
226      // into MI.  Add Offset to the relocation value to cancel out
227      // this difference.
228      const MCExpr *OffsetExpr = MCConstantExpr::create(Offset, Ctx);
229      Expr = MCBinaryExpr::createAdd(Expr, OffsetExpr, Ctx);
230    }
231  }
232  Fixups.push_back(MCFixup::create(Offset, Expr, (MCFixupKind)Kind));
233
234  // Output the fixup for the TLS marker if present.
235  if (AllowTLS && OpNum + 1 < MI.getNumOperands()) {
236    const MCOperand &MOTLS = MI.getOperand(OpNum + 1);
237    Fixups.push_back(MCFixup::create(0, MOTLS.getExpr(),
238                                     (MCFixupKind)SystemZ::FK_390_TLS_CALL));
239  }
240  return 0;
241}
242
243#include "SystemZGenMCCodeEmitter.inc"
244