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(MCOperand::createReg(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, SP::ORri, RS1, 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, SP::ADDrr, RS1, 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, SP::SLLri, RS1, 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(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(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(Sparc::Feature: 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(MI->getOpcode(), |
273 | 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 | #ifndef NDEBUG |
318 | // Verify the target flags. |
319 | if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) { |
320 | if (MI->getOpcode() == SP::CALL) |
321 | assert(TF == SparcMCExpr::VK_Sparc_None && |
322 | "Cannot handle target flags on call address" ); |
323 | else if (MI->getOpcode() == SP::SETHIi) |
324 | assert((TF == SparcMCExpr::VK_Sparc_HI |
325 | || TF == SparcMCExpr::VK_Sparc_H44 |
326 | || TF == SparcMCExpr::VK_Sparc_HH |
327 | || TF == SparcMCExpr::VK_Sparc_LM |
328 | || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22 |
329 | || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22 |
330 | || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22 |
331 | || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22 |
332 | || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) && |
333 | "Invalid target flags for address operand on sethi" ); |
334 | else if (MI->getOpcode() == SP::TLS_CALL) |
335 | assert((TF == SparcMCExpr::VK_Sparc_None |
336 | || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL |
337 | || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) && |
338 | "Cannot handle target flags on tls call address" ); |
339 | else if (MI->getOpcode() == SP::TLS_ADDrr) |
340 | assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD |
341 | || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD |
342 | || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD |
343 | || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) && |
344 | "Cannot handle target flags on add for TLS" ); |
345 | else if (MI->getOpcode() == SP::TLS_LDrr) |
346 | assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD && |
347 | "Cannot handle target flags on ld for TLS" ); |
348 | else if (MI->getOpcode() == SP::TLS_LDXrr) |
349 | assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX && |
350 | "Cannot handle target flags on ldx for TLS" ); |
351 | else if (MI->getOpcode() == SP::XORri) |
352 | assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10 |
353 | || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) && |
354 | "Cannot handle target flags on xor for TLS" ); |
355 | else |
356 | assert((TF == SparcMCExpr::VK_Sparc_LO |
357 | || TF == SparcMCExpr::VK_Sparc_M44 |
358 | || TF == SparcMCExpr::VK_Sparc_L44 |
359 | || TF == SparcMCExpr::VK_Sparc_HM |
360 | || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10 |
361 | || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10 |
362 | || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) && |
363 | "Invalid target flags for small address operand" ); |
364 | } |
365 | #endif |
366 | |
367 | |
368 | bool CloseParen = SparcMCExpr::printVariantKind(OS&: O, Kind: TF); |
369 | |
370 | switch (MO.getType()) { |
371 | case MachineOperand::MO_Register: |
372 | O << "%" << StringRef(getRegisterName(Reg: MO.getReg())).lower(); |
373 | break; |
374 | |
375 | case MachineOperand::MO_Immediate: |
376 | O << MO.getImm(); |
377 | break; |
378 | case MachineOperand::MO_MachineBasicBlock: |
379 | MO.getMBB()->getSymbol()->print(OS&: O, MAI); |
380 | return; |
381 | case MachineOperand::MO_GlobalAddress: |
382 | PrintSymbolOperand(MO, OS&: O); |
383 | break; |
384 | case MachineOperand::MO_BlockAddress: |
385 | O << GetBlockAddressSymbol(BA: MO.getBlockAddress())->getName(); |
386 | break; |
387 | case MachineOperand::MO_ExternalSymbol: |
388 | O << MO.getSymbolName(); |
389 | break; |
390 | case MachineOperand::MO_ConstantPoolIndex: |
391 | O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" |
392 | << MO.getIndex(); |
393 | break; |
394 | case MachineOperand::MO_Metadata: |
395 | MO.getMetadata()->printAsOperand(OS&: O, M: MMI->getModule()); |
396 | break; |
397 | default: |
398 | llvm_unreachable("<unknown operand type>" ); |
399 | } |
400 | if (CloseParen) O << ")" ; |
401 | } |
402 | |
403 | void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum, |
404 | raw_ostream &O, const char *Modifier) { |
405 | printOperand(MI, opNum, O); |
406 | |
407 | // If this is an ADD operand, emit it like normal operands. |
408 | if (Modifier && !strcmp(s1: Modifier, s2: "arith" )) { |
409 | O << ", " ; |
410 | printOperand(MI, opNum: opNum+1, O); |
411 | return; |
412 | } |
413 | |
414 | if (MI->getOperand(opNum+1).isReg() && |
415 | MI->getOperand(opNum+1).getReg() == SP::G0) |
416 | return; // don't print "+%g0" |
417 | if (MI->getOperand(i: opNum+1).isImm() && |
418 | MI->getOperand(i: opNum+1).getImm() == 0) |
419 | return; // don't print "+0" |
420 | |
421 | O << "+" ; |
422 | printOperand(MI, opNum: opNum+1, O); |
423 | } |
424 | |
425 | /// PrintAsmOperand - Print out an operand for an inline asm expression. |
426 | /// |
427 | bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, |
428 | const char *, |
429 | raw_ostream &O) { |
430 | if (ExtraCode && ExtraCode[0]) { |
431 | if (ExtraCode[1] != 0) return true; // Unknown modifier. |
432 | |
433 | switch (ExtraCode[0]) { |
434 | default: |
435 | // See if this is a generic print operand |
436 | return AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS&: O); |
437 | case 'L': // Low order register of a twin word register operand |
438 | case 'H': // High order register of a twin word register operand |
439 | { |
440 | const SparcSubtarget &Subtarget = MF->getSubtarget<SparcSubtarget>(); |
441 | const MachineOperand &MO = MI->getOperand(i: OpNo); |
442 | const SparcRegisterInfo *RegisterInfo = Subtarget.getRegisterInfo(); |
443 | Register MOReg = MO.getReg(); |
444 | |
445 | Register HiReg, LoReg; |
446 | if (!SP::IntPairRegClass.contains(MOReg)) { |
447 | // If we aren't given a register pair already, find out which pair it |
448 | // belongs to. Note that here, the specified register operand, which |
449 | // refers to the high part of the twinword, needs to be an even-numbered |
450 | // register. |
451 | MOReg = RegisterInfo->getMatchingSuperReg(MOReg, SP::sub_even, |
452 | &SP::IntPairRegClass); |
453 | if (!MOReg) { |
454 | SMLoc Loc; |
455 | OutContext.reportError( |
456 | L: Loc, Msg: "Hi part of pair should point to an even-numbered register" ); |
457 | OutContext.reportError( |
458 | L: Loc, Msg: "(note that in some cases it might be necessary to manually " |
459 | "bind the input/output registers instead of relying on " |
460 | "automatic allocation)" ); |
461 | return true; |
462 | } |
463 | } |
464 | |
465 | HiReg = RegisterInfo->getSubReg(MOReg, SP::sub_even); |
466 | LoReg = RegisterInfo->getSubReg(MOReg, SP::sub_odd); |
467 | |
468 | Register Reg; |
469 | switch (ExtraCode[0]) { |
470 | case 'L': |
471 | Reg = LoReg; |
472 | break; |
473 | case 'H': |
474 | Reg = HiReg; |
475 | break; |
476 | } |
477 | |
478 | O << '%' << SparcInstPrinter::getRegisterName(Reg); |
479 | return false; |
480 | } |
481 | case 'f': |
482 | case 'r': |
483 | break; |
484 | } |
485 | } |
486 | |
487 | printOperand(MI, opNum: OpNo, O); |
488 | |
489 | return false; |
490 | } |
491 | |
492 | bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, |
493 | unsigned OpNo, |
494 | const char *, |
495 | raw_ostream &O) { |
496 | if (ExtraCode && ExtraCode[0]) |
497 | return true; // Unknown modifier |
498 | |
499 | O << '['; |
500 | printMemOperand(MI, opNum: OpNo, O); |
501 | O << ']'; |
502 | |
503 | return false; |
504 | } |
505 | |
506 | // Force static initialization. |
507 | extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeSparcAsmPrinter() { |
508 | RegisterAsmPrinter<SparcAsmPrinter> X(getTheSparcTarget()); |
509 | RegisterAsmPrinter<SparcAsmPrinter> Y(getTheSparcV9Target()); |
510 | RegisterAsmPrinter<SparcAsmPrinter> Z(getTheSparcelTarget()); |
511 | } |
512 | |