1 | //===-- VEAsmPrinter.cpp - VE LLVM assembly writer ------------------------===// |
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 a printer that converts from our internal representation |
10 | // of machine-dependent LLVM code to GAS-format VE assembly language. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "MCTargetDesc/VEInstPrinter.h" |
15 | #include "MCTargetDesc/VEMCExpr.h" |
16 | #include "MCTargetDesc/VETargetStreamer.h" |
17 | #include "TargetInfo/VETargetInfo.h" |
18 | #include "VE.h" |
19 | #include "VEInstrInfo.h" |
20 | #include "VETargetMachine.h" |
21 | #include "llvm/CodeGen/AsmPrinter.h" |
22 | #include "llvm/CodeGen/MachineInstr.h" |
23 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
24 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
25 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
26 | #include "llvm/IR/Mangler.h" |
27 | #include "llvm/MC/MCAsmInfo.h" |
28 | #include "llvm/MC/MCContext.h" |
29 | #include "llvm/MC/MCInst.h" |
30 | #include "llvm/MC/MCInstBuilder.h" |
31 | #include "llvm/MC/MCStreamer.h" |
32 | #include "llvm/MC/MCSymbol.h" |
33 | #include "llvm/MC/TargetRegistry.h" |
34 | #include "llvm/Support/raw_ostream.h" |
35 | using namespace llvm; |
36 | |
37 | #define DEBUG_TYPE "ve-asmprinter" |
38 | |
39 | namespace { |
40 | class VEAsmPrinter : public AsmPrinter { |
41 | VETargetStreamer &getTargetStreamer() { |
42 | return static_cast<VETargetStreamer &>(*OutStreamer->getTargetStreamer()); |
43 | } |
44 | |
45 | public: |
46 | explicit VEAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer) |
47 | : AsmPrinter(TM, std::move(Streamer)) {} |
48 | |
49 | StringRef getPassName() const override { return "VE Assembly Printer" ; } |
50 | |
51 | void lowerGETGOTAndEmitMCInsts(const MachineInstr *MI, |
52 | const MCSubtargetInfo &STI); |
53 | void lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI, |
54 | const MCSubtargetInfo &STI); |
55 | void lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, |
56 | const MCSubtargetInfo &STI); |
57 | |
58 | void emitInstruction(const MachineInstr *MI) override; |
59 | |
60 | static const char *getRegisterName(MCRegister Reg) { |
61 | return VEInstPrinter::getRegisterName(Reg); |
62 | } |
63 | void printOperand(const MachineInstr *MI, int OpNum, raw_ostream &OS); |
64 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
65 | const char *, raw_ostream &O) override; |
66 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
67 | const char *, raw_ostream &O) override; |
68 | }; |
69 | } // end of anonymous namespace |
70 | |
71 | static MCOperand createVEMCOperand(VEMCExpr::VariantKind Kind, MCSymbol *Sym, |
72 | MCContext &OutContext) { |
73 | const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol: Sym, Ctx&: OutContext); |
74 | const VEMCExpr *expr = VEMCExpr::create(Kind, Expr: MCSym, Ctx&: OutContext); |
75 | return MCOperand::createExpr(Val: expr); |
76 | } |
77 | |
78 | static MCOperand createGOTRelExprOp(VEMCExpr::VariantKind Kind, |
79 | MCSymbol *GOTLabel, MCContext &OutContext) { |
80 | const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(Symbol: GOTLabel, Ctx&: OutContext); |
81 | const VEMCExpr *expr = VEMCExpr::create(Kind, Expr: GOT, Ctx&: OutContext); |
82 | return MCOperand::createExpr(Val: expr); |
83 | } |
84 | |
85 | static void emitSIC(MCStreamer &OutStreamer, MCOperand &RD, |
86 | const MCSubtargetInfo &STI) { |
87 | MCInst SICInst; |
88 | SICInst.setOpcode(VE::SIC); |
89 | SICInst.addOperand(Op: RD); |
90 | OutStreamer.emitInstruction(Inst: SICInst, STI); |
91 | } |
92 | |
93 | static void emitBSIC(MCStreamer &OutStreamer, MCOperand &R1, MCOperand &R2, |
94 | const MCSubtargetInfo &STI) { |
95 | MCInst BSICInst; |
96 | BSICInst.setOpcode(VE::BSICrii); |
97 | BSICInst.addOperand(Op: R1); |
98 | BSICInst.addOperand(Op: R2); |
99 | MCOperand czero = MCOperand::createImm(Val: 0); |
100 | BSICInst.addOperand(Op: czero); |
101 | BSICInst.addOperand(Op: czero); |
102 | OutStreamer.emitInstruction(Inst: BSICInst, STI); |
103 | } |
104 | |
105 | static void emitLEAzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, |
106 | const MCSubtargetInfo &STI) { |
107 | MCInst LEAInst; |
108 | LEAInst.setOpcode(VE::LEAzii); |
109 | LEAInst.addOperand(Op: RD); |
110 | MCOperand CZero = MCOperand::createImm(Val: 0); |
111 | LEAInst.addOperand(Op: CZero); |
112 | LEAInst.addOperand(Op: CZero); |
113 | LEAInst.addOperand(Op: Imm); |
114 | OutStreamer.emitInstruction(Inst: LEAInst, STI); |
115 | } |
116 | |
117 | static void emitLEASLzzi(MCStreamer &OutStreamer, MCOperand &Imm, MCOperand &RD, |
118 | const MCSubtargetInfo &STI) { |
119 | MCInst LEASLInst; |
120 | LEASLInst.setOpcode(VE::LEASLzii); |
121 | LEASLInst.addOperand(Op: RD); |
122 | MCOperand CZero = MCOperand::createImm(Val: 0); |
123 | LEASLInst.addOperand(Op: CZero); |
124 | LEASLInst.addOperand(Op: CZero); |
125 | LEASLInst.addOperand(Op: Imm); |
126 | OutStreamer.emitInstruction(Inst: LEASLInst, STI); |
127 | } |
128 | |
129 | static void emitLEAzii(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm, |
130 | MCOperand &RD, const MCSubtargetInfo &STI) { |
131 | MCInst LEAInst; |
132 | LEAInst.setOpcode(VE::LEAzii); |
133 | LEAInst.addOperand(Op: RD); |
134 | MCOperand CZero = MCOperand::createImm(Val: 0); |
135 | LEAInst.addOperand(Op: CZero); |
136 | LEAInst.addOperand(Op: RS1); |
137 | LEAInst.addOperand(Op: Imm); |
138 | OutStreamer.emitInstruction(Inst: LEAInst, STI); |
139 | } |
140 | |
141 | static void emitLEASLrri(MCStreamer &OutStreamer, MCOperand &RS1, |
142 | MCOperand &RS2, MCOperand &Imm, MCOperand &RD, |
143 | const MCSubtargetInfo &STI) { |
144 | MCInst LEASLInst; |
145 | LEASLInst.setOpcode(VE::LEASLrri); |
146 | LEASLInst.addOperand(Op: RD); |
147 | LEASLInst.addOperand(Op: RS1); |
148 | LEASLInst.addOperand(Op: RS2); |
149 | LEASLInst.addOperand(Op: Imm); |
150 | OutStreamer.emitInstruction(Inst: LEASLInst, STI); |
151 | } |
152 | |
153 | static void emitBinary(MCStreamer &OutStreamer, unsigned Opcode, MCOperand &RS1, |
154 | MCOperand &Src2, MCOperand &RD, |
155 | const MCSubtargetInfo &STI) { |
156 | MCInst Inst; |
157 | Inst.setOpcode(Opcode); |
158 | Inst.addOperand(Op: RD); |
159 | Inst.addOperand(Op: RS1); |
160 | Inst.addOperand(Op: Src2); |
161 | OutStreamer.emitInstruction(Inst, STI); |
162 | } |
163 | |
164 | static void emitANDrm(MCStreamer &OutStreamer, MCOperand &RS1, MCOperand &Imm, |
165 | MCOperand &RD, const MCSubtargetInfo &STI) { |
166 | emitBinary(OutStreamer, Opcode: VE::ANDrm, RS1, Src2&: Imm, RD, STI); |
167 | } |
168 | |
169 | static void emitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, |
170 | VEMCExpr::VariantKind HiKind, VEMCExpr::VariantKind LoKind, |
171 | MCOperand &RD, MCContext &OutContext, |
172 | const MCSubtargetInfo &STI) { |
173 | |
174 | MCOperand hi = createVEMCOperand(Kind: HiKind, Sym: GOTSym, OutContext); |
175 | MCOperand lo = createVEMCOperand(Kind: LoKind, Sym: GOTSym, OutContext); |
176 | emitLEAzzi(OutStreamer, Imm&: lo, RD, STI); |
177 | MCOperand M032 = MCOperand::createImm(Val: M0(Val: 32)); |
178 | emitANDrm(OutStreamer, RS1&: RD, Imm&: M032, RD, STI); |
179 | emitLEASLzzi(OutStreamer, Imm&: hi, RD, STI); |
180 | } |
181 | |
182 | void VEAsmPrinter::lowerGETGOTAndEmitMCInsts(const MachineInstr *MI, |
183 | const MCSubtargetInfo &STI) { |
184 | MCSymbol *GOTLabel = |
185 | OutContext.getOrCreateSymbol(Name: Twine("_GLOBAL_OFFSET_TABLE_" )); |
186 | |
187 | const MachineOperand &MO = MI->getOperand(i: 0); |
188 | MCOperand MCRegOP = MCOperand::createReg(Reg: MO.getReg()); |
189 | |
190 | if (!isPositionIndependent()) { |
191 | // Just load the address of GOT to MCRegOP. |
192 | switch (TM.getCodeModel()) { |
193 | default: |
194 | llvm_unreachable("Unsupported absolute code model" ); |
195 | case CodeModel::Small: |
196 | case CodeModel::Medium: |
197 | case CodeModel::Large: |
198 | emitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, HiKind: VEMCExpr::VK_VE_HI32, |
199 | LoKind: VEMCExpr::VK_VE_LO32, RD&: MCRegOP, OutContext, STI); |
200 | break; |
201 | } |
202 | return; |
203 | } |
204 | |
205 | MCOperand RegGOT = MCOperand::createReg(Reg: VE::SX15); // GOT |
206 | MCOperand RegPLT = MCOperand::createReg(Reg: VE::SX16); // PLT |
207 | |
208 | // lea %got, _GLOBAL_OFFSET_TABLE_@PC_LO(-24) |
209 | // and %got, %got, (32)0 |
210 | // sic %plt |
211 | // lea.sl %got, _GLOBAL_OFFSET_TABLE_@PC_HI(%plt, %got) |
212 | MCOperand cim24 = MCOperand::createImm(Val: -24); |
213 | MCOperand loImm = |
214 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PC_LO32, GOTLabel, OutContext); |
215 | emitLEAzii(OutStreamer&: *OutStreamer, RS1&: cim24, Imm&: loImm, RD&: MCRegOP, STI); |
216 | MCOperand M032 = MCOperand::createImm(Val: M0(Val: 32)); |
217 | emitANDrm(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: M032, RD&: MCRegOP, STI); |
218 | emitSIC(OutStreamer&: *OutStreamer, RD&: RegPLT, STI); |
219 | MCOperand hiImm = |
220 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PC_HI32, GOTLabel, OutContext); |
221 | emitLEASLrri(OutStreamer&: *OutStreamer, RS1&: RegGOT, RS2&: RegPLT, Imm&: hiImm, RD&: MCRegOP, STI); |
222 | } |
223 | |
224 | void VEAsmPrinter::lowerGETFunPLTAndEmitMCInsts(const MachineInstr *MI, |
225 | const MCSubtargetInfo &STI) { |
226 | const MachineOperand &MO = MI->getOperand(i: 0); |
227 | MCOperand MCRegOP = MCOperand::createReg(Reg: MO.getReg()); |
228 | const MachineOperand &Addr = MI->getOperand(i: 1); |
229 | MCSymbol *AddrSym = nullptr; |
230 | |
231 | switch (Addr.getType()) { |
232 | default: |
233 | llvm_unreachable("<unknown operand type>" ); |
234 | return; |
235 | case MachineOperand::MO_MachineBasicBlock: |
236 | report_fatal_error(reason: "MBB is not supported yet" ); |
237 | return; |
238 | case MachineOperand::MO_ConstantPoolIndex: |
239 | report_fatal_error(reason: "ConstantPool is not supported yet" ); |
240 | return; |
241 | case MachineOperand::MO_ExternalSymbol: |
242 | AddrSym = GetExternalSymbolSymbol(Sym: Addr.getSymbolName()); |
243 | break; |
244 | case MachineOperand::MO_GlobalAddress: |
245 | AddrSym = getSymbol(GV: Addr.getGlobal()); |
246 | break; |
247 | } |
248 | |
249 | if (!isPositionIndependent()) { |
250 | llvm_unreachable("Unsupported uses of %plt in not PIC code" ); |
251 | return; |
252 | } |
253 | |
254 | MCOperand RegPLT = MCOperand::createReg(Reg: VE::SX16); // PLT |
255 | |
256 | // lea %dst, func@plt_lo(-24) |
257 | // and %dst, %dst, (32)0 |
258 | // sic %plt ; FIXME: is it safe to use %plt here? |
259 | // lea.sl %dst, func@plt_hi(%plt, %dst) |
260 | MCOperand cim24 = MCOperand::createImm(Val: -24); |
261 | MCOperand loImm = |
262 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PLT_LO32, GOTLabel: AddrSym, OutContext); |
263 | emitLEAzii(OutStreamer&: *OutStreamer, RS1&: cim24, Imm&: loImm, RD&: MCRegOP, STI); |
264 | MCOperand M032 = MCOperand::createImm(Val: M0(Val: 32)); |
265 | emitANDrm(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: M032, RD&: MCRegOP, STI); |
266 | emitSIC(OutStreamer&: *OutStreamer, RD&: RegPLT, STI); |
267 | MCOperand hiImm = |
268 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PLT_HI32, GOTLabel: AddrSym, OutContext); |
269 | emitLEASLrri(OutStreamer&: *OutStreamer, RS1&: MCRegOP, RS2&: RegPLT, Imm&: hiImm, RD&: MCRegOP, STI); |
270 | } |
271 | |
272 | void VEAsmPrinter::lowerGETTLSAddrAndEmitMCInsts(const MachineInstr *MI, |
273 | const MCSubtargetInfo &STI) { |
274 | const MachineOperand &Addr = MI->getOperand(i: 0); |
275 | MCSymbol *AddrSym = nullptr; |
276 | |
277 | switch (Addr.getType()) { |
278 | default: |
279 | llvm_unreachable("<unknown operand type>" ); |
280 | return; |
281 | case MachineOperand::MO_MachineBasicBlock: |
282 | report_fatal_error(reason: "MBB is not supported yet" ); |
283 | return; |
284 | case MachineOperand::MO_ConstantPoolIndex: |
285 | report_fatal_error(reason: "ConstantPool is not supported yet" ); |
286 | return; |
287 | case MachineOperand::MO_ExternalSymbol: |
288 | AddrSym = GetExternalSymbolSymbol(Sym: Addr.getSymbolName()); |
289 | break; |
290 | case MachineOperand::MO_GlobalAddress: |
291 | AddrSym = getSymbol(GV: Addr.getGlobal()); |
292 | break; |
293 | } |
294 | |
295 | MCOperand RegLR = MCOperand::createReg(Reg: VE::SX10); // LR |
296 | MCOperand RegS0 = MCOperand::createReg(Reg: VE::SX0); // S0 |
297 | MCOperand RegS12 = MCOperand::createReg(Reg: VE::SX12); // S12 |
298 | MCSymbol *GetTLSLabel = OutContext.getOrCreateSymbol(Name: Twine("__tls_get_addr" )); |
299 | |
300 | // lea %s0, sym@tls_gd_lo(-24) |
301 | // and %s0, %s0, (32)0 |
302 | // sic %lr |
303 | // lea.sl %s0, sym@tls_gd_hi(%lr, %s0) |
304 | // lea %s12, __tls_get_addr@plt_lo(8) |
305 | // and %s12, %s12, (32)0 |
306 | // lea.sl %s12, __tls_get_addr@plt_hi(%s12, %lr) |
307 | // bsic %lr, (, %s12) |
308 | MCOperand cim24 = MCOperand::createImm(Val: -24); |
309 | MCOperand loImm = |
310 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_TLS_GD_LO32, GOTLabel: AddrSym, OutContext); |
311 | emitLEAzii(OutStreamer&: *OutStreamer, RS1&: cim24, Imm&: loImm, RD&: RegS0, STI); |
312 | MCOperand M032 = MCOperand::createImm(Val: M0(Val: 32)); |
313 | emitANDrm(OutStreamer&: *OutStreamer, RS1&: RegS0, Imm&: M032, RD&: RegS0, STI); |
314 | emitSIC(OutStreamer&: *OutStreamer, RD&: RegLR, STI); |
315 | MCOperand hiImm = |
316 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_TLS_GD_HI32, GOTLabel: AddrSym, OutContext); |
317 | emitLEASLrri(OutStreamer&: *OutStreamer, RS1&: RegS0, RS2&: RegLR, Imm&: hiImm, RD&: RegS0, STI); |
318 | MCOperand ci8 = MCOperand::createImm(Val: 8); |
319 | MCOperand loImm2 = |
320 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PLT_LO32, GOTLabel: GetTLSLabel, OutContext); |
321 | emitLEAzii(OutStreamer&: *OutStreamer, RS1&: ci8, Imm&: loImm2, RD&: RegS12, STI); |
322 | emitANDrm(OutStreamer&: *OutStreamer, RS1&: RegS12, Imm&: M032, RD&: RegS12, STI); |
323 | MCOperand hiImm2 = |
324 | createGOTRelExprOp(Kind: VEMCExpr::VK_VE_PLT_HI32, GOTLabel: GetTLSLabel, OutContext); |
325 | emitLEASLrri(OutStreamer&: *OutStreamer, RS1&: RegS12, RS2&: RegLR, Imm&: hiImm2, RD&: RegS12, STI); |
326 | emitBSIC(OutStreamer&: *OutStreamer, R1&: RegLR, R2&: RegS12, STI); |
327 | } |
328 | |
329 | void VEAsmPrinter::emitInstruction(const MachineInstr *MI) { |
330 | VE_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
331 | Features: getSubtargetInfo().getFeatureBits()); |
332 | |
333 | switch (MI->getOpcode()) { |
334 | default: |
335 | break; |
336 | case TargetOpcode::DBG_VALUE: |
337 | // FIXME: Debug Value. |
338 | return; |
339 | case VE::GETGOT: |
340 | lowerGETGOTAndEmitMCInsts(MI, STI: getSubtargetInfo()); |
341 | return; |
342 | case VE::GETFUNPLT: |
343 | lowerGETFunPLTAndEmitMCInsts(MI, STI: getSubtargetInfo()); |
344 | return; |
345 | case VE::GETTLSADDR: |
346 | lowerGETTLSAddrAndEmitMCInsts(MI, STI: getSubtargetInfo()); |
347 | return; |
348 | } |
349 | |
350 | MachineBasicBlock::const_instr_iterator I = MI->getIterator(); |
351 | MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); |
352 | do { |
353 | MCInst TmpInst; |
354 | LowerVEMachineInstrToMCInst(MI: &*I, OutMI&: TmpInst, AP&: *this); |
355 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
356 | } while ((++I != E) && I->isInsideBundle()); // Delay slot check. |
357 | } |
358 | |
359 | void VEAsmPrinter::printOperand(const MachineInstr *MI, int OpNum, |
360 | raw_ostream &O) { |
361 | const MachineOperand &MO = MI->getOperand(i: OpNum); |
362 | |
363 | switch (MO.getType()) { |
364 | case MachineOperand::MO_Register: |
365 | O << "%" << StringRef(getRegisterName(Reg: MO.getReg())).lower(); |
366 | break; |
367 | case MachineOperand::MO_Immediate: |
368 | O << (int)MO.getImm(); |
369 | break; |
370 | default: |
371 | llvm_unreachable("<unknown operand type>" ); |
372 | } |
373 | } |
374 | |
375 | // PrintAsmOperand - Print out an operand for an inline asm expression. |
376 | bool VEAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
377 | const char *, raw_ostream &O) { |
378 | if (ExtraCode && ExtraCode[0]) { |
379 | if (ExtraCode[1] != 0) |
380 | return true; // Unknown modifier. |
381 | |
382 | switch (ExtraCode[0]) { |
383 | default: |
384 | // See if this is a generic print operand |
385 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
386 | case 'r': |
387 | case 'v': |
388 | break; |
389 | } |
390 | } |
391 | |
392 | printOperand(MI, OpNum: OpNo, O); |
393 | |
394 | return false; |
395 | } |
396 | |
397 | bool VEAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
398 | const char *, |
399 | raw_ostream &O) { |
400 | if (ExtraCode && ExtraCode[0]) |
401 | return true; // Unknown modifier |
402 | |
403 | if (MI->getOperand(i: OpNo+1).isImm() && |
404 | MI->getOperand(i: OpNo+1).getImm() == 0) { |
405 | // don't print "+0" |
406 | } else { |
407 | printOperand(MI, OpNum: OpNo+1, O); |
408 | } |
409 | if (MI->getOperand(i: OpNo).isImm() && |
410 | MI->getOperand(i: OpNo).getImm() == 0) { |
411 | if (MI->getOperand(i: OpNo+1).isImm() && |
412 | MI->getOperand(i: OpNo+1).getImm() == 0) { |
413 | O << "0" ; |
414 | } else { |
415 | // don't print "(0)" |
416 | } |
417 | } else { |
418 | O << "(" ; |
419 | printOperand(MI, OpNum: OpNo, O); |
420 | O << ")" ; |
421 | } |
422 | return false; |
423 | } |
424 | |
425 | // Force static initialization. |
426 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeVEAsmPrinter() { |
427 | RegisterAsmPrinter<VEAsmPrinter> X(getTheVETarget()); |
428 | } |
429 | |