LLVM 18.0.0git
RISCVAsmPrinter.cpp
Go to the documentation of this file.
1//===-- RISCVAsmPrinter.cpp - RISC-V 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 the RISC-V assembly language.
11//
12//===----------------------------------------------------------------------===//
13
18#include "RISCV.h"
20#include "RISCVTargetMachine.h"
22#include "llvm/ADT/APInt.h"
23#include "llvm/ADT/Statistic.h"
30#include "llvm/MC/MCAsmInfo.h"
31#include "llvm/MC/MCContext.h"
32#include "llvm/MC/MCInst.h"
36#include "llvm/MC/MCStreamer.h"
37#include "llvm/MC/MCSymbol.h"
42
43using namespace llvm;
44
45#define DEBUG_TYPE "asm-printer"
46
47STATISTIC(RISCVNumInstrsCompressed,
48 "Number of RISC-V Compressed instructions emitted");
49
50namespace llvm {
51extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
52} // namespace llvm
53
54namespace {
55class RISCVAsmPrinter : public AsmPrinter {
56 const RISCVSubtarget *STI;
57
58public:
59 explicit RISCVAsmPrinter(TargetMachine &TM,
60 std::unique_ptr<MCStreamer> Streamer)
61 : AsmPrinter(TM, std::move(Streamer)) {}
62
63 StringRef getPassName() const override { return "RISC-V Assembly Printer"; }
64
65 bool runOnMachineFunction(MachineFunction &MF) override;
66
67 void emitInstruction(const MachineInstr *MI) override;
68
69 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
70 const char *ExtraCode, raw_ostream &OS) override;
71 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
72 const char *ExtraCode, raw_ostream &OS) override;
73
74 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
75 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
76 const MachineInstr *MI);
77
78 typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
79 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
80 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
81 void LowerKCFI_CHECK(const MachineInstr &MI);
82 void EmitHwasanMemaccessSymbols(Module &M);
83
84 // Wrapper needed for tblgenned pseudo lowering.
85 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
86
87 void emitStartOfAsmFile(Module &M) override;
88 void emitEndOfAsmFile(Module &M) override;
89
90 void emitFunctionEntryLabel() override;
91 bool emitDirectiveOptionArch();
92
93private:
94 void emitAttributes();
95
96 void emitNTLHint(const MachineInstr *MI);
97
98 bool lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
99};
100}
101
102void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
103 MCInst CInst;
104 bool Res = RISCVRVC::compress(CInst, Inst, *STI);
105 if (Res)
106 ++RISCVNumInstrsCompressed;
107 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
108}
109
110// Simple pseudo-instructions have their lowering (with expansion to real
111// instructions) auto-generated.
112#include "RISCVGenMCPseudoLowering.inc"
113
114// If the target supports Zihintntl and the instruction has a nontemporal
115// MachineMemOperand, emit an NTLH hint instruction before it.
116void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {
117 if (!STI->hasStdExtZihintntl())
118 return;
119
120 if (MI->memoperands_empty())
121 return;
122
123 MachineMemOperand *MMO = *(MI->memoperands_begin());
124 if (!MMO->isNonTemporal())
125 return;
126
127 unsigned NontemporalMode = 0;
128 if (MMO->getFlags() & MONontemporalBit0)
129 NontemporalMode += 0b1;
130 if (MMO->getFlags() & MONontemporalBit1)
131 NontemporalMode += 0b10;
132
133 MCInst Hint;
134 if (STI->hasStdExtCOrZca() && STI->enableRVCHintInstrs())
135 Hint.setOpcode(RISCV::C_ADD_HINT);
136 else
137 Hint.setOpcode(RISCV::ADD);
138
139 Hint.addOperand(MCOperand::createReg(RISCV::X0));
140 Hint.addOperand(MCOperand::createReg(RISCV::X0));
141 Hint.addOperand(MCOperand::createReg(RISCV::X2 + NontemporalMode));
142
143 EmitToStreamer(*OutStreamer, Hint);
144}
145
146void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
147 RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),
148 getSubtargetInfo().getFeatureBits());
149
150 emitNTLHint(MI);
151
152 // Do any auto-generated pseudo lowerings.
153 if (emitPseudoExpansionLowering(*OutStreamer, MI))
154 return;
155
156
157 switch (MI->getOpcode()) {
158 case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
159 LowerHWASAN_CHECK_MEMACCESS(*MI);
160 return;
161 case RISCV::KCFI_CHECK:
162 LowerKCFI_CHECK(*MI);
163 return;
164 case RISCV::PseudoRVVInitUndefM1:
165 case RISCV::PseudoRVVInitUndefM2:
166 case RISCV::PseudoRVVInitUndefM4:
167 case RISCV::PseudoRVVInitUndefM8:
168 return;
169 }
170
171 MCInst OutInst;
172 if (!lowerToMCInst(MI, OutInst))
173 EmitToStreamer(*OutStreamer, OutInst);
174}
175
176bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
177 const char *ExtraCode, raw_ostream &OS) {
178 // First try the generic code, which knows about modifiers like 'c' and 'n'.
179 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
180 return false;
181
182 const MachineOperand &MO = MI->getOperand(OpNo);
183 if (ExtraCode && ExtraCode[0]) {
184 if (ExtraCode[1] != 0)
185 return true; // Unknown modifier.
186
187 switch (ExtraCode[0]) {
188 default:
189 return true; // Unknown modifier.
190 case 'z': // Print zero register if zero, regular printing otherwise.
191 if (MO.isImm() && MO.getImm() == 0) {
193 return false;
194 }
195 break;
196 case 'i': // Literal 'i' if operand is not a register.
197 if (!MO.isReg())
198 OS << 'i';
199 return false;
200 }
201 }
202
203 switch (MO.getType()) {
205 OS << MO.getImm();
206 return false;
209 return false;
211 PrintSymbolOperand(MO, OS);
212 return false;
214 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
215 Sym->print(OS, MAI);
216 return false;
217 }
218 default:
219 break;
220 }
221
222 return true;
223}
224
225bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
226 unsigned OpNo,
227 const char *ExtraCode,
228 raw_ostream &OS) {
229 if (ExtraCode)
230 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
231
232 const MachineOperand &AddrReg = MI->getOperand(OpNo);
233 assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");
234 const MachineOperand &Offset = MI->getOperand(OpNo + 1);
235 // All memory operands should have a register and an immediate operand (see
236 // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).
237 if (!AddrReg.isReg())
238 return true;
239 if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress())
240 return true;
241
242 MCOperand MCO;
243 if (!lowerOperand(Offset, MCO))
244 return true;
245
246 if (Offset.isImm())
247 OS << MCO.getImm();
248 else if (Offset.isGlobal() || Offset.isBlockAddress())
249 OS << *MCO.getExpr();
250 OS << "(" << RISCVInstPrinter::getRegisterName(AddrReg.getReg()) << ")";
251 return false;
252}
253
254bool RISCVAsmPrinter::emitDirectiveOptionArch() {
256 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
257 SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
258 const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
259 for (const auto &Feature : RISCVFeatureKV) {
260 if (STI->hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
261 continue;
262
264 continue;
265
266 auto Delta = STI->hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus
267 : RISCVOptionArchArgType::Minus;
268 NeedEmitStdOptionArgs.emplace_back(Delta, Feature.Key);
269 }
270 if (!NeedEmitStdOptionArgs.empty()) {
272 RTS.emitDirectiveOptionArch(NeedEmitStdOptionArgs);
273 return true;
274 }
275
276 return false;
277}
278
279bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
280 STI = &MF.getSubtarget<RISCVSubtarget>();
282 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
283
284 bool EmittedOptionArch = emitDirectiveOptionArch();
285
286 SetupMachineFunction(MF);
287 emitFunctionBody();
288
289 if (EmittedOptionArch)
290 RTS.emitDirectiveOptionPop();
291 return false;
292}
293
294void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
296 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
297 if (const MDString *ModuleTargetABI =
298 dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
299 RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
300 if (TM.getTargetTriple().isOSBinFormatELF())
301 emitAttributes();
302}
303
304void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
306 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
307
308 if (TM.getTargetTriple().isOSBinFormatELF())
310 EmitHwasanMemaccessSymbols(M);
311}
312
313void RISCVAsmPrinter::emitAttributes() {
315 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
316 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
317 // attributes that differ from other functions in the module and we have no
318 // way to know which function is correct.
319 RTS.emitTargetAttributes(*TM.getMCSubtargetInfo(), /*EmitStackAlign*/ true);
320}
321
322void RISCVAsmPrinter::emitFunctionEntryLabel() {
323 const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
324 if (RMFI->isVectorCall()) {
325 auto &RTS =
326 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
327 RTS.emitDirectiveVariantCC(*CurrentFnSym);
328 }
330}
331
332// Force static initialization.
336}
337
338void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
339 Register Reg = MI.getOperand(0).getReg();
340 uint32_t AccessInfo = MI.getOperand(1).getImm();
341 MCSymbol *&Sym =
342 HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
343 if (!Sym) {
344 // FIXME: Make this work on non-ELF.
345 if (!TM.getTargetTriple().isOSBinFormatELF())
346 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
347
348 std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
349 utostr(AccessInfo) + "_short";
350 Sym = OutContext.getOrCreateSymbol(SymName);
351 }
353 auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);
354
355 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
356}
357
358void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
359 Register AddrReg = MI.getOperand(0).getReg();
360 assert(std::next(MI.getIterator())->isCall() &&
361 "KCFI_CHECK not followed by a call instruction");
362 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
363 "KCFI_CHECK call target doesn't match call operand");
364
365 // Temporary registers for comparing the hashes. If a register is used
366 // for the call target, or reserved by the user, we can clobber another
367 // temporary register as the check is immediately followed by the
368 // call. The check defaults to X6/X7, but can fall back to X28-X31 if
369 // needed.
370 unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};
371 unsigned NextReg = RISCV::X28;
372 auto isRegAvailable = [&](unsigned Reg) {
373 return Reg != AddrReg && !STI->isRegisterReservedByUser(Reg);
374 };
375 for (auto &Reg : ScratchRegs) {
376 if (isRegAvailable(Reg))
377 continue;
378 while (!isRegAvailable(NextReg))
379 ++NextReg;
380 Reg = NextReg++;
381 if (Reg > RISCV::X31)
382 report_fatal_error("Unable to find scratch registers for KCFI_CHECK");
383 }
384
385 if (AddrReg == RISCV::X0) {
386 // Checking X0 makes no sense. Instead of emitting a load, zero
387 // ScratchRegs[0].
388 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::ADDI)
389 .addReg(ScratchRegs[0])
390 .addReg(RISCV::X0)
391 .addImm(0));
392 } else {
393 // Adjust the offset for patchable-function-prefix. This assumes that
394 // patchable-function-prefix is the same for all functions.
395 int NopSize = STI->hasStdExtCOrZca() ? 2 : 4;
396 int64_t PrefixNops = 0;
397 (void)MI.getMF()
398 ->getFunction()
399 .getFnAttribute("patchable-function-prefix")
400 .getValueAsString()
401 .getAsInteger(10, PrefixNops);
402
403 // Load the target function type hash.
404 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)
405 .addReg(ScratchRegs[0])
406 .addReg(AddrReg)
407 .addImm(-(PrefixNops * NopSize + 4)));
408 }
409
410 // Load the expected 32-bit type hash.
411 const int64_t Type = MI.getOperand(1).getImm();
412 const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;
413 const int64_t Lo12 = SignExtend64<12>(Type);
414 if (Hi20) {
415 EmitToStreamer(
416 *OutStreamer,
417 MCInstBuilder(RISCV::LUI).addReg(ScratchRegs[1]).addImm(Hi20));
418 }
419 if (Lo12 || Hi20 == 0) {
420 EmitToStreamer(*OutStreamer,
421 MCInstBuilder((STI->hasFeature(RISCV::Feature64Bit) && Hi20)
422 ? RISCV::ADDIW
423 : RISCV::ADDI)
424 .addReg(ScratchRegs[1])
425 .addReg(ScratchRegs[1])
426 .addImm(Lo12));
427 }
428
429 // Compare the hashes and trap if there's a mismatch.
430 MCSymbol *Pass = OutContext.createTempSymbol();
431 EmitToStreamer(*OutStreamer,
432 MCInstBuilder(RISCV::BEQ)
433 .addReg(ScratchRegs[0])
434 .addReg(ScratchRegs[1])
435 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
436
437 MCSymbol *Trap = OutContext.createTempSymbol();
438 OutStreamer->emitLabel(Trap);
439 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::EBREAK));
440 emitKCFITrapEntry(*MI.getMF(), Trap);
441 OutStreamer->emitLabel(Pass);
442}
443
444void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
445 if (HwasanMemaccessSymbols.empty())
446 return;
447
448 assert(TM.getTargetTriple().isOSBinFormatELF());
449 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
450 // attributes that differ from other functions in the module and we have no
451 // way to know which function is correct.
452 const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
453
454 MCSymbol *HwasanTagMismatchV2Sym =
455 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
456 // Annotate symbol as one having incompatible calling convention, so
457 // run-time linkers can instead eagerly bind this function.
458 auto &RTS =
459 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
460 RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
461
462 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
463 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
464 auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,
465 RISCVMCExpr::VK_RISCV_CALL, OutContext);
466
467 for (auto &P : HwasanMemaccessSymbols) {
468 unsigned Reg = std::get<0>(P.first);
469 uint32_t AccessInfo = std::get<1>(P.first);
470 MCSymbol *Sym = P.second;
471
472 unsigned Size =
473 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
474 OutStreamer->switchSection(OutContext.getELFSection(
475 ".text.hot", ELF::SHT_PROGBITS,
477 /*IsComdat=*/true));
478
479 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
480 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
481 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
482 OutStreamer->emitLabel(Sym);
483
484 // Extract shadow offset from ptr
485 OutStreamer->emitInstruction(
486 MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
487 MCSTI);
488 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)
489 .addReg(RISCV::X6)
490 .addReg(RISCV::X6)
491 .addImm(12),
492 MCSTI);
493 // load shadow tag in X6, X5 contains shadow base
494 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)
495 .addReg(RISCV::X6)
496 .addReg(RISCV::X5)
497 .addReg(RISCV::X6),
498 MCSTI);
499 OutStreamer->emitInstruction(
500 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
501 MCSTI);
502 // Extract tag from X5 and compare it with loaded tag from shadow
503 OutStreamer->emitInstruction(
504 MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
505 MCSTI);
506 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
507 // X7 contains tag from memory, while X6 contains tag from the pointer
508 OutStreamer->emitInstruction(
509 MCInstBuilder(RISCV::BNE)
510 .addReg(RISCV::X7)
511 .addReg(RISCV::X6)
512 .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
513 OutContext)),
514 MCSTI);
515 MCSymbol *ReturnSym = OutContext.createTempSymbol();
516 OutStreamer->emitLabel(ReturnSym);
517 OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)
518 .addReg(RISCV::X0)
519 .addReg(RISCV::X1)
520 .addImm(0),
521 MCSTI);
522 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
523
524 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
525 .addReg(RISCV::X28)
526 .addReg(RISCV::X0)
527 .addImm(16),
528 MCSTI);
529 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
530 OutStreamer->emitInstruction(
531 MCInstBuilder(RISCV::BGEU)
532 .addReg(RISCV::X6)
533 .addReg(RISCV::X28)
534 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
535 MCSTI);
536
537 OutStreamer->emitInstruction(
538 MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
539 MCSTI);
540
541 if (Size != 1)
542 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
543 .addReg(RISCV::X28)
544 .addReg(RISCV::X28)
545 .addImm(Size - 1),
546 MCSTI);
547 OutStreamer->emitInstruction(
548 MCInstBuilder(RISCV::BGE)
549 .addReg(RISCV::X28)
550 .addReg(RISCV::X6)
551 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
552 MCSTI);
553
554 OutStreamer->emitInstruction(
555 MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
556 MCSTI);
557 OutStreamer->emitInstruction(
558 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
559 MCSTI);
560 OutStreamer->emitInstruction(
561 MCInstBuilder(RISCV::BEQ)
562 .addReg(RISCV::X6)
563 .addReg(RISCV::X7)
564 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
565 MCSTI);
566
567 OutStreamer->emitLabel(HandleMismatchSym);
568
569 // | Previous stack frames... |
570 // +=================================+ <-- [SP + 256]
571 // | ... |
572 // | |
573 // | Stack frame space for x12 - x31.|
574 // | |
575 // | ... |
576 // +---------------------------------+ <-- [SP + 96]
577 // | Saved x11(arg1), as |
578 // | __hwasan_check_* clobbers it. |
579 // +---------------------------------+ <-- [SP + 88]
580 // | Saved x10(arg0), as |
581 // | __hwasan_check_* clobbers it. |
582 // +---------------------------------+ <-- [SP + 80]
583 // | |
584 // | Stack frame space for x9. |
585 // +---------------------------------+ <-- [SP + 72]
586 // | |
587 // | Saved x8(fp), as |
588 // | __hwasan_check_* clobbers it. |
589 // +---------------------------------+ <-- [SP + 64]
590 // | ... |
591 // | |
592 // | Stack frame space for x2 - x7. |
593 // | |
594 // | ... |
595 // +---------------------------------+ <-- [SP + 16]
596 // | Return address (x1) for caller |
597 // | of __hwasan_check_*. |
598 // +---------------------------------+ <-- [SP + 8]
599 // | Reserved place for x0, possibly |
600 // | junk, since we don't save it. |
601 // +---------------------------------+ <-- [x2 / SP]
602
603 // Adjust sp
604 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
605 .addReg(RISCV::X2)
606 .addReg(RISCV::X2)
607 .addImm(-256),
608 MCSTI);
609
610 // store x10(arg0) by new sp
611 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
612 .addReg(RISCV::X10)
613 .addReg(RISCV::X2)
614 .addImm(8 * 10),
615 MCSTI);
616 // store x11(arg1) by new sp
617 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
618 .addReg(RISCV::X11)
619 .addReg(RISCV::X2)
620 .addImm(8 * 11),
621 MCSTI);
622
623 // store x8(fp) by new sp
624 OutStreamer->emitInstruction(
625 MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
626 8),
627 MCSTI);
628 // store x1(ra) by new sp
629 OutStreamer->emitInstruction(
630 MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
631 8),
632 MCSTI);
633 if (Reg != RISCV::X10)
634 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
635 .addReg(RISCV::X10)
636 .addReg(Reg)
637 .addImm(0),
638 MCSTI);
639 OutStreamer->emitInstruction(
640 MCInstBuilder(RISCV::ADDI)
641 .addReg(RISCV::X11)
642 .addReg(RISCV::X0)
644 MCSTI);
645
646 OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
647 MCSTI);
648 }
649}
650
652 const AsmPrinter &AP) {
653 MCContext &Ctx = AP.OutContext;
655
656 switch (MO.getTargetFlags()) {
657 default:
658 llvm_unreachable("Unknown target flag on GV operand");
659 case RISCVII::MO_None:
661 break;
662 case RISCVII::MO_CALL:
664 break;
665 case RISCVII::MO_PLT:
667 break;
668 case RISCVII::MO_LO:
670 break;
671 case RISCVII::MO_HI:
673 break;
676 break;
679 break;
682 break;
685 break;
688 break;
691 break;
694 break;
697 break;
698 }
699
700 const MCExpr *ME =
702
703 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
705 ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
706
707 if (Kind != RISCVMCExpr::VK_RISCV_None)
708 ME = RISCVMCExpr::create(ME, Kind, Ctx);
709 return MCOperand::createExpr(ME);
710}
711
712bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,
713 MCOperand &MCOp) const {
714 switch (MO.getType()) {
715 default:
716 report_fatal_error("lowerOperand: unknown operand type");
718 // Ignore all implicit register operands.
719 if (MO.isImplicit())
720 return false;
721 MCOp = MCOperand::createReg(MO.getReg());
722 break;
724 // Regmasks are like implicit defs.
725 return false;
727 MCOp = MCOperand::createImm(MO.getImm());
728 break;
730 MCOp = lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), *this);
731 break;
733 MCOp = lowerSymbolOperand(MO, getSymbolPreferLocal(*MO.getGlobal()), *this);
734 break;
736 MCOp = lowerSymbolOperand(MO, GetBlockAddressSymbol(MO.getBlockAddress()),
737 *this);
738 break;
740 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO.getSymbolName()),
741 *this);
742 break;
744 MCOp = lowerSymbolOperand(MO, GetCPISymbol(MO.getIndex()), *this);
745 break;
747 MCOp = lowerSymbolOperand(MO, GetJTISymbol(MO.getIndex()), *this);
748 break;
750 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol(), *this);
751 break;
752 }
753 return true;
754}
755
757 MCInst &OutMI) {
759 RISCVVPseudosTable::getPseudoInfo(MI->getOpcode());
760 if (!RVV)
761 return false;
762
763 OutMI.setOpcode(RVV->BaseInstr);
764
765 const MachineBasicBlock *MBB = MI->getParent();
766 assert(MBB && "MI expected to be in a basic block");
767 const MachineFunction *MF = MBB->getParent();
768 assert(MF && "MBB expected to be in a machine function");
769
770 const RISCVSubtarget &Subtarget = MF->getSubtarget<RISCVSubtarget>();
771 const TargetInstrInfo *TII = Subtarget.getInstrInfo();
772 const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
773 assert(TRI && "TargetRegisterInfo expected");
774
775 const MCInstrDesc &MCID = MI->getDesc();
776 uint64_t TSFlags = MCID.TSFlags;
777 unsigned NumOps = MI->getNumExplicitOperands();
778
779 // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if
780 // present.
782 --NumOps;
784 --NumOps;
786 --NumOps;
788 --NumOps;
789
790 bool hasVLOutput = RISCV::isFaultFirstLoad(*MI);
791 for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {
792 const MachineOperand &MO = MI->getOperand(OpNo);
793 // Skip vl ouput. It should be the second output.
794 if (hasVLOutput && OpNo == 1)
795 continue;
796
797 // Skip merge op. It should be the first operand after the defs.
798 if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {
799 assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&
800 "Expected tied to first def.");
801 const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
802 // Skip if the next operand in OutMI is not supposed to be tied. Unless it
803 // is a _TIED instruction.
805 0 &&
807 continue;
808 }
809
810 MCOperand MCOp;
811 switch (MO.getType()) {
812 default:
813 llvm_unreachable("Unknown operand type");
815 Register Reg = MO.getReg();
816
817 if (RISCV::VRM2RegClass.contains(Reg) ||
818 RISCV::VRM4RegClass.contains(Reg) ||
819 RISCV::VRM8RegClass.contains(Reg)) {
820 Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
821 assert(Reg && "Subregister does not exist");
822 } else if (RISCV::FPR16RegClass.contains(Reg)) {
823 Reg =
824 TRI->getMatchingSuperReg(Reg, RISCV::sub_16, &RISCV::FPR32RegClass);
825 assert(Reg && "Subregister does not exist");
826 } else if (RISCV::FPR64RegClass.contains(Reg)) {
827 Reg = TRI->getSubReg(Reg, RISCV::sub_32);
828 assert(Reg && "Superregister does not exist");
829 } else if (RISCV::VRN2M1RegClass.contains(Reg) ||
830 RISCV::VRN2M2RegClass.contains(Reg) ||
831 RISCV::VRN2M4RegClass.contains(Reg) ||
832 RISCV::VRN3M1RegClass.contains(Reg) ||
833 RISCV::VRN3M2RegClass.contains(Reg) ||
834 RISCV::VRN4M1RegClass.contains(Reg) ||
835 RISCV::VRN4M2RegClass.contains(Reg) ||
836 RISCV::VRN5M1RegClass.contains(Reg) ||
837 RISCV::VRN6M1RegClass.contains(Reg) ||
838 RISCV::VRN7M1RegClass.contains(Reg) ||
839 RISCV::VRN8M1RegClass.contains(Reg)) {
840 Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
841 assert(Reg && "Subregister does not exist");
842 }
843
844 MCOp = MCOperand::createReg(Reg);
845 break;
846 }
848 MCOp = MCOperand::createImm(MO.getImm());
849 break;
850 }
851 OutMI.addOperand(MCOp);
852 }
853
854 // Unmasked pseudo instructions need to append dummy mask operand to
855 // V instructions. All V instructions are modeled as the masked version.
856 const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
857 if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {
858 assert(OutMCID.operands()[OutMI.getNumOperands()].RegClass ==
859 RISCV::VMV0RegClassID &&
860 "Expected only mask operand to be missing");
861 OutMI.addOperand(MCOperand::createReg(RISCV::NoRegister));
862 }
863
864 assert(OutMI.getNumOperands() == OutMCID.getNumOperands());
865 return true;
866}
867
868bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
870 return false;
871
872 OutMI.setOpcode(MI->getOpcode());
873
874 for (const MachineOperand &MO : MI->operands()) {
875 MCOperand MCOp;
876 if (lowerOperand(MO, MCOp))
877 OutMI.addOperand(MCOp);
878 }
879
880 switch (OutMI.getOpcode()) {
881 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
882 const Function &F = MI->getParent()->getParent()->getFunction();
883 if (F.hasFnAttribute("patchable-function-entry")) {
884 unsigned Num;
885 if (F.getFnAttribute("patchable-function-entry")
886 .getValueAsString()
887 .getAsInteger(10, Num))
888 return false;
889 emitNops(Num);
890 return true;
891 }
892 break;
893 }
894 }
895 return false;
896}
MachineBasicBlock & MBB
This file implements a class to represent arbitrary precision integral constant values and operations...
#define LLVM_EXTERNAL_VISIBILITY
Definition: Compiler.h:135
uint64_t Size
Symbol * Sym
Definition: ELF_riscv.cpp:468
static GCMetadataPrinterRegistry::Add< ErlangGCPrinter > X("erlang", "erlang-compatible garbage collector")
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define F(x, y, z)
Definition: MD5.cpp:55
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
unsigned const TargetRegisterInfo * TRI
static GCMetadataPrinterRegistry::Add< OcamlGCMetadataPrinter > Y("ocaml", "ocaml 3.10-compatible collector")
#define P(N)
const char LLVMTargetMachineRef TM
LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter()
static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, const AsmPrinter &AP)
static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI)
uint64_t TSFlags
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition: Statistic.h:167
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition: Value.cpp:470
This class is intended to be used as a driving class for all asm writers.
Definition: AsmPrinter.h:85
virtual void emitInstruction(const MachineInstr *)
Targets should implement this to emit instructions.
Definition: AsmPrinter.h:572
void EmitToStreamer(MCStreamer &S, const MCInst &Inst)
Definition: AsmPrinter.cpp:401
virtual void emitStartOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the start of their fi...
Definition: AsmPrinter.h:548
virtual void emitEndOfAsmFile(Module &)
This virtual method can be overridden by targets that want to emit something at the end of their file...
Definition: AsmPrinter.h:552
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition: AsmPrinter.h:95
bool runOnMachineFunction(MachineFunction &MF) override
Emit the specified function out to the OutStreamer.
Definition: AsmPrinter.h:400
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant as...
virtual void emitFunctionEntryLabel()
EmitFunctionEntryLabel - Emit the label that is the entrypoint for the function.
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
static const MCBinaryExpr * createAdd(const MCExpr *LHS, const MCExpr *RHS, MCContext &Ctx)
Definition: MCExpr.h:528
static const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition: MCExpr.cpp:194
Context object for machine code objects.
Definition: MCContext.h:76
Base class for the full range of assembler expressions which are needed for parsing.
Definition: MCExpr.h:35
MCInstBuilder & addReg(unsigned Reg)
Add a new register operand.
Definition: MCInstBuilder.h:31
MCInstBuilder & addImm(int64_t Val)
Add a new integer immediate operand.
Definition: MCInstBuilder.h:37
MCInstBuilder & addExpr(const MCExpr *Val)
Add a new MCExpr operand.
Definition: MCInstBuilder.h:55
Instances of this class represent a single low-level machine instruction.
Definition: MCInst.h:184
unsigned getNumOperands() const
Definition: MCInst.h:208
unsigned getOpcode() const
Definition: MCInst.h:198
void addOperand(const MCOperand Op)
Definition: MCInst.h:210
void setOpcode(unsigned Op)
Definition: MCInst.h:197
Describe properties that are true of each instruction in the target description file.
Definition: MCInstrDesc.h:198
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
Definition: MCInstrDesc.h:237
ArrayRef< MCOperandInfo > operands() const
Definition: MCInstrDesc.h:239
int getOperandConstraint(unsigned OpNum, MCOI::OperandConstraint Constraint) const
Returns the value of the specified operand constraint if it is present.
Definition: MCInstrDesc.h:219
Instances of this class represent operands of the MCInst class.
Definition: MCInst.h:36
static MCOperand createReg(unsigned Reg)
Definition: MCInst.h:134
static MCOperand createExpr(const MCExpr *Val)
Definition: MCInst.h:162
int64_t getImm() const
Definition: MCInst.h:80
static MCOperand createImm(int64_t Val)
Definition: MCInst.h:141
const MCExpr * getExpr() const
Definition: MCInst.h:114
Streaming machine code generation interface.
Definition: MCStreamer.h:212
Generic base class for all target subtargets.
bool hasFeature(unsigned Feature) const
Represent a reference to a symbol from inside an expression.
Definition: MCExpr.h:192
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx)
Definition: MCExpr.h:389
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition: MCSymbol.h:41
A single uniqued string.
Definition: Metadata.h:611
MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Ty * getInfo()
getInfo - Keep track of various per-function pieces of information for backends that would like to do...
Representation of each machine instruction.
Definition: MachineInstr.h:68
A description of a memory reference used in the backend.
Flags getFlags() const
Return the raw flags of the source value,.
MachineOperand class - Representation of each machine instruction operand.
const GlobalValue * getGlobal() const
int64_t getImm() const
bool isImplicit() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isJTI() const
isJTI - Tests if this is a MO_JumpTableIndex operand.
const BlockAddress * getBlockAddress() const
unsigned getTargetFlags() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
MCSymbol * getMCSymbol() const
@ MO_Immediate
Immediate operand.
@ MO_ConstantPoolIndex
Address of indexed Constant in Constant Pool.
@ MO_MCSymbol
MCSymbol reference (for debug/eh info)
@ MO_GlobalAddress
Address of a global value.
@ MO_RegisterMask
Mask of preserved registers.
@ MO_BlockAddress
Address of a basic block.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
@ MO_JumpTableIndex
Address of indexed Jump Table for switch.
int64_t getOffset() const
Return the offset from the symbol in this operand.
bool isMBB() const
isMBB - Tests if this is a MO_MachineBasicBlock operand.
A Module instance is used to store all the information related to an LLVM module.
Definition: Module.h:65
Pass interface - Implemented by all 'passes'.
Definition: Pass.h:94
virtual StringRef getPassName() const
getPassName - Return a nice clean name for a pass.
Definition: Pass.cpp:81
static bool isSupportedExtensionFeature(StringRef Ext)
static const char * getRegisterName(MCRegister Reg)
static const RISCVMCExpr * create(const MCExpr *Expr, VariantKind Kind, MCContext &Ctx)
Definition: RISCVMCExpr.cpp:31
RISCVMachineFunctionInfo - This class is derived from MachineFunctionInfo and contains private RISCV-...
const RISCVRegisterInfo * getRegisterInfo() const override
const RISCVInstrInfo * getInstrInfo() const override
virtual void emitDirectiveVariantCC(MCSymbol &Symbol)
void emitTargetAttributes(const MCSubtargetInfo &STI, bool EmitStackAlign)
void setTargetABI(RISCVABI::ABI ABI)
virtual void emitDirectiveOptionArch(ArrayRef< RISCVOptionArchArg > Args)
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
bool empty() const
Definition: SmallVector.h:94
reference emplace_back(ArgTypes &&... Args)
Definition: SmallVector.h:941
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
TargetInstrInfo - Interface to description of machine instruction set.
Primary interface to the complete machine description for the target machine.
Definition: TargetMachine.h:78
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ SHT_PROGBITS
Definition: ELF.h:1000
@ SHF_ALLOC
Definition: ELF.h:1089
@ SHF_GROUP
Definition: ELF.h:1111
@ SHF_EXECINSTR
Definition: ELF.h:1092
ABI getTargetABI(StringRef ABIName)
static bool hasRoundModeOp(uint64_t TSFlags)
static bool isTiedPseudo(uint64_t TSFlags)
static bool hasVLOp(uint64_t TSFlags)
static bool hasVecPolicyOp(uint64_t TSFlags)
static bool hasSEWOp(uint64_t TSFlags)
bool compress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI)
bool isFaultFirstLoad(const MachineInstr &MI)
Reg
All possible values of the reg field in the ModR/M byte.
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
@ Offset
Definition: DWP.cpp:440
static const MachineMemOperand::Flags MONontemporalBit1
Target & getTheRISCV32Target()
static const MachineMemOperand::Flags MONontemporalBit0
void report_fatal_error(Error Err, bool gen_crash_diag=true)
Report a serious error, calling any installed error handler.
Definition: Error.cpp:156
Target & getTheRISCV64Target()
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1854
const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures]
@ MCSA_Weak
.weak
Definition: MCDirectives.h:45
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
Definition: MCDirectives.h:23
@ MCSA_Hidden
.hidden (ELF)
Definition: MCDirectives.h:33
Implement std::hash so that hash_code can be used in STL containers.
Definition: BitVector.h:858
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...
Used to provide key value pairs for feature and CPU bit flags.