AMDGPU: Mark test as XFAIL in expensive_checks builds
[llvm-project.git] / llvm / lib / Target / Sparc / SparcAsmPrinter.cpp
blob7fb67ebfe2200c47a5bc73b79c26ae1d99529173
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.
12 //===----------------------------------------------------------------------===//
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;
37 #define DEBUG_TYPE "asm-printer"
39 namespace {
40 class SparcAsmPrinter : public AsmPrinter {
41 SparcTargetStreamer &getTargetStreamer() {
42 return static_cast<SparcTargetStreamer &>(
43 *OutStreamer->getTargetStreamer());
45 public:
46 explicit SparcAsmPrinter(TargetMachine &TM,
47 std::unique_ptr<MCStreamer> Streamer)
48 : AsmPrinter(TM, std::move(Streamer)) {}
50 StringRef getPassName() const override { return "Sparc Assembly Printer"; }
52 void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
53 void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
55 void emitFunctionBodyStart() override;
56 void emitInstruction(const MachineInstr *MI) override;
58 static const char *getRegisterName(MCRegister Reg) {
59 return SparcInstPrinter::getRegisterName(Reg);
62 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
63 const char *ExtraCode, raw_ostream &O) override;
64 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
65 const char *ExtraCode, raw_ostream &O) override;
67 void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
68 const MCSubtargetInfo &STI);
71 } // end of anonymous namespace
73 static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,
74 MCSymbol *Sym, MCContext &OutContext) {
75 const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym,
76 OutContext);
77 const SparcMCExpr *expr = SparcMCExpr::create(Kind, MCSym, OutContext);
78 return MCOperand::createExpr(expr);
81 static MCOperand createPCXCallOP(MCSymbol *Label,
82 MCContext &OutContext) {
83 return createSparcMCOperand(SparcMCExpr::VK_Sparc_WDISP30, Label, OutContext);
86 static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
87 MCSymbol *GOTLabel, MCSymbol *StartLabel,
88 MCSymbol *CurLabel,
89 MCContext &OutContext)
91 const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
92 const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,
93 OutContext);
94 const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,
95 OutContext);
97 const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);
98 const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);
99 const SparcMCExpr *expr = SparcMCExpr::create(Kind,
100 Add, OutContext);
101 return MCOperand::createExpr(expr);
104 static void EmitCall(MCStreamer &OutStreamer,
105 MCOperand &Callee,
106 const MCSubtargetInfo &STI)
108 MCInst CallInst;
109 CallInst.setOpcode(SP::CALL);
110 CallInst.addOperand(Callee);
111 OutStreamer.emitInstruction(CallInst, STI);
114 static void EmitRDPC(MCStreamer &OutStreamer, MCOperand &RD,
115 const MCSubtargetInfo &STI) {
116 MCInst RDPCInst;
117 RDPCInst.setOpcode(SP::RDASR);
118 RDPCInst.addOperand(RD);
119 RDPCInst.addOperand(MCOperand::createReg(SP::ASR5));
120 OutStreamer.emitInstruction(RDPCInst, STI);
123 static void EmitSETHI(MCStreamer &OutStreamer,
124 MCOperand &Imm, MCOperand &RD,
125 const MCSubtargetInfo &STI)
127 MCInst SETHIInst;
128 SETHIInst.setOpcode(SP::SETHIi);
129 SETHIInst.addOperand(RD);
130 SETHIInst.addOperand(Imm);
131 OutStreamer.emitInstruction(SETHIInst, STI);
134 static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
135 MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
136 const MCSubtargetInfo &STI)
138 MCInst Inst;
139 Inst.setOpcode(Opcode);
140 Inst.addOperand(RD);
141 Inst.addOperand(RS1);
142 Inst.addOperand(Src2);
143 OutStreamer.emitInstruction(Inst, STI);
146 static void EmitOR(MCStreamer &OutStreamer,
147 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
148 const MCSubtargetInfo &STI) {
149 EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);
152 static void EmitADD(MCStreamer &OutStreamer,
153 MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
154 const MCSubtargetInfo &STI) {
155 EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);
158 static void EmitSHL(MCStreamer &OutStreamer,
159 MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
160 const MCSubtargetInfo &STI) {
161 EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);
165 static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
166 SparcMCExpr::VariantKind HiKind,
167 SparcMCExpr::VariantKind LoKind,
168 MCOperand &RD,
169 MCContext &OutContext,
170 const MCSubtargetInfo &STI) {
172 MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
173 MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
174 EmitSETHI(OutStreamer, hi, RD, STI);
175 EmitOR(OutStreamer, RD, lo, RD, STI);
178 void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
179 const MCSubtargetInfo &STI)
181 MCSymbol *GOTLabel =
182 OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
184 const MachineOperand &MO = MI->getOperand(0);
185 assert(MO.getReg() != SP::O7 &&
186 "%o7 is assigned as destination for getpcx!");
188 MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
191 if (!isPositionIndependent()) {
192 // Just load the address of GOT to MCRegOP.
193 switch(TM.getCodeModel()) {
194 default:
195 llvm_unreachable("Unsupported absolute code model");
196 case CodeModel::Small:
197 EmitHiLo(*OutStreamer, GOTLabel,
198 SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
199 MCRegOP, OutContext, STI);
200 break;
201 case CodeModel::Medium: {
202 EmitHiLo(*OutStreamer, GOTLabel,
203 SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
204 MCRegOP, OutContext, STI);
205 MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,
206 OutContext));
207 EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
208 MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
209 GOTLabel, OutContext);
210 EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);
211 break;
213 case CodeModel::Large: {
214 EmitHiLo(*OutStreamer, GOTLabel,
215 SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
216 MCRegOP, OutContext, STI);
217 MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,
218 OutContext));
219 EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
220 // Use register %o7 to load the lower 32 bits.
221 MCOperand RegO7 = MCOperand::createReg(SP::O7);
222 EmitHiLo(*OutStreamer, GOTLabel,
223 SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
224 RegO7, OutContext, STI);
225 EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
228 return;
231 MCSymbol *StartLabel = OutContext.createTempSymbol();
232 MCSymbol *EndLabel = OutContext.createTempSymbol();
233 MCSymbol *SethiLabel = OutContext.createTempSymbol();
235 MCOperand RegO7 = MCOperand::createReg(SP::O7);
237 // <StartLabel>:
238 // <GET-PC> // This will be either `call <EndLabel>` or `rd %pc, %o7`.
239 // <SethiLabel>:
240 // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
241 // <EndLabel>:
242 // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
243 // add <MO>, %o7, <MO>
245 OutStreamer->emitLabel(StartLabel);
246 if (!STI.getTargetTriple().isSPARC64() ||
247 STI.hasFeature(Sparc::TuneSlowRDPC)) {
248 MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
249 EmitCall(*OutStreamer, Callee, STI);
250 } else {
251 // TODO find out whether it is possible to store PC
252 // in other registers, to enable leaf function optimization.
253 // (On the other hand, approx. over 97.8% of GETPCXes happen
254 // in non-leaf functions, so would this be worth the effort?)
255 EmitRDPC(*OutStreamer, RegO7, STI);
257 OutStreamer->emitLabel(SethiLabel);
258 MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,
259 GOTLabel, StartLabel, SethiLabel,
260 OutContext);
261 EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);
262 OutStreamer->emitLabel(EndLabel);
263 MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,
264 GOTLabel, StartLabel, EndLabel,
265 OutContext);
266 EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);
267 EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
270 void SparcAsmPrinter::emitInstruction(const MachineInstr *MI) {
271 Sparc_MC::verifyInstructionPredicates(MI->getOpcode(),
272 getSubtargetInfo().getFeatureBits());
274 switch (MI->getOpcode()) {
275 default: break;
276 case TargetOpcode::DBG_VALUE:
277 // FIXME: Debug Value.
278 return;
279 case SP::CASArr:
280 case SP::SWAPrr:
281 case SP::SWAPri:
282 if (MF->getSubtarget<SparcSubtarget>().fixTN0011())
283 OutStreamer->emitCodeAlignment(Align(16), &getSubtargetInfo());
284 break;
285 case SP::GETPCX:
286 LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());
287 return;
289 MachineBasicBlock::const_instr_iterator I = MI->getIterator();
290 MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
291 do {
292 MCInst TmpInst;
293 LowerSparcMachineInstrToMCInst(&*I, TmpInst, *this);
294 EmitToStreamer(*OutStreamer, TmpInst);
295 } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
298 void SparcAsmPrinter::emitFunctionBodyStart() {
299 if (!MF->getSubtarget<SparcSubtarget>().is64Bit())
300 return;
302 const MachineRegisterInfo &MRI = MF->getRegInfo();
303 const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
304 for (unsigned i = 0; globalRegs[i] != 0; ++i) {
305 unsigned reg = globalRegs[i];
306 if (MRI.use_empty(reg))
307 continue;
309 if (reg == SP::G6 || reg == SP::G7)
310 getTargetStreamer().emitSparcRegisterIgnore(reg);
311 else
312 getTargetStreamer().emitSparcRegisterScratch(reg);
316 void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
317 raw_ostream &O) {
318 const DataLayout &DL = getDataLayout();
319 const MachineOperand &MO = MI->getOperand (opNum);
320 SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();
322 bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
324 switch (MO.getType()) {
325 case MachineOperand::MO_Register:
326 O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
327 break;
329 case MachineOperand::MO_Immediate:
330 O << MO.getImm();
331 break;
332 case MachineOperand::MO_MachineBasicBlock:
333 MO.getMBB()->getSymbol()->print(O, MAI);
334 return;
335 case MachineOperand::MO_GlobalAddress:
336 PrintSymbolOperand(MO, O);
337 break;
338 case MachineOperand::MO_BlockAddress:
339 O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();
340 break;
341 case MachineOperand::MO_ExternalSymbol:
342 O << MO.getSymbolName();
343 break;
344 case MachineOperand::MO_ConstantPoolIndex:
345 O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
346 << MO.getIndex();
347 break;
348 case MachineOperand::MO_Metadata:
349 MO.getMetadata()->printAsOperand(O, MMI->getModule());
350 break;
351 default:
352 llvm_unreachable("<unknown operand type>");
354 if (CloseParen) O << ")";
357 void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
358 raw_ostream &O) {
359 printOperand(MI, opNum, O);
361 if (MI->getOperand(opNum+1).isReg() &&
362 MI->getOperand(opNum+1).getReg() == SP::G0)
363 return; // don't print "+%g0"
364 if (MI->getOperand(opNum+1).isImm() &&
365 MI->getOperand(opNum+1).getImm() == 0)
366 return; // don't print "+0"
368 O << "+";
369 printOperand(MI, opNum+1, O);
372 /// PrintAsmOperand - Print out an operand for an inline asm expression.
374 bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
375 const char *ExtraCode,
376 raw_ostream &O) {
377 if (ExtraCode && ExtraCode[0]) {
378 if (ExtraCode[1] != 0) return true; // Unknown modifier.
380 switch (ExtraCode[0]) {
381 default:
382 // See if this is a generic print operand
383 return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, O);
384 case 'L': // Low order register of a twin word register operand
385 case 'H': // High order register of a twin word register operand
387 const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>();
388 const MachineOperand &MO = MI->getOperand(OpNo);
389 const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo();
390 Register MOReg = MO.getReg();
392 Register HiReg, LoReg;
393 if (!SP::IntPairRegClass.contains(MOReg)) {
394 // If we aren't given a register pair already, find out which pair it
395 // belongs to. Note that here, the specified register operand, which
396 // refers to the high part of the twinword, needs to be an even-numbered
397 // register.
398 MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even,
399 &SP::IntPairRegClass);
400 if (!MOReg) {
401 SMLoc Loc;
402 OutContext.reportError(
403 Loc, "Hi part of pair should point to an even-numbered register");
404 OutContext.reportError(
405 Loc, "(note that in some cases it might be necessary to manually "
406 "bind the input/output registers instead of relying on "
407 "automatic allocation)");
408 return true;
412 HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even);
413 LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd);
415 Register Reg;
416 switch (ExtraCode[0]) {
417 case 'L':
418 Reg = LoReg;
419 break;
420 case 'H':
421 Reg = HiReg;
422 break;
425 O << '%' << SparcInstPrinter::getRegisterName(Reg);
426 return false;
428 case 'f':
429 case 'r':
430 break;
434 printOperand(MI, OpNo, O);
436 return false;
439 bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
440 unsigned OpNo,
441 const char *ExtraCode,
442 raw_ostream &O) {
443 if (ExtraCode && ExtraCode[0])
444 return true; // Unknown modifier
446 O << '[';
447 printMemOperand(MI, OpNo, O);
448 O << ']';
450 return false;
453 // Force static initialization.
454 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmPrinter() {
455 RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget());
456 RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target());
457 RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget());