xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===-- SparcMCCodeEmitter.cpp - Convert Sparc 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 SparcMCCodeEmitter class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "MCTargetDesc/SparcFixupKinds.h"
14 #include "SparcMCTargetDesc.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/Statistic.h"
17 #include "llvm/BinaryFormat/ELF.h"
18 #include "llvm/MC/MCAsmInfo.h"
19 #include "llvm/MC/MCCodeEmitter.h"
20 #include "llvm/MC/MCContext.h"
21 #include "llvm/MC/MCExpr.h"
22 #include "llvm/MC/MCFixup.h"
23 #include "llvm/MC/MCInst.h"
24 #include "llvm/MC/MCInstrInfo.h"
25 #include "llvm/MC/MCObjectFileInfo.h"
26 #include "llvm/MC/MCRegisterInfo.h"
27 #include "llvm/MC/MCSubtargetInfo.h"
28 #include "llvm/MC/MCSymbol.h"
29 #include "llvm/Support/Casting.h"
30 #include "llvm/Support/EndianStream.h"
31 #include "llvm/Support/ErrorHandling.h"
32 #include <cassert>
33 #include <cstdint>
34 
35 using namespace llvm;
36 
37 #define DEBUG_TYPE "mccodeemitter"
38 
39 STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
40 
41 namespace {
42 
43 class SparcMCCodeEmitter : public MCCodeEmitter {
44   MCContext &Ctx;
45 
46 public:
SparcMCCodeEmitter(const MCInstrInfo &,MCContext & ctx)47   SparcMCCodeEmitter(const MCInstrInfo &, MCContext &ctx)
48       : Ctx(ctx) {}
49   SparcMCCodeEmitter(const SparcMCCodeEmitter &) = delete;
50   SparcMCCodeEmitter &operator=(const SparcMCCodeEmitter &) = delete;
51   ~SparcMCCodeEmitter() override = default;
52 
53   void encodeInstruction(const MCInst &MI, SmallVectorImpl<char> &CB,
54                          SmallVectorImpl<MCFixup> &Fixups,
55                          const MCSubtargetInfo &STI) const override;
56 
57   // getBinaryCodeForInstr - TableGen'erated function for getting the
58   // binary encoding for an instruction.
59   uint64_t getBinaryCodeForInstr(const MCInst &MI,
60                                  SmallVectorImpl<MCFixup> &Fixups,
61                                  const MCSubtargetInfo &STI) const;
62 
63   /// getMachineOpValue - Return binary encoding of operand. If the machine
64   /// operand requires relocation, record the relocation and return zero.
65   unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
66                              SmallVectorImpl<MCFixup> &Fixups,
67                              const MCSubtargetInfo &STI) const;
68   unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
69                              SmallVectorImpl<MCFixup> &Fixups,
70                              const MCSubtargetInfo &STI) const;
71   unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
72                              SmallVectorImpl<MCFixup> &Fixups,
73                              const MCSubtargetInfo &STI) const;
74   unsigned getSImm5OpValue(const MCInst &MI, unsigned OpNo,
75                            SmallVectorImpl<MCFixup> &Fixups,
76                            const MCSubtargetInfo &STI) const;
77   unsigned getSImm13OpValue(const MCInst &MI, unsigned OpNo,
78                             SmallVectorImpl<MCFixup> &Fixups,
79                             const MCSubtargetInfo &STI) const;
80   unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,
81                                       SmallVectorImpl<MCFixup> &Fixups,
82                                       const MCSubtargetInfo &STI) const;
83   unsigned getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
84                                        SmallVectorImpl<MCFixup> &Fixups,
85                                        const MCSubtargetInfo &STI) const;
86   unsigned getCompareAndBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
87                                             SmallVectorImpl<MCFixup> &Fixups,
88                                             const MCSubtargetInfo &STI) const;
89 };
90 
91 } // end anonymous namespace
92 
addFixup(SmallVectorImpl<MCFixup> & Fixups,uint32_t Offset,const MCExpr * Value,uint16_t Kind)93 static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,
94                      const MCExpr *Value, uint16_t Kind) {
95   bool PCRel = false;
96   switch (Kind) {
97   case ELF::R_SPARC_PC10:
98   case ELF::R_SPARC_PC22:
99   case ELF::R_SPARC_WDISP10:
100   case ELF::R_SPARC_WDISP16:
101   case ELF::R_SPARC_WDISP19:
102   case ELF::R_SPARC_WDISP22:
103   case Sparc::fixup_sparc_call30:
104     PCRel = true;
105   }
106   Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));
107 }
108 
encodeInstruction(const MCInst & MI,SmallVectorImpl<char> & CB,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const109 void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI,
110                                            SmallVectorImpl<char> &CB,
111                                            SmallVectorImpl<MCFixup> &Fixups,
112                                            const MCSubtargetInfo &STI) const {
113   unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI);
114   support::endian::write(CB, Bits,
115                          Ctx.getAsmInfo()->isLittleEndian()
116                              ? llvm::endianness::little
117                              : llvm::endianness::big);
118 
119   // Some instructions have phantom operands that only contribute a fixup entry.
120   unsigned SymOpNo = 0;
121   switch (MI.getOpcode()) {
122   default: break;
123   case SP::TLS_CALL:   SymOpNo = 1; break;
124   case SP::GDOP_LDrr:
125   case SP::GDOP_LDXrr:
126   case SP::TLS_ADDrr:
127   case SP::TLS_LDrr:
128   case SP::TLS_LDXrr:  SymOpNo = 3; break;
129   }
130   if (SymOpNo != 0) {
131     const MCOperand &MO = MI.getOperand(SymOpNo);
132     uint64_t op = getMachineOpValue(MI, MO, Fixups, STI);
133     assert(op == 0 && "Unexpected operand value!");
134     (void)op; // suppress warning.
135   }
136 
137   ++MCNumEmitted;  // Keep track of the # of mi's emitted.
138 }
139 
140 unsigned SparcMCCodeEmitter::
getMachineOpValue(const MCInst & MI,const MCOperand & MO,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const141 getMachineOpValue(const MCInst &MI, const MCOperand &MO,
142                   SmallVectorImpl<MCFixup> &Fixups,
143                   const MCSubtargetInfo &STI) const {
144   if (MO.isReg())
145     return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
146 
147   if (MO.isImm())
148     return MO.getImm();
149 
150   assert(MO.isExpr());
151   const MCExpr *Expr = MO.getExpr();
152   if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {
153     addFixup(Fixups, 0, Expr, SExpr->getSpecifier());
154     return 0;
155   }
156 
157   int64_t Res;
158   if (Expr->evaluateAsAbsolute(Res))
159     return Res;
160 
161   llvm_unreachable("Unhandled expression!");
162   return 0;
163 }
164 
getSImm5OpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const165 unsigned SparcMCCodeEmitter::getSImm5OpValue(const MCInst &MI, unsigned OpNo,
166                                              SmallVectorImpl<MCFixup> &Fixups,
167                                              const MCSubtargetInfo &STI) const {
168   const MCOperand &MO = MI.getOperand(OpNo);
169 
170   if (MO.isImm())
171     return MO.getImm();
172 
173   assert(MO.isExpr() &&
174          "getSImm5OpValue expects only expressions or an immediate");
175 
176   const MCExpr *Expr = MO.getExpr();
177 
178   // Constant value, no fixup is needed
179   if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
180     return CE->getValue();
181 
182   if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {
183     addFixup(Fixups, 0, Expr, SExpr->getSpecifier());
184     return 0;
185   }
186   addFixup(Fixups, 0, Expr, ELF::R_SPARC_5);
187   return 0;
188 }
189 
190 unsigned
getSImm13OpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const191 SparcMCCodeEmitter::getSImm13OpValue(const MCInst &MI, unsigned OpNo,
192                                      SmallVectorImpl<MCFixup> &Fixups,
193                                      const MCSubtargetInfo &STI) const {
194   const MCOperand &MO = MI.getOperand(OpNo);
195 
196   if (MO.isImm())
197     return MO.getImm();
198 
199   assert(MO.isExpr() &&
200          "getSImm13OpValue expects only expressions or an immediate");
201 
202   const MCExpr *Expr = MO.getExpr();
203 
204   // Constant value, no fixup is needed
205   if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
206     return CE->getValue();
207 
208   if (auto *SExpr = dyn_cast<MCSpecifierExpr>(Expr)) {
209     addFixup(Fixups, 0, Expr, SExpr->getSpecifier());
210     return 0;
211   }
212   addFixup(Fixups, 0, Expr, Sparc::fixup_sparc_13);
213   return 0;
214 }
215 
216 unsigned SparcMCCodeEmitter::
getCallTargetOpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const217 getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
218                      SmallVectorImpl<MCFixup> &Fixups,
219                      const MCSubtargetInfo &STI) const {
220   if (MI.getOpcode() == SP::TLS_CALL) {
221     // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in
222     // encodeInstruction.
223     return 0;
224   }
225 
226   const MCOperand &MO = MI.getOperand(OpNo);
227   addFixup(Fixups, 0, MO.getExpr(), Sparc::fixup_sparc_call30);
228   return 0;
229 }
230 
231 unsigned SparcMCCodeEmitter::
getBranchTargetOpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const232 getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
233                   SmallVectorImpl<MCFixup> &Fixups,
234                   const MCSubtargetInfo &STI) const {
235   const MCOperand &MO = MI.getOperand(OpNo);
236   if (MO.isReg() || MO.isImm())
237     return getMachineOpValue(MI, MO, Fixups, STI);
238 
239   addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP22);
240   return 0;
241 }
242 
getBranchPredTargetOpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const243 unsigned SparcMCCodeEmitter::getBranchPredTargetOpValue(
244     const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
245     const MCSubtargetInfo &STI) const {
246   const MCOperand &MO = MI.getOperand(OpNo);
247   if (MO.isReg() || MO.isImm())
248     return getMachineOpValue(MI, MO, Fixups, STI);
249 
250   addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP19);
251   return 0;
252 }
253 
getBranchOnRegTargetOpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const254 unsigned SparcMCCodeEmitter::getBranchOnRegTargetOpValue(
255     const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
256     const MCSubtargetInfo &STI) const {
257   const MCOperand &MO = MI.getOperand(OpNo);
258   if (MO.isReg() || MO.isImm())
259     return getMachineOpValue(MI, MO, Fixups, STI);
260 
261   addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP16);
262   return 0;
263 }
264 
getCompareAndBranchTargetOpValue(const MCInst & MI,unsigned OpNo,SmallVectorImpl<MCFixup> & Fixups,const MCSubtargetInfo & STI) const265 unsigned SparcMCCodeEmitter::getCompareAndBranchTargetOpValue(
266     const MCInst &MI, unsigned OpNo, SmallVectorImpl<MCFixup> &Fixups,
267     const MCSubtargetInfo &STI) const {
268   const MCOperand &MO = MI.getOperand(OpNo);
269   if (MO.isImm())
270     return getMachineOpValue(MI, MO, Fixups, STI);
271 
272   addFixup(Fixups, 0, MO.getExpr(), ELF::R_SPARC_WDISP10);
273   return 0;
274 }
275 
276 #include "SparcGenMCCodeEmitter.inc"
277 
createSparcMCCodeEmitter(const MCInstrInfo & MCII,MCContext & Ctx)278 MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,
279                                               MCContext &Ctx) {
280   return new SparcMCCodeEmitter(MCII, Ctx);
281 }
282