SystemZMCCodeEmitter.cpp revision 251662
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#define DEBUG_TYPE "mccodeemitter"
15#include "MCTargetDesc/SystemZMCTargetDesc.h"
16#include "MCTargetDesc/SystemZMCFixups.h"
17#include "llvm/MC/MCCodeEmitter.h"
18#include "llvm/MC/MCContext.h"
19#include "llvm/MC/MCExpr.h"
20#include "llvm/MC/MCInstrInfo.h"
21
22using namespace llvm;
23
24namespace {
25class SystemZMCCodeEmitter : public MCCodeEmitter {
26  const MCInstrInfo &MCII;
27  MCContext &Ctx;
28
29public:
30  SystemZMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
31    : MCII(mcii), Ctx(ctx) {
32  }
33
34  ~SystemZMCCodeEmitter() {}
35
36  // OVerride MCCodeEmitter.
37  virtual void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
38                                 SmallVectorImpl<MCFixup> &Fixups) const
39    LLVM_OVERRIDE;
40
41private:
42  // Automatically generated by TableGen.
43  uint64_t getBinaryCodeForInstr(const MCInst &MI,
44                                 SmallVectorImpl<MCFixup> &Fixups) const;
45
46  // Called by the TableGen code to get the binary encoding of operand
47  // MO in MI.  Fixups is the list of fixups against MI.
48  unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
49                             SmallVectorImpl<MCFixup> &Fixups) const;
50
51  // Operand OpNum of MI needs a PC-relative fixup of kind Kind at
52  // Offset bytes from the start of MI.  Add the fixup to Fixups
53  // and return the in-place addend, which since we're a RELA target
54  // is always 0.
55  unsigned getPCRelEncoding(const MCInst &MI, unsigned int OpNum,
56                            SmallVectorImpl<MCFixup> &Fixups,
57                            unsigned Kind, int64_t Offset) const;
58
59  unsigned getPC16DBLEncoding(const MCInst &MI, unsigned int OpNum,
60                              SmallVectorImpl<MCFixup> &Fixups) const {
61    return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC16DBL, 2);
62  }
63  unsigned getPC32DBLEncoding(const MCInst &MI, unsigned int OpNum,
64                              SmallVectorImpl<MCFixup> &Fixups) const {
65    return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PC32DBL, 2);
66  }
67  unsigned getPLT16DBLEncoding(const MCInst &MI, unsigned int OpNum,
68                               SmallVectorImpl<MCFixup> &Fixups) const {
69    return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PLT16DBL, 2);
70  }
71  unsigned getPLT32DBLEncoding(const MCInst &MI, unsigned int OpNum,
72                               SmallVectorImpl<MCFixup> &Fixups) const {
73    return getPCRelEncoding(MI, OpNum, Fixups, SystemZ::FK_390_PLT32DBL, 2);
74  }
75};
76}
77
78MCCodeEmitter *llvm::createSystemZMCCodeEmitter(const MCInstrInfo &MCII,
79                                                const MCRegisterInfo &MRI,
80                                                const MCSubtargetInfo &MCSTI,
81                                                MCContext &Ctx) {
82  return new SystemZMCCodeEmitter(MCII, Ctx);
83}
84
85void SystemZMCCodeEmitter::
86EncodeInstruction(const MCInst &MI, raw_ostream &OS,
87                  SmallVectorImpl<MCFixup> &Fixups) const {
88  uint64_t Bits = getBinaryCodeForInstr(MI, Fixups);
89  unsigned Size = MCII.get(MI.getOpcode()).getSize();
90  // Big-endian insertion of Size bytes.
91  unsigned ShiftValue = (Size * 8) - 8;
92  for (unsigned I = 0; I != Size; ++I) {
93    OS << uint8_t(Bits >> ShiftValue);
94    ShiftValue -= 8;
95  }
96}
97
98unsigned SystemZMCCodeEmitter::
99getMachineOpValue(const MCInst &MI, const MCOperand &MO,
100                  SmallVectorImpl<MCFixup> &Fixups) const {
101  if (MO.isReg())
102    return Ctx.getRegisterInfo().getEncodingValue(MO.getReg());
103  if (MO.isImm())
104    return static_cast<unsigned>(MO.getImm());
105  llvm_unreachable("Unexpected operand type!");
106}
107
108unsigned
109SystemZMCCodeEmitter::getPCRelEncoding(const MCInst &MI, unsigned int OpNum,
110                                       SmallVectorImpl<MCFixup> &Fixups,
111                                       unsigned Kind, int64_t Offset) const {
112  const MCOperand &MO = MI.getOperand(OpNum);
113  // For compatibility with the GNU assembler, treat constant operands as
114  // unadjusted PC-relative offsets.
115  if (MO.isImm())
116    return MO.getImm() / 2;
117
118  const MCExpr *Expr = MO.getExpr();
119  if (Offset) {
120    // The operand value is relative to the start of MI, but the fixup
121    // is relative to the operand field itself, which is Offset bytes
122    // into MI.  Add Offset to the relocation value to cancel out
123    // this difference.
124    const MCExpr *OffsetExpr = MCConstantExpr::Create(Offset, Ctx);
125    Expr = MCBinaryExpr::CreateAdd(Expr, OffsetExpr, Ctx);
126  }
127  Fixups.push_back(MCFixup::Create(Offset, Expr, (MCFixupKind)Kind));
128  return 0;
129}
130
131#include "SystemZGenMCCodeEmitter.inc"
132