1 //===-- SystemZMCCodeEmitter.cpp - Convert SystemZ code to machine code ---===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements the SystemZMCCodeEmitter class.
11 //===----------------------------------------------------------------------===//
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 "llvm/Support/ErrorHandling.h"
30 #define DEBUG_TYPE "mccodeemitter"
34 class SystemZMCCodeEmitter
: public MCCodeEmitter
{
35 const MCInstrInfo
&MCII
;
39 SystemZMCCodeEmitter(const MCInstrInfo
&MCII
, MCContext
&Ctx
)
40 : MCII(MCII
), Ctx(Ctx
) {}
42 ~SystemZMCCodeEmitter() override
= default;
44 // OVerride MCCodeEmitter.
45 void encodeInstruction(const MCInst
&MI
, SmallVectorImpl
<char> &CB
,
46 SmallVectorImpl
<MCFixup
> &Fixups
,
47 const MCSubtargetInfo
&STI
) const override
;
50 // Automatically generated by TableGen.
51 uint64_t getBinaryCodeForInstr(const MCInst
&MI
,
52 SmallVectorImpl
<MCFixup
> &Fixups
,
53 const MCSubtargetInfo
&STI
) const;
54 uint32_t getOperandBitOffset(const MCInst
&MI
, unsigned OpNum
,
55 const MCSubtargetInfo
&STI
) const;
57 // Called by the TableGen code to get the binary encoding of operand
58 // MO in MI. Fixups is the list of fixups against MI.
59 uint64_t getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
60 SmallVectorImpl
<MCFixup
> &Fixups
,
61 const MCSubtargetInfo
&STI
) const;
63 // Return the encoded immediate value for the OpNum operand. If it is a
64 // symbol, add a fixup for it and return 0.
65 template <SystemZ::FixupKind Kind
>
66 uint64_t getImmOpValue(const MCInst
&MI
, unsigned OpNum
,
67 SmallVectorImpl
<MCFixup
> &Fixups
,
68 const MCSubtargetInfo
&STI
) const;
70 // Called by the TableGen code to get the binary encoding of a length value.
71 // Length values are encoded by subtracting 1 from the actual value.
72 template <SystemZ::FixupKind Kind
>
73 uint64_t getLenEncoding(const MCInst
&MI
, unsigned OpNum
,
74 SmallVectorImpl
<MCFixup
> &Fixups
,
75 const MCSubtargetInfo
&STI
) const;
77 // Operand OpNum of MI needs a PC-relative fixup of kind Kind at
78 // Offset bytes from the start of MI. Add the fixup to Fixups
79 // and return the in-place addend, which since we're a RELA target
80 // is always 0. If AllowTLS is true and optional operand OpNum + 1
81 // is present, also emit a TLS call fixup for it.
82 uint64_t getPCRelEncoding(const MCInst
&MI
, unsigned OpNum
,
83 SmallVectorImpl
<MCFixup
> &Fixups
,
84 unsigned Kind
, int64_t Offset
,
87 uint64_t getPC16DBLEncoding(const MCInst
&MI
, unsigned OpNum
,
88 SmallVectorImpl
<MCFixup
> &Fixups
,
89 const MCSubtargetInfo
&STI
) const {
90 return getPCRelEncoding(MI
, OpNum
, Fixups
,
91 SystemZ::FK_390_PC16DBL
, 2, false);
93 uint64_t getPC32DBLEncoding(const MCInst
&MI
, unsigned OpNum
,
94 SmallVectorImpl
<MCFixup
> &Fixups
,
95 const MCSubtargetInfo
&STI
) const {
96 return getPCRelEncoding(MI
, OpNum
, Fixups
,
97 SystemZ::FK_390_PC32DBL
, 2, false);
99 uint64_t getPC16DBLTLSEncoding(const MCInst
&MI
, unsigned OpNum
,
100 SmallVectorImpl
<MCFixup
> &Fixups
,
101 const MCSubtargetInfo
&STI
) const {
102 return getPCRelEncoding(MI
, OpNum
, Fixups
,
103 SystemZ::FK_390_PC16DBL
, 2, true);
105 uint64_t getPC32DBLTLSEncoding(const MCInst
&MI
, unsigned OpNum
,
106 SmallVectorImpl
<MCFixup
> &Fixups
,
107 const MCSubtargetInfo
&STI
) const {
108 return getPCRelEncoding(MI
, OpNum
, Fixups
,
109 SystemZ::FK_390_PC32DBL
, 2, true);
111 uint64_t getPC12DBLBPPEncoding(const MCInst
&MI
, unsigned OpNum
,
112 SmallVectorImpl
<MCFixup
> &Fixups
,
113 const MCSubtargetInfo
&STI
) const {
114 return getPCRelEncoding(MI
, OpNum
, Fixups
,
115 SystemZ::FK_390_PC12DBL
, 1, false);
117 uint64_t getPC16DBLBPPEncoding(const MCInst
&MI
, unsigned OpNum
,
118 SmallVectorImpl
<MCFixup
> &Fixups
,
119 const MCSubtargetInfo
&STI
) const {
120 return getPCRelEncoding(MI
, OpNum
, Fixups
,
121 SystemZ::FK_390_PC16DBL
, 4, false);
123 uint64_t getPC24DBLBPPEncoding(const MCInst
&MI
, unsigned OpNum
,
124 SmallVectorImpl
<MCFixup
> &Fixups
,
125 const MCSubtargetInfo
&STI
) const {
126 return getPCRelEncoding(MI
, OpNum
, Fixups
,
127 SystemZ::FK_390_PC24DBL
, 3, false);
131 } // end anonymous namespace
133 void SystemZMCCodeEmitter::encodeInstruction(const MCInst
&MI
,
134 SmallVectorImpl
<char> &CB
,
135 SmallVectorImpl
<MCFixup
> &Fixups
,
136 const MCSubtargetInfo
&STI
) const {
137 uint64_t Bits
= getBinaryCodeForInstr(MI
, Fixups
, STI
);
138 unsigned Size
= MCII
.get(MI
.getOpcode()).getSize();
139 // Big-endian insertion of Size bytes.
140 unsigned ShiftValue
= (Size
* 8) - 8;
141 for (unsigned I
= 0; I
!= Size
; ++I
) {
142 CB
.push_back(uint8_t(Bits
>> ShiftValue
));
147 uint64_t SystemZMCCodeEmitter::
148 getMachineOpValue(const MCInst
&MI
, const MCOperand
&MO
,
149 SmallVectorImpl
<MCFixup
> &Fixups
,
150 const MCSubtargetInfo
&STI
) const {
152 return Ctx
.getRegisterInfo()->getEncodingValue(MO
.getReg());
153 // SystemZAsmParser::parseAnyRegister() produces KindImm when registers are
154 // specified as integers.
156 return static_cast<uint64_t>(MO
.getImm());
157 llvm_unreachable("Unexpected operand type!");
160 template <SystemZ::FixupKind Kind
>
161 uint64_t SystemZMCCodeEmitter::getImmOpValue(const MCInst
&MI
, unsigned OpNum
,
162 SmallVectorImpl
<MCFixup
> &Fixups
,
163 const MCSubtargetInfo
&STI
) const {
164 const MCOperand
&MO
= MI
.getOperand(OpNum
);
166 return static_cast<uint64_t>(MO
.getImm());
168 unsigned MIBitSize
= MCII
.get(MI
.getOpcode()).getSize() * 8;
169 uint32_t RawBitOffset
= getOperandBitOffset(MI
, OpNum
, STI
);
171 SystemZ::MCFixupKindInfos
[Kind
- FirstTargetFixupKind
].TargetSize
;
172 uint32_t BitOffset
= MIBitSize
- RawBitOffset
- OpBitSize
;
173 Fixups
.push_back(MCFixup::create(BitOffset
>> 3, MO
.getExpr(),
174 (MCFixupKind
)Kind
, MI
.getLoc()));
177 llvm_unreachable("Unexpected operand type!");
180 template <SystemZ::FixupKind Kind
>
182 SystemZMCCodeEmitter::getLenEncoding(const MCInst
&MI
, unsigned OpNum
,
183 SmallVectorImpl
<MCFixup
> &Fixups
,
184 const MCSubtargetInfo
&STI
) const {
185 return getImmOpValue
<Kind
>(MI
, OpNum
, Fixups
, STI
) - 1;
189 SystemZMCCodeEmitter::getPCRelEncoding(const MCInst
&MI
, unsigned OpNum
,
190 SmallVectorImpl
<MCFixup
> &Fixups
,
191 unsigned Kind
, int64_t Offset
,
192 bool AllowTLS
) const {
193 SMLoc Loc
= MI
.getLoc();
194 const MCOperand
&MO
= MI
.getOperand(OpNum
);
197 Expr
= MCConstantExpr::create(MO
.getImm() + Offset
, Ctx
);
201 // The operand value is relative to the start of MI, but the fixup
202 // is relative to the operand field itself, which is Offset bytes
203 // into MI. Add Offset to the relocation value to cancel out
205 const MCExpr
*OffsetExpr
= MCConstantExpr::create(Offset
, Ctx
);
206 Expr
= MCBinaryExpr::createAdd(Expr
, OffsetExpr
, Ctx
);
209 Fixups
.push_back(MCFixup::create(Offset
, Expr
, (MCFixupKind
)Kind
, Loc
));
211 // Output the fixup for the TLS marker if present.
212 if (AllowTLS
&& OpNum
+ 1 < MI
.getNumOperands()) {
213 const MCOperand
&MOTLS
= MI
.getOperand(OpNum
+ 1);
214 Fixups
.push_back(MCFixup::create(
215 0, MOTLS
.getExpr(), (MCFixupKind
)SystemZ::FK_390_TLS_CALL
, Loc
));
220 #define GET_OPERAND_BIT_OFFSET
221 #include "SystemZGenMCCodeEmitter.inc"
223 MCCodeEmitter
*llvm::createSystemZMCCodeEmitter(const MCInstrInfo
&MCII
,
225 return new SystemZMCCodeEmitter(MCII
, Ctx
);