xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Mips/MipsMCInstLower.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1 //===- MipsMCInstLower.cpp - Convert Mips MachineInstr to MCInst ----------===//
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 contains code to lower Mips MachineInstrs to their corresponding
10 // MCInst records.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "MipsMCInstLower.h"
15 #include "MCTargetDesc/MipsBaseInfo.h"
16 #include "MCTargetDesc/MipsMCAsmInfo.h"
17 #include "MipsAsmPrinter.h"
18 #include "llvm/CodeGen/MachineBasicBlock.h"
19 #include "llvm/CodeGen/MachineInstr.h"
20 #include "llvm/CodeGen/MachineOperand.h"
21 #include "llvm/MC/MCContext.h"
22 #include "llvm/MC/MCExpr.h"
23 #include "llvm/MC/MCInst.h"
24 #include "llvm/Support/ErrorHandling.h"
25 
26 using namespace llvm;
27 
MipsMCInstLower(MipsAsmPrinter & asmprinter)28 MipsMCInstLower::MipsMCInstLower(MipsAsmPrinter &asmprinter)
29   : AsmPrinter(asmprinter) {}
30 
Initialize(MCContext * C)31 void MipsMCInstLower::Initialize(MCContext *C) {
32   Ctx = C;
33 }
34 
LowerSymbolOperand(const MachineOperand & MO,MachineOperandType MOTy,int64_t Offset) const35 MCOperand MipsMCInstLower::LowerSymbolOperand(const MachineOperand &MO,
36                                               MachineOperandType MOTy,
37                                               int64_t Offset) const {
38   Mips::Specifier TargetKind = Mips::S_None;
39   bool IsGpOff = false;
40   const MCSymbol *Symbol;
41   SmallString<128> Name;
42   unsigned TargetFlags = MO.getTargetFlags();
43 
44   if (TargetFlags & MipsII::MO_DLLIMPORT) {
45     // Handle dllimport linkage
46     Name += "__imp_";
47     TargetFlags &= ~MipsII::MO_DLLIMPORT;
48   }
49 
50   switch (TargetFlags) {
51   default:
52     llvm_unreachable("Invalid target flag!");
53   case MipsII::MO_NO_FLAG:
54     break;
55   case MipsII::MO_GPREL:
56     TargetKind = Mips::S_GPREL;
57     break;
58   case MipsII::MO_GOT_CALL:
59     TargetKind = Mips::S_GOT_CALL;
60     break;
61   case MipsII::MO_GOT:
62     TargetKind = Mips::S_GOT;
63     break;
64   case MipsII::MO_ABS_HI:
65     TargetKind = Mips::S_HI;
66     break;
67   case MipsII::MO_ABS_LO:
68     TargetKind = Mips::S_LO;
69     break;
70   case MipsII::MO_TLSGD:
71     TargetKind = Mips::S_TLSGD;
72     break;
73   case MipsII::MO_TLSLDM:
74     TargetKind = Mips::S_TLSLDM;
75     break;
76   case MipsII::MO_DTPREL_HI:
77     TargetKind = Mips::S_DTPREL_HI;
78     break;
79   case MipsII::MO_DTPREL_LO:
80     TargetKind = Mips::S_DTPREL_LO;
81     break;
82   case MipsII::MO_GOTTPREL:
83     TargetKind = Mips::S_GOTTPREL;
84     break;
85   case MipsII::MO_TPREL_HI:
86     TargetKind = Mips::S_TPREL_HI;
87     break;
88   case MipsII::MO_TPREL_LO:
89     TargetKind = Mips::S_TPREL_LO;
90     break;
91   case MipsII::MO_GPOFF_HI:
92     TargetKind = Mips::S_HI;
93     IsGpOff = true;
94     break;
95   case MipsII::MO_GPOFF_LO:
96     TargetKind = Mips::S_LO;
97     IsGpOff = true;
98     break;
99   case MipsII::MO_GOT_DISP:
100     TargetKind = Mips::S_GOT_DISP;
101     break;
102   case MipsII::MO_GOT_HI16:
103     TargetKind = Mips::S_GOT_HI16;
104     break;
105   case MipsII::MO_GOT_LO16:
106     TargetKind = Mips::S_GOT_LO16;
107     break;
108   case MipsII::MO_GOT_PAGE:
109     TargetKind = Mips::S_GOT_PAGE;
110     break;
111   case MipsII::MO_GOT_OFST:
112     TargetKind = Mips::S_GOT_OFST;
113     break;
114   case MipsII::MO_HIGHER:
115     TargetKind = Mips::S_HIGHER;
116     break;
117   case MipsII::MO_HIGHEST:
118     TargetKind = Mips::S_HIGHEST;
119     break;
120   case MipsII::MO_CALL_HI16:
121     TargetKind = Mips::S_CALL_HI16;
122     break;
123   case MipsII::MO_CALL_LO16:
124     TargetKind = Mips::S_CALL_LO16;
125     break;
126   case MipsII::MO_JALR:
127     return MCOperand();
128   }
129 
130   switch (MOTy) {
131   case MachineOperand::MO_MachineBasicBlock:
132     Symbol = MO.getMBB()->getSymbol();
133     break;
134 
135   case MachineOperand::MO_GlobalAddress:
136     AsmPrinter.getNameWithPrefix(Name, MO.getGlobal());
137     Symbol = Ctx->getOrCreateSymbol(Name);
138     Offset += MO.getOffset();
139     break;
140 
141   case MachineOperand::MO_BlockAddress:
142     Symbol = AsmPrinter.GetBlockAddressSymbol(MO.getBlockAddress());
143     Offset += MO.getOffset();
144     break;
145 
146   case MachineOperand::MO_ExternalSymbol:
147     Symbol = AsmPrinter.GetExternalSymbolSymbol(MO.getSymbolName());
148     Offset += MO.getOffset();
149     break;
150 
151   case MachineOperand::MO_MCSymbol:
152     Symbol = MO.getMCSymbol();
153     Offset += MO.getOffset();
154     break;
155 
156   case MachineOperand::MO_JumpTableIndex:
157     Symbol = AsmPrinter.GetJTISymbol(MO.getIndex());
158     break;
159 
160   case MachineOperand::MO_ConstantPoolIndex:
161     Symbol = AsmPrinter.GetCPISymbol(MO.getIndex());
162     Offset += MO.getOffset();
163     break;
164 
165   default:
166     llvm_unreachable("<unknown operand type>");
167   }
168 
169   const MCExpr *Expr = MCSymbolRefExpr::create(Symbol, *Ctx);
170 
171   if (Offset) {
172     // Note: Offset can also be negative
173     Expr = MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, *Ctx),
174                                    *Ctx);
175   }
176 
177   if (IsGpOff)
178     Expr = Mips::createGpOff(Expr, TargetKind, *Ctx);
179   else if (TargetKind != Mips::S_None)
180     Expr = MCSpecifierExpr::create(Expr, TargetKind, *Ctx);
181 
182   return MCOperand::createExpr(Expr);
183 }
184 
LowerOperand(const MachineOperand & MO,int64_t offset) const185 MCOperand MipsMCInstLower::LowerOperand(const MachineOperand &MO,
186                                         int64_t offset) const {
187   MachineOperandType MOTy = MO.getType();
188 
189   switch (MOTy) {
190   default: llvm_unreachable("unknown operand type");
191   case MachineOperand::MO_Register:
192     // Ignore all implicit register operands.
193     if (MO.isImplicit()) break;
194     return MCOperand::createReg(MO.getReg());
195   case MachineOperand::MO_Immediate:
196     return MCOperand::createImm(MO.getImm() + offset);
197   case MachineOperand::MO_MachineBasicBlock:
198   case MachineOperand::MO_GlobalAddress:
199   case MachineOperand::MO_ExternalSymbol:
200   case MachineOperand::MO_MCSymbol:
201   case MachineOperand::MO_JumpTableIndex:
202   case MachineOperand::MO_ConstantPoolIndex:
203   case MachineOperand::MO_BlockAddress:
204     return LowerSymbolOperand(MO, MOTy, offset);
205   case MachineOperand::MO_RegisterMask:
206     break;
207  }
208 
209   return MCOperand();
210 }
211 
createSub(MachineBasicBlock * BB1,MachineBasicBlock * BB2,Mips::Specifier Kind) const212 MCOperand MipsMCInstLower::createSub(MachineBasicBlock *BB1,
213                                      MachineBasicBlock *BB2,
214                                      Mips::Specifier Kind) const {
215   const MCSymbolRefExpr *Sym1 = MCSymbolRefExpr::create(BB1->getSymbol(), *Ctx);
216   const MCSymbolRefExpr *Sym2 = MCSymbolRefExpr::create(BB2->getSymbol(), *Ctx);
217   const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Sym1, Sym2, *Ctx);
218 
219   return MCOperand::createExpr(MCSpecifierExpr::create(Sub, Kind, *Ctx));
220 }
221 
222 void MipsMCInstLower::
lowerLongBranchLUi(const MachineInstr * MI,MCInst & OutMI) const223 lowerLongBranchLUi(const MachineInstr *MI, MCInst &OutMI) const {
224   OutMI.setOpcode(Mips::LUi);
225 
226   // Lower register operand.
227   OutMI.addOperand(LowerOperand(MI->getOperand(0)));
228 
229   Mips::Specifier Spec;
230   unsigned TargetFlags = MI->getOperand(1).getTargetFlags();
231   switch (TargetFlags) {
232   case MipsII::MO_HIGHEST:
233     Spec = Mips::S_HIGHEST;
234     break;
235   case MipsII::MO_HIGHER:
236     Spec = Mips::S_HIGHER;
237     break;
238   case MipsII::MO_ABS_HI:
239     Spec = Mips::S_HI;
240     break;
241   case MipsII::MO_ABS_LO:
242     Spec = Mips::S_LO;
243     break;
244   default:
245     report_fatal_error("Unexpected flags for lowerLongBranchLUi");
246   }
247 
248   if (MI->getNumOperands() == 2) {
249     const MCExpr *Expr =
250         MCSymbolRefExpr::create(MI->getOperand(1).getMBB()->getSymbol(), *Ctx);
251     const auto *MipsExpr = MCSpecifierExpr::create(Expr, Spec, *Ctx);
252     OutMI.addOperand(MCOperand::createExpr(MipsExpr));
253   } else if (MI->getNumOperands() == 3) {
254     // Create %hi($tgt-$baltgt).
255     OutMI.addOperand(createSub(MI->getOperand(1).getMBB(),
256                                MI->getOperand(2).getMBB(), Spec));
257   }
258 }
259 
lowerLongBranchADDiu(const MachineInstr * MI,MCInst & OutMI,int Opcode) const260 void MipsMCInstLower::lowerLongBranchADDiu(const MachineInstr *MI,
261                                            MCInst &OutMI, int Opcode) const {
262   OutMI.setOpcode(Opcode);
263 
264   Mips::Specifier Spec;
265   unsigned TargetFlags = MI->getOperand(2).getTargetFlags();
266   switch (TargetFlags) {
267   case MipsII::MO_HIGHEST:
268     Spec = Mips::S_HIGHEST;
269     break;
270   case MipsII::MO_HIGHER:
271     Spec = Mips::S_HIGHER;
272     break;
273   case MipsII::MO_ABS_HI:
274     Spec = Mips::S_HI;
275     break;
276   case MipsII::MO_ABS_LO:
277     Spec = Mips::S_LO;
278     break;
279   default:
280     report_fatal_error("Unexpected flags for lowerLongBranchADDiu");
281   }
282 
283   // Lower two register operands.
284   for (unsigned I = 0, E = 2; I != E; ++I) {
285     const MachineOperand &MO = MI->getOperand(I);
286     OutMI.addOperand(LowerOperand(MO));
287   }
288 
289   if (MI->getNumOperands() == 3) {
290     // Lower register operand.
291     const MCExpr *Expr =
292         MCSymbolRefExpr::create(MI->getOperand(2).getMBB()->getSymbol(), *Ctx);
293     const auto *MipsExpr = MCSpecifierExpr::create(Expr, Spec, *Ctx);
294     OutMI.addOperand(MCOperand::createExpr(MipsExpr));
295   } else if (MI->getNumOperands() == 4) {
296     // Create %lo($tgt-$baltgt) or %hi($tgt-$baltgt).
297     OutMI.addOperand(createSub(MI->getOperand(2).getMBB(),
298                                MI->getOperand(3).getMBB(), Spec));
299   }
300 }
301 
lowerLongBranch(const MachineInstr * MI,MCInst & OutMI) const302 bool MipsMCInstLower::lowerLongBranch(const MachineInstr *MI,
303                                       MCInst &OutMI) const {
304   switch (MI->getOpcode()) {
305   default:
306     return false;
307   case Mips::LONG_BRANCH_LUi:
308   case Mips::LONG_BRANCH_LUi2Op:
309   case Mips::LONG_BRANCH_LUi2Op_64:
310     lowerLongBranchLUi(MI, OutMI);
311     return true;
312   case Mips::LONG_BRANCH_ADDiu:
313   case Mips::LONG_BRANCH_ADDiu2Op:
314     lowerLongBranchADDiu(MI, OutMI, Mips::ADDiu);
315     return true;
316   case Mips::LONG_BRANCH_DADDiu:
317   case Mips::LONG_BRANCH_DADDiu2Op:
318     lowerLongBranchADDiu(MI, OutMI, Mips::DADDiu);
319     return true;
320   }
321 }
322 
Lower(const MachineInstr * MI,MCInst & OutMI) const323 void MipsMCInstLower::Lower(const MachineInstr *MI, MCInst &OutMI) const {
324   if (lowerLongBranch(MI, OutMI))
325     return;
326 
327   OutMI.setOpcode(MI->getOpcode());
328 
329   for (const MachineOperand &MO : MI->operands()) {
330     MCOperand MCOp = LowerOperand(MO);
331 
332     if (MCOp.isValid())
333       OutMI.addOperand(MCOp);
334   }
335 }
336