1 | //===-- SparcAsmPrinter.cpp - Sparc 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 SPARC assembly language. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "MCTargetDesc/SparcInstPrinter.h" |
15 | #include "MCTargetDesc/SparcMCExpr.h" |
16 | #include "MCTargetDesc/SparcMCTargetDesc.h" |
17 | #include "MCTargetDesc/SparcTargetStreamer.h" |
18 | #include "Sparc.h" |
19 | #include "SparcInstrInfo.h" |
20 | #include "SparcTargetMachine.h" |
21 | #include "TargetInfo/SparcTargetInfo.h" |
22 | #include "llvm/CodeGen/AsmPrinter.h" |
23 | #include "llvm/CodeGen/MachineInstr.h" |
24 | #include "llvm/CodeGen/MachineModuleInfoImpls.h" |
25 | #include "llvm/CodeGen/MachineRegisterInfo.h" |
26 | #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h" |
27 | #include "llvm/IR/Mangler.h" |
28 | #include "llvm/MC/MCAsmInfo.h" |
29 | #include "llvm/MC/MCContext.h" |
30 | #include "llvm/MC/MCInst.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 "asm-printer" |
38 | |
39 | namespace { |
40 | class SparcAsmPrinter : public AsmPrinter { |
41 | SparcTargetStreamer &getTargetStreamer() { |
42 | return static_cast<SparcTargetStreamer &>( |
43 | *OutStreamer->getTargetStreamer()); |
44 | } |
45 | public: |
46 | explicit SparcAsmPrinter(TargetMachine &TM, |
47 | std::unique_ptr<MCStreamer> Streamer) |
48 | : AsmPrinter(TM, std::move(Streamer)) {} |
49 | |
50 | StringRef getPassName() const override { return "Sparc Assembly Printer" ; } |
51 | |
52 | void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); |
53 | void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, |
54 | const char *Modifier = nullptr); |
55 | |
56 | void emitFunctionBodyStart() override; |
57 | void emitInstruction(const MachineInstr *MI) override; |
58 | |
59 | static const char *getRegisterName(MCRegister Reg) { |
60 | return SparcInstPrinter::getRegisterName(Reg); |
61 | } |
62 | |
63 | bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
64 | const char *, raw_ostream &O) override; |
65 | bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, |
66 | const char *, raw_ostream &O) override; |
67 | |
68 | void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, |
69 | const MCSubtargetInfo &STI); |
70 | |
71 | }; |
72 | } // end of anonymous namespace |
73 | |
74 | static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind, |
75 | MCSymbol *Sym, MCContext &OutContext) { |
76 | const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol: Sym, |
77 | Ctx&: OutContext); |
78 | const SparcMCExpr *expr = SparcMCExpr::create(Kind, Expr: MCSym, Ctx&: OutContext); |
79 | return MCOperand::createExpr(Val: expr); |
80 | |
81 | } |
82 | static MCOperand createPCXCallOP(MCSymbol *Label, |
83 | MCContext &OutContext) { |
84 | return createSparcMCOperand(Kind: SparcMCExpr::VK_Sparc_WDISP30, Sym: Label, OutContext); |
85 | } |
86 | |
87 | static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind, |
88 | MCSymbol *GOTLabel, MCSymbol *StartLabel, |
89 | MCSymbol *CurLabel, |
90 | MCContext &OutContext) |
91 | { |
92 | const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(Symbol: GOTLabel, Ctx&: OutContext); |
93 | const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(Symbol: StartLabel, |
94 | Ctx&: OutContext); |
95 | const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(Symbol: CurLabel, |
96 | Ctx&: OutContext); |
97 | |
98 | const MCBinaryExpr *Sub = MCBinaryExpr::createSub(LHS: Cur, RHS: Start, Ctx&: OutContext); |
99 | const MCBinaryExpr *Add = MCBinaryExpr::createAdd(LHS: GOT, RHS: Sub, Ctx&: OutContext); |
100 | const SparcMCExpr *expr = SparcMCExpr::create(Kind, |
101 | Expr: Add, Ctx&: OutContext); |
102 | return MCOperand::createExpr(Val: expr); |
103 | } |
104 | |
105 | static void EmitCall(MCStreamer &OutStreamer, |
106 | MCOperand &Callee, |
107 | const MCSubtargetInfo &STI) |
108 | { |
109 | MCInst CallInst; |
110 | CallInst.setOpcode(SP::CALL); |
111 | CallInst.addOperand(Op: Callee); |
112 | OutStreamer.emitInstruction(Inst: CallInst, STI); |
113 | } |
114 | |
115 | static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD, |
116 | const MCSubtargetInfo &STI) { |
117 | MCInst RDPCInst; |
118 | RDPCInst.setOpcode(SP::RDASR); |
119 | RDPCInst.addOperand(Op: RD); |
120 | RDPCInst.addOperand(Op: MCOperand::createReg(Reg: SP::ASR5)); |
121 | OutStreamer.emitInstruction(Inst: RDPCInst, STI); |
122 | } |
123 | |
124 | static void EmitSETHI(MCStreamer &OutStreamer, |
125 | MCOperand &Imm, MCOperand &RD, |
126 | const MCSubtargetInfo &STI) |
127 | { |
128 | MCInst SETHIInst; |
129 | SETHIInst.setOpcode(SP::SETHIi); |
130 | SETHIInst.addOperand(Op: RD); |
131 | SETHIInst.addOperand(Op: Imm); |
132 | OutStreamer.emitInstruction(Inst: SETHIInst, STI); |
133 | } |
134 | |
135 | static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode, |
136 | MCOperand &RS1, MCOperand &Src2, MCOperand &RD, |
137 | const MCSubtargetInfo &STI) |
138 | { |
139 | MCInst Inst; |
140 | Inst.setOpcode(Opcode); |
141 | Inst.addOperand(Op: RD); |
142 | Inst.addOperand(Op: RS1); |
143 | Inst.addOperand(Op: Src2); |
144 | OutStreamer.emitInstruction(Inst, STI); |
145 | } |
146 | |
147 | static void EmitOR(MCStreamer &OutStreamer, |
148 | MCOperand &RS1, MCOperand &Imm, MCOperand &RD, |
149 | const MCSubtargetInfo &STI) { |
150 | EmitBinary(OutStreamer, Opcode: SP::ORri, RS1, Src2&: Imm, RD, STI); |
151 | } |
152 | |
153 | static void EmitADD(MCStreamer &OutStreamer, |
154 | MCOperand &RS1, MCOperand &RS2, MCOperand &RD, |
155 | const MCSubtargetInfo &STI) { |
156 | EmitBinary(OutStreamer, Opcode: SP::ADDrr, RS1, Src2&: RS2, RD, STI); |
157 | } |
158 | |
159 | static void EmitSHL(MCStreamer &OutStreamer, |
160 | MCOperand &RS1, MCOperand &Imm, MCOperand &RD, |
161 | const MCSubtargetInfo &STI) { |
162 | EmitBinary(OutStreamer, Opcode: SP::SLLri, RS1, Src2&: Imm, RD, STI); |
163 | } |
164 | |
165 | |
166 | static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym, |
167 | SparcMCExpr::VariantKind HiKind, |
168 | SparcMCExpr::VariantKind LoKind, |
169 | MCOperand &RD, |
170 | MCContext &OutContext, |
171 | const MCSubtargetInfo &STI) { |
172 | |
173 | MCOperand hi = createSparcMCOperand(Kind: HiKind, Sym: GOTSym, OutContext); |
174 | MCOperand lo = createSparcMCOperand(Kind: LoKind, Sym: GOTSym, OutContext); |
175 | EmitSETHI(OutStreamer, Imm&: hi, RD, STI); |
176 | EmitOR(OutStreamer, RS1&: RD, Imm&: lo, RD, STI); |
177 | } |
178 | |
179 | void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, |
180 | const MCSubtargetInfo &STI) |
181 | { |
182 | MCSymbol *GOTLabel = |
183 | OutContext.getOrCreateSymbol(Name: Twine("_GLOBAL_OFFSET_TABLE_" )); |
184 | |
185 | const MachineOperand &MO = MI->getOperand(i: 0); |
186 | assert(MO.getReg() != SP::O7 && |
187 | "%o7 is assigned as destination for getpcx!" ); |
188 | |
189 | MCOperand MCRegOP = MCOperand::createReg(Reg: MO.getReg()); |
190 | |
191 | |
192 | if (!isPositionIndependent()) { |
193 | // Just load the address of GOT to MCRegOP. |
194 | switch(TM.getCodeModel()) { |
195 | default: |
196 | llvm_unreachable("Unsupported absolute code model" ); |
197 | case CodeModel::Small: |
198 | EmitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, |
199 | HiKind: SparcMCExpr::VK_Sparc_HI, LoKind: SparcMCExpr::VK_Sparc_LO, |
200 | RD&: MCRegOP, OutContext, STI); |
201 | break; |
202 | case CodeModel::Medium: { |
203 | EmitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, |
204 | HiKind: SparcMCExpr::VK_Sparc_H44, LoKind: SparcMCExpr::VK_Sparc_M44, |
205 | RD&: MCRegOP, OutContext, STI); |
206 | MCOperand imm = MCOperand::createExpr(Val: MCConstantExpr::create(Value: 12, |
207 | Ctx&: OutContext)); |
208 | EmitSHL(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: imm, RD&: MCRegOP, STI); |
209 | MCOperand lo = createSparcMCOperand(Kind: SparcMCExpr::VK_Sparc_L44, |
210 | Sym: GOTLabel, OutContext); |
211 | EmitOR(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: lo, RD&: MCRegOP, STI); |
212 | break; |
213 | } |
214 | case CodeModel::Large: { |
215 | EmitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, |
216 | HiKind: SparcMCExpr::VK_Sparc_HH, LoKind: SparcMCExpr::VK_Sparc_HM, |
217 | RD&: MCRegOP, OutContext, STI); |
218 | MCOperand imm = MCOperand::createExpr(Val: MCConstantExpr::create(Value: 32, |
219 | Ctx&: OutContext)); |
220 | EmitSHL(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: imm, RD&: MCRegOP, STI); |
221 | // Use register %o7 to load the lower 32 bits. |
222 | MCOperand RegO7 = MCOperand::createReg(Reg: SP::O7); |
223 | EmitHiLo(OutStreamer&: *OutStreamer, GOTSym: GOTLabel, |
224 | HiKind: SparcMCExpr::VK_Sparc_HI, LoKind: SparcMCExpr::VK_Sparc_LO, |
225 | RD&: RegO7, OutContext, STI); |
226 | EmitADD(OutStreamer&: *OutStreamer, RS1&: MCRegOP, RS2&: RegO7, RD&: MCRegOP, STI); |
227 | } |
228 | } |
229 | return; |
230 | } |
231 | |
232 | MCSymbol *StartLabel = OutContext.createTempSymbol(); |
233 | MCSymbol *EndLabel = OutContext.createTempSymbol(); |
234 | MCSymbol *SethiLabel = OutContext.createTempSymbol(); |
235 | |
236 | MCOperand RegO7 = MCOperand::createReg(Reg: SP::O7); |
237 | |
238 | // <StartLabel>: |
239 | // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`. |
240 | // <SethiLabel>: |
241 | // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO> |
242 | // <EndLabel>: |
243 | // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO> |
244 | // add <MO>, %o7, <MO> |
245 | |
246 | OutStreamer->emitLabel(Symbol: StartLabel); |
247 | if (!STI.getTargetTriple().isSPARC64() || |
248 | STI.hasFeature(Feature: Sparc::TuneSlowRDPC)) { |
249 | MCOperand Callee = createPCXCallOP(Label: EndLabel, OutContext); |
250 | EmitCall(OutStreamer&: *OutStreamer, Callee, STI); |
251 | } else { |
252 | // TODO find out whether it is possible to store PC |
253 | // in other registers, to enable leaf function optimization. |
254 | // (On the other hand, approx. over 97.8% of GETPCXes happen |
255 | // in non-leaf functions, so would this be worth the effort?) |
256 | EmitRDPC(OutStreamer&: *OutStreamer, RD&: RegO7, STI); |
257 | } |
258 | OutStreamer->emitLabel(Symbol: SethiLabel); |
259 | MCOperand hiImm = createPCXRelExprOp(Kind: SparcMCExpr::VK_Sparc_PC22, |
260 | GOTLabel, StartLabel, CurLabel: SethiLabel, |
261 | OutContext); |
262 | EmitSETHI(OutStreamer&: *OutStreamer, Imm&: hiImm, RD&: MCRegOP, STI); |
263 | OutStreamer->emitLabel(Symbol: EndLabel); |
264 | MCOperand loImm = createPCXRelExprOp(Kind: SparcMCExpr::VK_Sparc_PC10, |
265 | GOTLabel, StartLabel, CurLabel: EndLabel, |
266 | OutContext); |
267 | EmitOR(OutStreamer&: *OutStreamer, RS1&: MCRegOP, Imm&: loImm, RD&: MCRegOP, STI); |
268 | EmitADD(OutStreamer&: *OutStreamer, RS1&: MCRegOP, RS2&: RegO7, RD&: MCRegOP, STI); |
269 | } |
270 | |
271 | void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) { |
272 | Sparc_MC::verifyInstructionPredicates(Opcode: MI->getOpcode(), |
273 | Features: getSubtargetInfo().getFeatureBits()); |
274 | |
275 | switch (MI->getOpcode()) { |
276 | default: break; |
277 | case TargetOpcode::DBG_VALUE: |
278 | // FIXME: Debug Value. |
279 | return; |
280 | case SP::GETPCX: |
281 | LowerGETPCXAndEmitMCInsts(MI, STI: getSubtargetInfo()); |
282 | return; |
283 | } |
284 | MachineBasicBlock::const_instr_iterator I = MI->getIterator(); |
285 | MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end(); |
286 | do { |
287 | MCInst TmpInst; |
288 | LowerSparcMachineInstrToMCInst(MI: &*I, OutMI&: TmpInst, AP&: *this); |
289 | EmitToStreamer(S&: *OutStreamer, Inst: TmpInst); |
290 | } while ((++I != E) && I->isInsideBundle()); // Delay slot check. |
291 | } |
292 | |
293 | void SparcAsmPrinter::emitFunctionBodyStart() { |
294 | if (!MF->getSubtarget<SparcSubtarget>().is64Bit()) |
295 | return; |
296 | |
297 | const MachineRegisterInfo &MRI = MF->getRegInfo(); |
298 | const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 }; |
299 | for (unsigned i = 0; globalRegs[i] != 0; ++i) { |
300 | unsigned reg = globalRegs[i]; |
301 | if (MRI.use_empty(RegNo: reg)) |
302 | continue; |
303 | |
304 | if (reg == SP::G6 || reg == SP::G7) |
305 | getTargetStreamer().emitSparcRegisterIgnore(reg); |
306 | else |
307 | getTargetStreamer().emitSparcRegisterScratch(reg); |
308 | } |
309 | } |
310 | |
311 | void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, |
312 | raw_ostream &O) { |
313 | const DataLayout &DL = getDataLayout(); |
314 | const MachineOperand &MO = MI->getOperand (i: opNum); |
315 | SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags(); |
316 | |
317 | bool CloseParen = SparcMCExpr::printVariantKind(OS&: O, Kind: TF); |
318 | |
319 | switch (MO.getType()) { |
320 | case MachineOperand::MO_Register: |
321 | O << "%" << StringRef(getRegisterName(Reg: MO.getReg())).lower(); |
322 | break; |
323 | |
324 | case MachineOperand::MO_Immediate: |
325 | O << MO.getImm(); |
326 | break; |
327 | case MachineOperand::MO_MachineBasicBlock: |
328 | MO.getMBB()->getSymbol()->print(OS&: O, MAI); |
329 | return; |
330 | case MachineOperand::MO_GlobalAddress: |
331 | PrintSymbolOperand(MO, OS&: O); |
332 | break; |
333 | case MachineOperand::MO_BlockAddress: |
334 | O << GetBlockAddressSymbol(BA: MO.getBlockAddress())->getName(); |
335 | break; |
336 | case MachineOperand::MO_ExternalSymbol: |
337 | O << MO.getSymbolName(); |
338 | break; |
339 | case MachineOperand::MO_ConstantPoolIndex: |
340 | O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" |
341 | << MO.getIndex(); |
342 | break; |
343 | case MachineOperand::MO_Metadata: |
344 | MO.getMetadata()->printAsOperand(OS&: O, M: MMI->getModule()); |
345 | break; |
346 | default: |
347 | llvm_unreachable("<unknown operand type>" ); |
348 | } |
349 | if (CloseParen) O << ")" ; |
350 | } |
351 | |
352 | void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, |
353 | raw_ostream &O, const char *Modifier) { |
354 | printOperand(MI, opNum, O); |
355 | |
356 | // If this is an ADD operand, emit it like normal operands. |
357 | if (Modifier && !strcmp(s1: Modifier, s2: "arith" )) { |
358 | O << ", " ; |
359 | printOperand(MI, opNum: opNum+1, O); |
360 | return; |
361 | } |
362 | |
363 | if (MI->getOperand(i: opNum+1).isReg() && |
364 | MI->getOperand(i: opNum+1).getReg() == SP::G0) |
365 | return; // don't print "+%g0" |
366 | if (MI->getOperand(i: opNum+1).isImm() && |
367 | MI->getOperand(i: opNum+1).getImm() == 0) |
368 | return; // don't print "+0" |
369 | |
370 | O << "+" ; |
371 | printOperand(MI, opNum: opNum+1, O); |
372 | } |
373 | |
374 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
375 | /// |
376 | bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
377 | const char *, |
378 | raw_ostream &O) { |
379 | if (ExtraCode && ExtraCode[0]) { |
380 | if (ExtraCode[1] != 0) 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 'L': // Low order register of a twin word register operand |
387 | case 'H': // High order register of a twin word register operand |
388 | { |
389 | const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>(); |
390 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
391 | const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo(); |
392 | Register MOReg = MO.getReg(); |
393 | |
394 | Register HiReg, LoReg; |
395 | if (!SP::IntPairRegClass.contains(Reg: MOReg)) { |
396 | // If we aren't given a register pair already, find out which pair it |
397 | // belongs to. Note that here, the specified register operand, which |
398 | // refers to the high part of the twinword, needs to be an even-numbered |
399 | // register. |
400 | MOReg = RegisterInfo->getMatchingSuperReg(Reg: MOReg, SubIdx: SP::sub_even, |
401 | RC: &SP::IntPairRegClass); |
402 | if (!MOReg) { |
403 | SMLoc Loc; |
404 | OutContext.reportError( |
405 | L: Loc, Msg: "Hi part of pair should point to an even-numbered register" ); |
406 | OutContext.reportError( |
407 | L: Loc, Msg: "(note that in some cases it might be necessary to manually " |
408 | "bind the input/output registers instead of relying on " |
409 | "automatic allocation)" ); |
410 | return true; |
411 | } |
412 | } |
413 | |
414 | HiReg = RegisterInfo->getSubReg(Reg: MOReg, Idx: SP::sub_even); |
415 | LoReg = RegisterInfo->getSubReg(Reg: MOReg, Idx: SP::sub_odd); |
416 | |
417 | Register Reg; |
418 | switch (ExtraCode[0]) { |
419 | case 'L': |
420 | Reg = LoReg; |
421 | break; |
422 | case 'H': |
423 | Reg = HiReg; |
424 | break; |
425 | } |
426 | |
427 | O << '%' << SparcInstPrinter::getRegisterName(Reg); |
428 | return false; |
429 | } |
430 | case 'f': |
431 | case 'r': |
432 | break; |
433 | } |
434 | } |
435 | |
436 | printOperand(MI, opNum: OpNo, O); |
437 | |
438 | return false; |
439 | } |
440 | |
441 | bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
442 | unsigned OpNo, |
443 | const char *, |
444 | raw_ostream &O) { |
445 | if (ExtraCode && ExtraCode[0]) |
446 | return true; // Unknown modifier |
447 | |
448 | O << '['; |
449 | printMemOperand(MI, opNum: OpNo, O); |
450 | O << ']'; |
451 | |
452 | return false; |
453 | } |
454 | |
455 | // Force static initialization. |
456 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmPrinter() { |
457 | RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget()); |
458 | RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target()); |
459 | RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget()); |
460 | } |
461 | |