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