LLVM 23.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
20#include "RISCV.h"
23#include "RISCVRegisterInfo.h"
25#include "llvm/ADT/APInt.h"
26#include "llvm/ADT/Statistic.h"
32#include "llvm/IR/Module.h"
33#include "llvm/MC/MCAsmInfo.h"
34#include "llvm/MC/MCContext.h"
35#include "llvm/MC/MCInst.h"
39#include "llvm/MC/MCStreamer.h"
40#include "llvm/MC/MCSymbol.h"
46
47using namespace llvm;
48
49#define DEBUG_TYPE "asm-printer"
50
51STATISTIC(RISCVNumInstrsCompressed,
52 "Number of RISC-V Compressed instructions emitted");
53
54namespace {
55class RISCVAsmPrinter : public AsmPrinter {
56public:
57 static char ID;
58
59private:
60 const RISCVSubtarget *STI;
61
62public:
63 explicit RISCVAsmPrinter(TargetMachine &TM,
64 std::unique_ptr<MCStreamer> Streamer)
65 : AsmPrinter(TM, std::move(Streamer), ID) {}
66
67 StringRef getPassName() const override { return "RISC-V Assembly Printer"; }
68
69 RISCVTargetStreamer &getTargetStreamer() const {
70 return static_cast<RISCVTargetStreamer &>(
71 *OutStreamer->getTargetStreamer());
72 }
73
74 void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
75 const MachineInstr &MI);
76
77 void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
78 const MachineInstr &MI);
79
80 void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
81 const MachineInstr &MI);
82
83 bool runOnMachineFunction(MachineFunction &MF) override;
84
85 void emitInstruction(const MachineInstr *MI) override;
86
87 void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) override;
88
89 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
90 const char *ExtraCode, raw_ostream &OS) override;
91 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
92 const char *ExtraCode, raw_ostream &OS) override;
93
94 // Returns whether Inst is compressed.
95 bool EmitToStreamer(MCStreamer &S, const MCInst &Inst,
96 const MCSubtargetInfo &SubtargetInfo);
97 bool EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
98 return EmitToStreamer(S, Inst, *STI);
99 }
100
101 bool lowerPseudoInstExpansion(const MachineInstr *MI, MCInst &Inst);
102
103 typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
104 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
105 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
106 void LowerKCFI_CHECK(const MachineInstr &MI);
107 void EmitHwasanMemaccessSymbols(Module &M);
108
109 // Wrapper needed for tblgenned pseudo lowering.
110 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
111
112 void emitStartOfAsmFile(Module &M) override;
113 void emitEndOfAsmFile(Module &M) override;
114
115 void emitFunctionEntryLabel() override;
116 bool emitTargetFeaturePush(const MCSubtargetInfo &STI) override;
117 void emitTargetFeaturePop(const MCSubtargetInfo &STI, bool DidPush) override;
118
119 void emitNoteGnuProperty(const Module &M);
120
121private:
122 void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
123
124 void emitNTLHint(const MachineInstr *MI);
125
126 void emitLpadAlignedCall(const MachineInstr &MI);
127
128 // XRay Support
129 void LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI);
130 void LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI);
131 void LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI);
132 void emitSled(const MachineInstr *MI, SledKind Kind);
133
134 void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
135};
136} // namespace
137
138void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
139 const MachineInstr &MI) {
140 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
141 unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
142
143 auto &Ctx = OutStreamer.getContext();
144 MCSymbol *MILabel = Ctx.createTempSymbol();
145 OutStreamer.emitLabel(MILabel);
146
147 SM.recordStackMap(*MILabel, MI);
148 assert(NumNOPBytes % NOPBytes == 0 &&
149 "Invalid number of NOP bytes requested!");
150
151 // Scan ahead to trim the shadow.
152 const MachineBasicBlock &MBB = *MI.getParent();
154 ++MII;
155 while (NumNOPBytes > 0) {
156 if (MII == MBB.end() || MII->isCall() ||
157 MII->getOpcode() == RISCV::DBG_VALUE ||
158 MII->getOpcode() == TargetOpcode::PATCHPOINT ||
159 MII->getOpcode() == TargetOpcode::STACKMAP)
160 break;
161 ++MII;
162 NumNOPBytes -= NOPBytes;
163 }
164
165 // Emit nops.
166 emitNops(NumNOPBytes / NOPBytes);
167}
168
169// Lower a patchpoint of the form:
170// [<def>], <id>, <numBytes>, <target>, <numArgs>
171void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
172 const MachineInstr &MI) {
173 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
174
175 auto &Ctx = OutStreamer.getContext();
176 MCSymbol *MILabel = Ctx.createTempSymbol();
177 OutStreamer.emitLabel(MILabel);
178 SM.recordPatchPoint(*MILabel, MI);
179
180 PatchPointOpers Opers(&MI);
181
182 const MachineOperand &CalleeMO = Opers.getCallTarget();
183 unsigned EncodedBytes = 0;
184
185 if (CalleeMO.isImm()) {
186 uint64_t CallTarget = CalleeMO.getImm();
187 if (CallTarget) {
188 assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget &&
189 "High 16 bits of call target should be zero.");
190 // Materialize the jump address:
192 RISCVMatInt::generateMCInstSeq(CallTarget, *STI, RISCV::X1, Seq);
193 for (MCInst &Inst : Seq) {
194 bool Compressed = EmitToStreamer(OutStreamer, Inst);
195 EncodedBytes += Compressed ? 2 : 4;
196 }
197 bool Compressed = EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)
198 .addReg(RISCV::X1)
199 .addReg(RISCV::X1)
200 .addImm(0));
201 EncodedBytes += Compressed ? 2 : 4;
202 }
203 } else if (CalleeMO.isGlobal()) {
204 MCOperand CallTargetMCOp;
205 lowerOperand(CalleeMO, CallTargetMCOp);
206 EmitToStreamer(OutStreamer,
207 MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));
208 EncodedBytes += 8;
209 }
210
211 // Emit padding.
212 unsigned NumBytes = Opers.getNumPatchBytes();
213 assert(NumBytes >= EncodedBytes &&
214 "Patchpoint can't request size less than the length of a call.");
215 assert((NumBytes - EncodedBytes) % NOPBytes == 0 &&
216 "Invalid number of NOP bytes requested!");
217 emitNops((NumBytes - EncodedBytes) / NOPBytes);
218}
219
220void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
221 const MachineInstr &MI) {
222 unsigned NOPBytes = STI->hasStdExtZca() ? 2 : 4;
223
224 StatepointOpers SOpers(&MI);
225 if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
226 assert(PatchBytes % NOPBytes == 0 &&
227 "Invalid number of NOP bytes requested!");
228 emitNops(PatchBytes / NOPBytes);
229 } else {
230 // Lower call target and choose correct opcode
231 const MachineOperand &CallTarget = SOpers.getCallTarget();
232 MCOperand CallTargetMCOp;
233 switch (CallTarget.getType()) {
236 lowerOperand(CallTarget, CallTargetMCOp);
237 EmitToStreamer(
238 OutStreamer,
239 MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));
240 break;
242 CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
243 EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JAL)
244 .addReg(RISCV::X1)
245 .addOperand(CallTargetMCOp));
246 break;
248 CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
249 EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)
250 .addReg(RISCV::X1)
251 .addOperand(CallTargetMCOp)
252 .addImm(0));
253 break;
254 default:
255 llvm_unreachable("Unsupported operand type in statepoint call target");
256 break;
257 }
258 }
259
260 auto &Ctx = OutStreamer.getContext();
261 MCSymbol *MILabel = Ctx.createTempSymbol();
262 OutStreamer.emitLabel(MILabel);
263 SM.recordStatepoint(*MILabel, MI);
264}
265
266bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst,
267 const MCSubtargetInfo &SubtargetInfo) {
268 MCInst CInst;
269 bool Res = RISCVRVC::compress(CInst, Inst, SubtargetInfo);
270 if (Res)
271 ++RISCVNumInstrsCompressed;
272 S.emitInstruction(Res ? CInst : Inst, SubtargetInfo);
273 return Res;
274}
275
276// Simple pseudo-instructions have their lowering (with expansion to real
277// instructions) auto-generated.
278#include "RISCVGenMCPseudoLowering.inc"
279
280// Emit a call to a returns_twice function with LPAD.
281// When Zca is enabled, emit .p2align 2 before the call to ensure the
282// following LPAD is 4-byte aligned. For assembly output, wrap with
283// .option push/exact/pop to prevent relaxation. For object output,
284// emit the pseudo directly so MCCodeEmitter handles it without R_RISCV_RELAX.
285void RISCVAsmPrinter::emitLpadAlignedCall(const MachineInstr &MI) {
286 const MCSubtargetInfo &MCSTI = getSubtargetInfo();
287 const bool IsIndirect = MI.getOpcode() == RISCV::PseudoCALLIndirectLpadAlign,
288 HasZca = MCSTI.hasFeature(RISCV::FeatureStdExtZca),
289 HasRelax = MCSTI.hasFeature(RISCV::FeatureRelax);
290
291 if (HasZca)
292 OutStreamer->emitCodeAlignment(Align(4), MCSTI);
293
294 if (OutStreamer->hasRawTextSupport()) {
295 // Assembly path: wrap call with .option push/exact/pop and emit LPAD
296 // separately so the output is human-readable.
297 RISCVTargetStreamer &RTS = getTargetStreamer();
298 if (HasZca && HasRelax) {
301 }
302
303 MCInst CallInst;
304 if (!IsIndirect) {
305 MCOperand MCOp;
306 lowerOperand(MI.getOperand(0), MCOp);
307 CallInst = MCInstBuilder(RISCV::PseudoCALL).addOperand(MCOp);
308 } else {
309 CallInst = MCInstBuilder(RISCV::JALR)
310 .addReg(RISCV::X1)
311 .addReg(MI.getOperand(0).getReg())
312 .addImm(0);
313 }
314
315 if (HasZca && HasRelax) {
316 MCSubtargetInfo NoRelaxSTI(MCSTI);
317 NoRelaxSTI.ToggleFeature(RISCV::FeatureRelax);
318 EmitToStreamer(*OutStreamer, CallInst, NoRelaxSTI);
320 } else {
321 EmitToStreamer(*OutStreamer, CallInst, MCSTI);
322 }
323
324 // LPAD is encoded as AUIPC X0, label.
325 MCInst LpadInst = MCInstBuilder(RISCV::AUIPC)
326 .addReg(RISCV::X0)
327 .addImm(MI.getOperand(1).getImm());
328 EmitToStreamer(*OutStreamer, LpadInst, MCSTI);
329 } else {
330 // Object path: emit PseudoCALL(Indirect)LpadAlign directly.
331 // MCCodeEmitter::expandFunctionCallLpad expands to AUIPC+JALR+LPAD
332 // without emitting R_RISCV_RELAX on the call fixup.
333 MCInst TmpInst;
334 TmpInst.setOpcode(MI.getOpcode());
335 if (!IsIndirect) {
336 MCOperand MCOp;
337 lowerOperand(MI.getOperand(0), MCOp);
338 TmpInst.addOperand(MCOp);
339 } else {
340 TmpInst.addOperand(MCOperand::createReg(MI.getOperand(0).getReg()));
341 }
342 TmpInst.addOperand(MCOperand::createImm(MI.getOperand(1).getImm()));
343 EmitToStreamer(*OutStreamer, TmpInst, MCSTI);
344 }
345}
346
347// If the instruction has a nontemporal MachineMemOperand, emit an NTL hint
348// instruction before it. NTL hints are always safe to emit since they use
349// HINT encodings that are guaranteed not to trap
350// (riscv-non-isa/riscv-elf-psabi-doc#474).
351void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {
352 if (!STI->getInstrInfo()->requiresNTLHint(*MI))
353 return;
354
355 assert(!MI->memoperands_empty());
356
357 MachineMemOperand *MMO = *(MI->memoperands_begin());
358
359 assert(MMO->isNonTemporal());
360
361 unsigned NontemporalMode = 0;
362 if (MMO->getFlags() & MONontemporalBit0)
363 NontemporalMode += 0b1;
364 if (MMO->getFlags() & MONontemporalBit1)
365 NontemporalMode += 0b10;
366
367 MCInst Hint;
368 if (STI->hasStdExtZca())
369 Hint.setOpcode(RISCV::C_ADD);
370 else
371 Hint.setOpcode(RISCV::ADD);
372
373 Hint.addOperand(MCOperand::createReg(RISCV::X0));
374 Hint.addOperand(MCOperand::createReg(RISCV::X0));
375 Hint.addOperand(MCOperand::createReg(RISCV::X2 + NontemporalMode));
376
377 EmitToStreamer(*OutStreamer, Hint);
378}
379
380void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
381 RISCV_MC::verifyInstructionPredicates(MI->getOpcode(), STI->getFeatureBits());
382
383 emitNTLHint(MI);
384
385 // Do any auto-generated pseudo lowerings.
386 if (MCInst OutInst; lowerPseudoInstExpansion(MI, OutInst)) {
387 EmitToStreamer(*OutStreamer, OutInst);
388 return;
389 }
390
391 switch (MI->getOpcode()) {
392 case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
393 LowerHWASAN_CHECK_MEMACCESS(*MI);
394 return;
395 case RISCV::KCFI_CHECK:
396 LowerKCFI_CHECK(*MI);
397 return;
398 case TargetOpcode::STACKMAP:
399 return LowerSTACKMAP(*OutStreamer, SM, *MI);
400 case TargetOpcode::PATCHPOINT:
401 return LowerPATCHPOINT(*OutStreamer, SM, *MI);
402 case TargetOpcode::STATEPOINT:
403 return LowerSTATEPOINT(*OutStreamer, SM, *MI);
404 case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
405 const Function &F = MI->getParent()->getParent()->getFunction();
406 if (F.hasFnAttribute("patchable-function-entry")) {
407 unsigned Num =
408 F.getFnAttributeAsParsedInteger("patchable-function-entry");
409 emitNops(Num);
410 return;
411 }
412 LowerPATCHABLE_FUNCTION_ENTER(MI);
413 return;
414 }
415 case TargetOpcode::PATCHABLE_FUNCTION_EXIT:
416 LowerPATCHABLE_FUNCTION_EXIT(MI);
417 return;
418 case TargetOpcode::PATCHABLE_TAIL_CALL:
419 LowerPATCHABLE_TAIL_CALL(MI);
420 return;
421 case RISCV::PseudoCALLLpadAlign:
422 case RISCV::PseudoCALLIndirectLpadAlign:
423 emitLpadAlignedCall(*MI);
424 return;
425 }
426
427 MCInst OutInst;
428 lowerToMCInst(MI, OutInst);
429 EmitToStreamer(*OutStreamer, OutInst);
430}
431
432bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
433 const char *ExtraCode, raw_ostream &OS) {
434 // First try the generic code, which knows about modifiers like 'c' and 'n'.
435 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
436 return false;
437
438 const MachineOperand &MO = MI->getOperand(OpNo);
439 if (ExtraCode && ExtraCode[0]) {
440 if (ExtraCode[1] != 0)
441 return true; // Unknown modifier.
442
443 switch (ExtraCode[0]) {
444 default:
445 return true; // Unknown modifier.
446 case 'z': // Print zero register if zero, regular printing otherwise.
447 if (MO.isImm() && MO.getImm() == 0) {
448 OS << RISCVInstPrinter::getRegisterName(RISCV::X0);
449 return false;
450 }
451 break;
452 case 'i': // Literal 'i' if operand is not a register.
453 if (!MO.isReg())
454 OS << 'i';
455 return false;
456 case 'N': // Print the register encoding as an integer (0-31)
457 if (!MO.isReg())
458 return true;
459
460 const RISCVRegisterInfo *TRI = STI->getRegisterInfo();
461 OS << TRI->getEncodingValue(MO.getReg());
462 return false;
463 }
464 }
465
466 switch (MO.getType()) {
468 OS << MO.getImm();
469 return false;
472 return false;
474 PrintSymbolOperand(MO, OS);
475 return false;
477 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
478 Sym->print(OS, MAI);
479 return false;
480 }
481 default:
482 break;
483 }
484
485 return true;
486}
487
488bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
489 unsigned OpNo,
490 const char *ExtraCode,
491 raw_ostream &OS) {
492 if (ExtraCode)
493 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
494
495 const MachineOperand &AddrReg = MI->getOperand(OpNo);
496 assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");
497 const MachineOperand &Offset = MI->getOperand(OpNo + 1);
498 // All memory operands should have a register and an immediate operand (see
499 // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).
500 if (!AddrReg.isReg())
501 return true;
502 if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() &&
503 !Offset.isMCSymbol())
504 return true;
505
506 MCOperand MCO;
507 if (!lowerOperand(Offset, MCO))
508 return true;
509
510 if (Offset.isImm())
511 OS << MCO.getImm();
512 else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol())
513 MAI.printExpr(OS, *MCO.getExpr());
514
515 if (Offset.isMCSymbol())
516 MMI->getContext().registerInlineAsmLabel(Offset.getMCSymbol());
517 if (Offset.isBlockAddress()) {
518 const BlockAddress *BA = Offset.getBlockAddress();
519 MCSymbol *Sym = GetBlockAddressSymbol(BA);
520 MMI->getContext().registerInlineAsmLabel(Sym);
521 }
522
523 OS << "(" << RISCVInstPrinter::getRegisterName(AddrReg.getReg()) << ")";
524 return false;
525}
526
527bool RISCVAsmPrinter::emitTargetFeaturePush(const MCSubtargetInfo &STI) {
528 RISCVTargetStreamer &RTS = getTargetStreamer();
529 SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
530 const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
531 for (const auto &Feature : MCSTI.getAllProcessorFeatures()) {
532 if (STI.hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
533 continue;
534
536 continue;
537
538 auto Delta = STI.hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus
539 : RISCVOptionArchArgType::Minus;
540 StringRef ExtName = Feature.key();
541 ExtName.consume_front("experimental-");
542 NeedEmitStdOptionArgs.emplace_back(Delta, ExtName.str());
543 }
544 if (!NeedEmitStdOptionArgs.empty()) {
546 RTS.emitDirectiveOptionArch(NeedEmitStdOptionArgs);
547 return true;
548 }
549
550 return false;
551}
552
553void RISCVAsmPrinter::emitTargetFeaturePop(const MCSubtargetInfo &STI,
554 bool DidPush) {
555 if (DidPush)
556 getTargetStreamer().emitDirectiveOptionPop();
557}
558
559bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
560 STI = &MF.getSubtarget<RISCVSubtarget>();
561
562 bool EmittedOptionArch = emitTargetFeaturePush(*STI);
563
564 SetupMachineFunction(MF);
565 emitFunctionBody();
566
567 // Emit the XRay table
568 emitXRayTable();
569
570 emitTargetFeaturePop(*STI, EmittedOptionArch);
571 return false;
572}
573
574void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_ENTER(const MachineInstr *MI) {
575 emitSled(MI, SledKind::FUNCTION_ENTER);
576}
577
578void RISCVAsmPrinter::LowerPATCHABLE_FUNCTION_EXIT(const MachineInstr *MI) {
579 emitSled(MI, SledKind::FUNCTION_EXIT);
580}
581
582void RISCVAsmPrinter::LowerPATCHABLE_TAIL_CALL(const MachineInstr *MI) {
583 emitSled(MI, SledKind::TAIL_CALL);
584}
585
586void RISCVAsmPrinter::emitSled(const MachineInstr *MI, SledKind Kind) {
587 // We want to emit the jump instruction and the nops constituting the sled.
588 // The format is as follows:
589 // .Lxray_sled_N
590 // ALIGN
591 // J .tmpN
592 // 21 or 33 C.NOP instructions
593 // .tmpN
594
595 // The following variable holds the count of the number of NOPs to be patched
596 // in for XRay instrumentation during compilation.
597 // Note that RV64 and RV32 each has a sled of 68 and 44 bytes, respectively.
598 // Assuming we're using JAL to jump to .tmpN, then we only need
599 // (68 - 4)/2 = 32 NOPs for RV64 and (44 - 4)/2 = 20 for RV32. However, there
600 // is a chance that we'll use C.JAL instead, so an additional NOP is needed.
601 const uint8_t NoopsInSledCount = STI->is64Bit() ? 33 : 21;
602
603 OutStreamer->emitCodeAlignment(Align(4), *STI);
604 auto CurSled = OutContext.createTempSymbol("xray_sled_", true);
605 OutStreamer->emitLabel(CurSled);
606 auto Target = OutContext.createTempSymbol();
607
608 const MCExpr *TargetExpr = MCSymbolRefExpr::create(Target, OutContext);
609
610 // Emit "J bytes" instruction, which jumps over the nop sled to the actual
611 // start of function.
612 EmitToStreamer(
613 *OutStreamer,
614 MCInstBuilder(RISCV::JAL).addReg(RISCV::X0).addExpr(TargetExpr));
615
616 // Emit NOP instructions
617 for (int8_t I = 0; I < NoopsInSledCount; ++I)
618 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::ADDI)
619 .addReg(RISCV::X0)
620 .addReg(RISCV::X0)
621 .addImm(0));
622
623 OutStreamer->emitLabel(Target);
624 recordSled(CurSled, *MI, Kind, 2);
625}
626
627void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
628 assert(OutStreamer->getTargetStreamer() &&
629 "target streamer is uninitialized");
630 RISCVTargetStreamer &RTS = getTargetStreamer();
631 if (const MDString *ModuleTargetABI =
632 dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
633 RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
634
635 MCSubtargetInfo SubtargetInfo = TM.getMCSubtargetInfo();
636
637 // Use module flag to update feature bits.
638 if (auto *MD = dyn_cast_or_null<MDNode>(M.getModuleFlag("riscv-isa"))) {
639 for (auto &ISA : MD->operands()) {
640 if (auto *ISAString = dyn_cast_or_null<MDString>(ISA)) {
641 auto ParseResult = llvm::RISCVISAInfo::parseArchString(
642 ISAString->getString(), /*EnableExperimentalExtension=*/true,
643 /*ExperimentalExtensionVersionCheck=*/true);
644 if (!errorToBool(ParseResult.takeError())) {
645 auto &ISAInfo = *ParseResult;
646 for (const auto &Feature : SubtargetInfo.getAllProcessorFeatures()) {
647 if (ISAInfo->hasExtension(Feature.key()) &&
648 !SubtargetInfo.hasFeature(Feature.Value))
649 SubtargetInfo.ToggleFeature(Feature.key());
650 }
651 }
652 }
653 }
654
655 RTS.setFlagsFromFeatures(SubtargetInfo);
656 }
657
658 if (TM.getTargetTriple().isOSBinFormatELF())
659 emitAttributes(SubtargetInfo);
660}
661
662void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
663 RISCVTargetStreamer &RTS = getTargetStreamer();
664
665 if (TM.getTargetTriple().isOSBinFormatELF()) {
667 emitNoteGnuProperty(M);
668 }
669 EmitHwasanMemaccessSymbols(M);
670}
671
672void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) {
673 RISCVTargetStreamer &RTS = getTargetStreamer();
674 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
675 // attributes that differ from other functions in the module and we have no
676 // way to know which function is correct.
677 RTS.emitTargetAttributes(SubtargetInfo, /*EmitStackAlign*/ true);
678}
679
680void RISCVAsmPrinter::emitFunctionEntryLabel() {
681 const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
682 if (RMFI->isVectorCall()) {
683 RISCVTargetStreamer &RTS = getTargetStreamer();
684 RTS.emitDirectiveVariantCC(*CurrentFnSym);
685 }
687}
688
689// Force static initialization.
697
698void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
699 Register Reg = MI.getOperand(0).getReg();
700 uint32_t AccessInfo = MI.getOperand(1).getImm();
701 MCSymbol *&Sym =
702 HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
703 if (!Sym) {
704 // FIXME: Make this work on non-ELF.
705 if (!TM.getTargetTriple().isOSBinFormatELF())
706 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
707
708 std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
709 utostr(AccessInfo) + "_short";
710 Sym = OutContext.getOrCreateSymbol(SymName);
711 }
712 auto Res = MCSymbolRefExpr::create(Sym, OutContext);
713 auto Expr = MCSpecifierExpr::create(Res, RISCV::S_CALL_PLT, OutContext);
714
715 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
716}
717
718void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
719 Register AddrReg = MI.getOperand(0).getReg();
720 assert(std::next(MI.getIterator())->isCall() &&
721 "KCFI_CHECK not followed by a call instruction");
722 assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
723 "KCFI_CHECK call target doesn't match call operand");
724
725 // Temporary registers for comparing the hashes. If a register is used
726 // for the call target, or reserved by the user, we can clobber another
727 // temporary register as the check is immediately followed by the
728 // call. The check defaults to X6/X7, but can fall back to X28-X31 if
729 // needed.
730 unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};
731 unsigned NextReg = RISCV::X28;
732 auto isRegAvailable = [&](unsigned Reg) {
733 return Reg != AddrReg && !STI->isRegisterReservedByUser(Reg);
734 };
735 for (auto &Reg : ScratchRegs) {
736 if (isRegAvailable(Reg))
737 continue;
738 while (!isRegAvailable(NextReg))
739 ++NextReg;
740 Reg = NextReg++;
741 if (Reg > RISCV::X31)
742 report_fatal_error("Unable to find scratch registers for KCFI_CHECK");
743 }
744
745 if (AddrReg == RISCV::X0) {
746 // Checking X0 makes no sense. Instead of emitting a load, zero
747 // ScratchRegs[0].
748 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::ADDI)
749 .addReg(ScratchRegs[0])
750 .addReg(RISCV::X0)
751 .addImm(0));
752 } else {
753 // Adjust the offset for patchable-function-prefix. This assumes that
754 // patchable-function-prefix is the same for all functions.
755 int NopSize = STI->hasStdExtZca() ? 2 : 4;
756 int64_t PrefixNops =
757 MI.getMF()->getFunction().getFnAttributeAsParsedInteger(
758 "patchable-function-prefix");
759
760 // Load the target function type hash.
761 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)
762 .addReg(ScratchRegs[0])
763 .addReg(AddrReg)
764 .addImm(-(PrefixNops * NopSize + 4)));
765 }
766
767 // Load the expected 32-bit type hash.
768 const int64_t Type = MI.getOperand(1).getImm();
769 const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;
770 const int64_t Lo12 = SignExtend64<12>(Type);
771 if (Hi20) {
772 EmitToStreamer(
773 *OutStreamer,
774 MCInstBuilder(RISCV::LUI).addReg(ScratchRegs[1]).addImm(Hi20));
775 }
776 if (Lo12 || Hi20 == 0) {
777 EmitToStreamer(*OutStreamer,
778 MCInstBuilder((STI->hasFeature(RISCV::Feature64Bit) && Hi20)
779 ? RISCV::ADDIW
780 : RISCV::ADDI)
781 .addReg(ScratchRegs[1])
782 .addReg(ScratchRegs[1])
783 .addImm(Lo12));
784 }
785
786 // Compare the hashes and trap if there's a mismatch.
787 MCSymbol *Pass = OutContext.createTempSymbol();
788 EmitToStreamer(*OutStreamer,
789 MCInstBuilder(RISCV::BEQ)
790 .addReg(ScratchRegs[0])
791 .addReg(ScratchRegs[1])
792 .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
793
794 MCSymbol *Trap = OutContext.createTempSymbol();
795 OutStreamer->emitLabel(Trap);
796 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::EBREAK));
797 emitKCFITrapEntry(*MI.getMF(), Trap);
798 OutStreamer->emitLabel(Pass);
799}
800
801void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
802 if (HwasanMemaccessSymbols.empty())
803 return;
804
805 assert(TM.getTargetTriple().isOSBinFormatELF());
806 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
807 // attributes that differ from other functions in the module and we have no
808 // way to know which function is correct.
809 const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
810
811 MCSymbol *HwasanTagMismatchV2Sym =
812 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
813 // Annotate symbol as one having incompatible calling convention, so
814 // run-time linkers can instead eagerly bind this function.
815 RISCVTargetStreamer &RTS = getTargetStreamer();
816 RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
817
818 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
819 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
820 auto Expr = MCSpecifierExpr::create(HwasanTagMismatchV2Ref, RISCV::S_CALL_PLT,
821 OutContext);
822
823 for (auto &P : HwasanMemaccessSymbols) {
824 unsigned Reg = std::get<0>(P.first);
825 uint32_t AccessInfo = std::get<1>(P.first);
826 MCSymbol *Sym = P.second;
827
828 unsigned Size =
829 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
830 OutStreamer->switchSection(OutContext.getELFSection(
831 ".text.hot", ELF::SHT_PROGBITS,
833 /*IsComdat=*/true));
834
836 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
837 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
838 OutStreamer->emitLabel(Sym);
839
840 // Extract shadow offset from ptr
841 EmitToStreamer(
842 *OutStreamer,
843 MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
844 MCSTI);
845 EmitToStreamer(*OutStreamer,
846 MCInstBuilder(RISCV::SRLI)
847 .addReg(RISCV::X6)
848 .addReg(RISCV::X6)
849 .addImm(12),
850 MCSTI);
851 // load shadow tag in X6, X5 contains shadow base
852 EmitToStreamer(*OutStreamer,
853 MCInstBuilder(RISCV::ADD)
854 .addReg(RISCV::X6)
855 .addReg(RISCV::X5)
856 .addReg(RISCV::X6),
857 MCSTI);
858 EmitToStreamer(
859 *OutStreamer,
860 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
861 MCSTI);
862 // Extract tag from pointer and compare it with loaded tag from shadow
863 EmitToStreamer(
864 *OutStreamer,
865 MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
866 MCSTI);
867 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
868 // X7 contains tag from the pointer, while X6 contains tag from memory
869 EmitToStreamer(*OutStreamer,
870 MCInstBuilder(RISCV::BNE)
871 .addReg(RISCV::X7)
872 .addReg(RISCV::X6)
874 HandleMismatchOrPartialSym, OutContext)),
875 MCSTI);
876 MCSymbol *ReturnSym = OutContext.createTempSymbol();
877 OutStreamer->emitLabel(ReturnSym);
878 EmitToStreamer(*OutStreamer,
879 MCInstBuilder(RISCV::JALR)
880 .addReg(RISCV::X0)
881 .addReg(RISCV::X1)
882 .addImm(0),
883 MCSTI);
884 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
885
886 EmitToStreamer(*OutStreamer,
887 MCInstBuilder(RISCV::ADDI)
888 .addReg(RISCV::X28)
889 .addReg(RISCV::X0)
890 .addImm(16),
891 MCSTI);
892 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
893 EmitToStreamer(
894 *OutStreamer,
895 MCInstBuilder(RISCV::BGEU)
896 .addReg(RISCV::X6)
897 .addReg(RISCV::X28)
898 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
899 MCSTI);
900
901 EmitToStreamer(
902 *OutStreamer,
903 MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
904 MCSTI);
905
906 if (Size != 1)
907 EmitToStreamer(*OutStreamer,
908 MCInstBuilder(RISCV::ADDI)
909 .addReg(RISCV::X28)
910 .addReg(RISCV::X28)
911 .addImm(Size - 1),
912 MCSTI);
913 EmitToStreamer(
914 *OutStreamer,
915 MCInstBuilder(RISCV::BGE)
916 .addReg(RISCV::X28)
917 .addReg(RISCV::X6)
918 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
919 MCSTI);
920
921 EmitToStreamer(
922 *OutStreamer,
923 MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
924 MCSTI);
925 EmitToStreamer(
926 *OutStreamer,
927 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
928 MCSTI);
929 EmitToStreamer(*OutStreamer,
930 MCInstBuilder(RISCV::BEQ)
931 .addReg(RISCV::X6)
932 .addReg(RISCV::X7)
933 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
934 MCSTI);
935
936 OutStreamer->emitLabel(HandleMismatchSym);
937
938 // | Previous stack frames... |
939 // +=================================+ <-- [SP + 256]
940 // | ... |
941 // | |
942 // | Stack frame space for x12 - x31.|
943 // | |
944 // | ... |
945 // +---------------------------------+ <-- [SP + 96]
946 // | Saved x11(arg1), as |
947 // | __hwasan_check_* clobbers it. |
948 // +---------------------------------+ <-- [SP + 88]
949 // | Saved x10(arg0), as |
950 // | __hwasan_check_* clobbers it. |
951 // +---------------------------------+ <-- [SP + 80]
952 // | |
953 // | Stack frame space for x9. |
954 // +---------------------------------+ <-- [SP + 72]
955 // | |
956 // | Saved x8(fp), as |
957 // | __hwasan_check_* clobbers it. |
958 // +---------------------------------+ <-- [SP + 64]
959 // | ... |
960 // | |
961 // | Stack frame space for x2 - x7. |
962 // | |
963 // | ... |
964 // +---------------------------------+ <-- [SP + 16]
965 // | Return address (x1) for caller |
966 // | of __hwasan_check_*. |
967 // +---------------------------------+ <-- [SP + 8]
968 // | Reserved place for x0, possibly |
969 // | junk, since we don't save it. |
970 // +---------------------------------+ <-- [x2 / SP]
971
972 // Adjust sp
973 EmitToStreamer(*OutStreamer,
974 MCInstBuilder(RISCV::ADDI)
975 .addReg(RISCV::X2)
976 .addReg(RISCV::X2)
977 .addImm(-256),
978 MCSTI);
979
980 // store x10(arg0) by new sp
981 EmitToStreamer(*OutStreamer,
982 MCInstBuilder(RISCV::SD)
983 .addReg(RISCV::X10)
984 .addReg(RISCV::X2)
985 .addImm(8 * 10),
986 MCSTI);
987 // store x11(arg1) by new sp
988 EmitToStreamer(*OutStreamer,
989 MCInstBuilder(RISCV::SD)
990 .addReg(RISCV::X11)
991 .addReg(RISCV::X2)
992 .addImm(8 * 11),
993 MCSTI);
994
995 // store x8(fp) by new sp
996 EmitToStreamer(
997 *OutStreamer,
998 MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
999 8),
1000 MCSTI);
1001 // store x1(ra) by new sp
1002 EmitToStreamer(
1003 *OutStreamer,
1004 MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
1005 8),
1006 MCSTI);
1007 if (Reg != RISCV::X10)
1008 EmitToStreamer(
1009 *OutStreamer,
1010 MCInstBuilder(RISCV::ADDI).addReg(RISCV::X10).addReg(Reg).addImm(0),
1011 MCSTI);
1012 EmitToStreamer(*OutStreamer,
1013 MCInstBuilder(RISCV::ADDI)
1014 .addReg(RISCV::X11)
1015 .addReg(RISCV::X0)
1016 .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),
1017 MCSTI);
1018
1019 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
1020 MCSTI);
1021 }
1022}
1023
1024void RISCVAsmPrinter::emitNoteGnuProperty(const Module &M) {
1025 assert(TM.getTargetTriple().isOSBinFormatELF() && "invalid binary format");
1026 uint32_t GnuProps = 0;
1027 if (const Metadata *const Flag = M.getModuleFlag("cf-protection-return");
1028 Flag && !mdconst::extract<ConstantInt>(Flag)->isZero())
1030
1031 if (const Metadata *const Flag = M.getModuleFlag("cf-protection-branch");
1032 Flag && !mdconst::extract<ConstantInt>(Flag)->isZero()) {
1033 using namespace llvm::RISCVISAUtils;
1034 const Metadata *const CFBranchLabelSchemeFlag =
1035 M.getModuleFlag("cf-branch-label-scheme");
1036 assert(CFBranchLabelSchemeFlag &&
1037 "cf-protection=branch should come with cf-branch-label-scheme=... "
1038 "on RISC-V targets");
1039 const StringRef CFBranchLabelScheme =
1040 cast<MDString>(CFBranchLabelSchemeFlag)->getString();
1041 switch (llvm::RISCVCFI::getZicfilpLabelScheme(CFBranchLabelScheme)) {
1043 reportFatalInternalError("invalid RISC-V Zicfilp label scheme");
1046 break;
1048 // TODO: Emit the func-sig bit after the feature is implemented
1049 reportFatalUsageError("the complete func-sig label scheme feature is not "
1050 "implemented yet");
1051 break;
1052 }
1053 }
1054
1055 if (!GnuProps)
1056 return;
1057
1058 auto &RTS = static_cast<RISCVTargetELFStreamer &>(getTargetStreamer());
1059 RTS.emitNoteGnuPropertySection(GnuProps);
1060}
1061
1063 const AsmPrinter &AP) {
1064 MCContext &Ctx = AP.OutContext;
1065 RISCV::Specifier Kind;
1066
1067 switch (MO.getTargetFlags()) {
1068 default:
1069 llvm_unreachable("Unknown target flag on GV operand");
1070 case RISCVII::MO_None:
1071 Kind = RISCV::S_None;
1072 break;
1073 case RISCVII::MO_CALL:
1074 Kind = RISCV::S_CALL_PLT;
1075 break;
1076 case RISCVII::MO_LO:
1077 Kind = RISCV::S_LO;
1078 break;
1079 case RISCVII::MO_HI:
1080 Kind = ELF::R_RISCV_HI20;
1081 break;
1083 Kind = RISCV::S_PCREL_LO;
1084 break;
1086 Kind = RISCV::S_PCREL_HI;
1087 break;
1088 case RISCVII::MO_GOT_HI:
1089 Kind = RISCV::S_GOT_HI;
1090 break;
1092 Kind = RISCV::S_TPREL_LO;
1093 break;
1095 Kind = ELF::R_RISCV_TPREL_HI20;
1096 break;
1098 Kind = ELF::R_RISCV_TPREL_ADD;
1099 break;
1101 Kind = ELF::R_RISCV_TLS_GOT_HI20;
1102 break;
1104 Kind = ELF::R_RISCV_TLS_GD_HI20;
1105 break;
1107 Kind = ELF::R_RISCV_TLSDESC_HI20;
1108 break;
1110 Kind = ELF::R_RISCV_TLSDESC_LOAD_LO12;
1111 break;
1113 Kind = ELF::R_RISCV_TLSDESC_ADD_LO12;
1114 break;
1116 Kind = ELF::R_RISCV_TLSDESC_CALL;
1117 break;
1119 Kind = RISCV::S_QC_ACCESS;
1120 break;
1121 }
1122
1123 const MCExpr *ME = MCSymbolRefExpr::create(Sym, Ctx);
1124
1125 if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
1127 ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
1128
1129 if (Kind != RISCV::S_None)
1130 ME = MCSpecifierExpr::create(ME, Kind, Ctx);
1131 return MCOperand::createExpr(ME);
1132}
1133
1134bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,
1135 MCOperand &MCOp) const {
1136 switch (MO.getType()) {
1137 default:
1138 report_fatal_error("lowerOperand: unknown operand type");
1140 // Ignore all implicit register operands.
1141 if (MO.isImplicit())
1142 return false;
1143 MCOp = MCOperand::createReg(MO.getReg());
1144 break;
1146 // Regmasks are like implicit defs.
1147 return false;
1149 MCOp = MCOperand::createImm(MO.getImm());
1150 break;
1152 MCOp = lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), *this);
1153 break;
1155 MCOp = lowerSymbolOperand(MO, getSymbolPreferLocal(*MO.getGlobal()), *this);
1156 break;
1158 MCOp = lowerSymbolOperand(MO, GetBlockAddressSymbol(MO.getBlockAddress()),
1159 *this);
1160 break;
1162 MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO.getSymbolName()),
1163 *this);
1164 break;
1166 MCOp = lowerSymbolOperand(MO, GetCPISymbol(MO.getIndex()), *this);
1167 break;
1169 MCOp = lowerSymbolOperand(MO, GetJTISymbol(MO.getIndex()), *this);
1170 break;
1172 MCOp = lowerSymbolOperand(MO, MO.getMCSymbol(), *this);
1173 break;
1174 }
1175 return true;
1176}
1177
1179 MCInst &OutMI,
1180 const RISCVSubtarget *STI) {
1182 RISCVVPseudosTable::getPseudoInfo(MI->getOpcode());
1183 if (!RVV)
1184 return false;
1185
1186 OutMI.setOpcode(RVV->BaseInstr);
1187
1188 const TargetInstrInfo *TII = STI->getInstrInfo();
1189 const TargetRegisterInfo *TRI = STI->getRegisterInfo();
1190 assert(TRI && "TargetRegisterInfo expected");
1191
1192 const MCInstrDesc &MCID = MI->getDesc();
1193 uint64_t TSFlags = MCID.TSFlags;
1194 unsigned NumOps = MI->getNumExplicitOperands();
1195
1196 // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if
1197 // present.
1198 if (RISCVII::hasVecPolicyOp(TSFlags))
1199 --NumOps;
1200 if (RISCVII::hasSEWOp(TSFlags))
1201 --NumOps;
1202 if (RISCVII::hasVLOp(TSFlags))
1203 --NumOps;
1204 if (RISCVII::hasRoundModeOp(TSFlags))
1205 --NumOps;
1206 if (RISCVII::hasTWidenOp(TSFlags))
1207 --NumOps;
1208 if (RISCVII::hasTMOp(TSFlags))
1209 --NumOps;
1210 if (RISCVII::hasTKOp(TSFlags))
1211 --NumOps;
1212
1213 bool hasVLOutput = RISCVInstrInfo::isFaultOnlyFirstLoad(*MI);
1214 for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {
1215 const MachineOperand &MO = MI->getOperand(OpNo);
1216 // Skip vl output. It should be the second output.
1217 if (hasVLOutput && OpNo == 1)
1218 continue;
1219
1220 // Skip passthru op. It should be the first operand after the defs.
1221 if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {
1222 assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&
1223 "Expected tied to first def.");
1224 const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
1225 // Skip if the next operand in OutMI is not supposed to be tied. Unless it
1226 // is a _TIED instruction.
1227 if (OutMCID.getOperandConstraint(OutMI.getNumOperands(), MCOI::TIED_TO) <
1228 0 &&
1229 !RISCVII::isTiedPseudo(TSFlags))
1230 continue;
1231 }
1232
1233 MCOperand MCOp;
1234 switch (MO.getType()) {
1235 default:
1236 llvm_unreachable("Unknown operand type");
1238 Register Reg = MO.getReg();
1239
1240 if (RISCV::VRM2RegClass.contains(Reg) ||
1241 RISCV::VRM4RegClass.contains(Reg) ||
1242 RISCV::VRM8RegClass.contains(Reg)) {
1243 Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
1244 assert(Reg && "Subregister does not exist");
1245 } else if (RISCV::FPR16RegClass.contains(Reg)) {
1246 Reg =
1247 TRI->getMatchingSuperReg(Reg, RISCV::sub_16, &RISCV::FPR32RegClass);
1248 assert(Reg && "Subregister does not exist");
1249 } else if (RISCV::FPR64RegClass.contains(Reg)) {
1250 Reg = TRI->getSubReg(Reg, RISCV::sub_32);
1251 assert(Reg && "Superregister does not exist");
1252 } else if (RISCV::VRN2M1RegClass.contains(Reg) ||
1253 RISCV::VRN2M2RegClass.contains(Reg) ||
1254 RISCV::VRN2M4RegClass.contains(Reg) ||
1255 RISCV::VRN3M1RegClass.contains(Reg) ||
1256 RISCV::VRN3M2RegClass.contains(Reg) ||
1257 RISCV::VRN4M1RegClass.contains(Reg) ||
1258 RISCV::VRN4M2RegClass.contains(Reg) ||
1259 RISCV::VRN5M1RegClass.contains(Reg) ||
1260 RISCV::VRN6M1RegClass.contains(Reg) ||
1261 RISCV::VRN7M1RegClass.contains(Reg) ||
1262 RISCV::VRN8M1RegClass.contains(Reg)) {
1263 Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
1264 assert(Reg && "Subregister does not exist");
1265 }
1266
1267 MCOp = MCOperand::createReg(Reg);
1268 break;
1269 }
1271 MCOp = MCOperand::createImm(MO.getImm());
1272 break;
1273 }
1274 OutMI.addOperand(MCOp);
1275 }
1276
1277 // Unmasked pseudo instructions need to append dummy mask operand to
1278 // V instructions. All V instructions are modeled as the masked version.
1279 const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
1280 if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {
1281 assert(OutMCID.operands()[OutMI.getNumOperands()].OperandType ==
1283 "Expected only mask operand to be missing");
1284 OutMI.addOperand(MCOperand::createReg(RISCV::NoRegister));
1285 }
1286
1287 assert(OutMI.getNumOperands() == OutMCID.getNumOperands());
1288 return true;
1289}
1290
1291void RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
1292 if (lowerRISCVVMachineInstrToMCInst(MI, OutMI, STI))
1293 return;
1294
1295 OutMI.setOpcode(MI->getOpcode());
1296
1297 for (const MachineOperand &MO : MI->operands()) {
1298 MCOperand MCOp;
1299 if (lowerOperand(MO, MCOp))
1300 OutMI.addOperand(MCOp);
1301 }
1302}
1303
1304void RISCVAsmPrinter::emitMachineConstantPoolValue(
1305 MachineConstantPoolValue *MCPV) {
1306 auto *RCPV = static_cast<RISCVConstantPoolValue *>(MCPV);
1307 MCSymbol *MCSym;
1308
1309 if (RCPV->isGlobalValue()) {
1310 auto *GV = RCPV->getGlobalValue();
1311 MCSym = getSymbol(GV);
1312 } else {
1313 assert(RCPV->isExtSymbol() && "unrecognized constant pool type");
1314 auto Sym = RCPV->getSymbol();
1315 MCSym = GetExternalSymbolSymbol(Sym);
1316 }
1317
1318 const MCExpr *Expr = MCSymbolRefExpr::create(MCSym, OutContext);
1319 uint64_t Size = getDataLayout().getTypeAllocSize(RCPV->getType());
1320 OutStreamer->emitValue(Expr, Size);
1321}
1322
1323char RISCVAsmPrinter::ID = 0;
1324
1325INITIALIZE_PASS(RISCVAsmPrinter, "riscv-asm-printer", "RISC-V Assembly Printer",
1326 false, false)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static MCDisassembler::DecodeStatus addOperand(MCInst &Inst, const MCOperand &Opnd)
This file implements a class to represent arbitrary precision integral constant values and operations...
MachineBasicBlock & MBB
#define X(NUM, ENUM, NAME)
Definition ELF.h:856
static GCRegistry::Add< ErlangGC > A("erlang", "erlang-compatible garbage collector")
static GCRegistry::Add< OcamlGC > B("ocaml", "ocaml 3.10-compatible GC")
#define LLVM_ABI
Definition Compiler.h:215
#define LLVM_EXTERNAL_VISIBILITY
Definition Compiler.h:132
dxil translate DXIL Translate Metadata
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
Module.h This file contains the declarations for the Module class.
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym, const AsmPrinter &AP)
#define F(x, y, z)
Definition MD5.cpp:54
#define I(x, y, z)
Definition MD5.cpp:57
print mir2vec MIR2Vec Vocabulary Printer Pass
Definition MIR2Vec.cpp:598
Machine Check Debug Module
This file declares the MachineConstantPool class which is an abstract constant pool to keep track of ...
Register Reg
Register const TargetRegisterInfo * TRI
Promote Memory to Register
Definition Mem2Reg.cpp:110
static constexpr unsigned SM(unsigned Version)
#define P(N)
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, const RISCVSubtarget *STI)
LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter()
static bool contains(SmallPtrSetImpl< ConstantExpr * > &Cache, ConstantExpr *Expr, Constant *C)
Definition Value.cpp:484
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:171
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
This class is intended to be used as a driving class for all asm writers.
Definition AsmPrinter.h:91
MCContext & OutContext
This is the context for the output file that we are streaming.
Definition AsmPrinter.h:101
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, SMLoc Loc=SMLoc())
Definition MCExpr.h:342
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Definition MCExpr.cpp:212
Context object for machine code objects.
Definition MCContext.h:83
Base class for the full range of assembler expressions which are needed for parsing.
Definition MCExpr.h:34
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
unsigned getNumOperands() const
Definition MCInst.h:212
unsigned getOpcode() const
Definition MCInst.h:202
void addOperand(const MCOperand Op)
Definition MCInst.h:215
void setOpcode(unsigned Op)
Definition MCInst.h:201
Describe properties that are true of each instruction in the target description file.
unsigned getNumOperands() const
Return the number of declared MachineOperands for this MachineInstruction.
ArrayRef< MCOperandInfo > operands() const
int getOperandConstraint(unsigned OpNum, MCOI::OperandConstraint Constraint) const
Returns the value of the specified operand constraint if it is present.
Instances of this class represent operands of the MCInst class.
Definition MCInst.h:40
static MCOperand createExpr(const MCExpr *Val)
Definition MCInst.h:166
int64_t getImm() const
Definition MCInst.h:84
static MCOperand createReg(MCRegister Reg)
Definition MCInst.h:138
static MCOperand createImm(int64_t Val)
Definition MCInst.h:145
const MCExpr * getExpr() const
Definition MCInst.h:118
static const MCSpecifierExpr * create(const MCExpr *Expr, Spec S, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.cpp:743
Streaming machine code generation interface.
Definition MCStreamer.h:222
virtual void emitInstruction(const MCInst &Inst, const MCSubtargetInfo &STI)
Emit the given Instruction into the current section.
virtual bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute)=0
Add the given Attribute to Symbol.
virtual void emitCodeAlignment(Align Alignment, const MCSubtargetInfo &STI, unsigned MaxBytesToEmit=0)
Emit nops until the byte alignment ByteAlignment is reached.
virtual bool hasRawTextSupport() const
Return true if this asm streamer supports emitting unformatted text to the .s file with EmitRawText.
Definition MCStreamer.h:385
MCContext & getContext() const
Definition MCStreamer.h:326
void emitValue(const MCExpr *Value, unsigned Size, SMLoc Loc=SMLoc())
virtual void emitLabel(MCSymbol *Symbol, SMLoc Loc=SMLoc())
Emit a label for Symbol into the current section.
MCTargetStreamer * getTargetStreamer()
Definition MCStreamer.h:336
virtual void switchSection(MCSection *Section, uint32_t Subsec=0)
Set the current section where code is being emitted to Section.
bool hasFeature(unsigned Feature) const
const FeatureBitset & ToggleFeature(uint64_t FB)
Toggle a feature and return the re-computed feature bits.
ArrayRef< SubtargetFeatureKV > getAllProcessorFeatures() const
Return processor features.
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
Definition MCExpr.h:213
MCSymbol - Instances of this class represent a symbol name in the MC file, and MCSymbols are created ...
Definition MCSymbol.h:42
LLVM_ABI void print(raw_ostream &OS, const MCAsmInfo *MAI) const
print - Print the value to the stream OS.
Definition MCSymbol.cpp:59
StringRef getName() const
getName - Get the symbol name.
Definition MCSymbol.h:188
MachineInstrBundleIterator< const MachineInstr > const_iterator
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Representation of each machine instruction.
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 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
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
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.
static LLVM_ABI bool isSupportedExtensionFeature(StringRef Ext)
static LLVM_ABI llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseArchString(StringRef Arch, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck=true)
Parse RISC-V ISA info from arch string.
static const char * getRegisterName(MCRegister Reg)
bool requiresNTLHint(const MachineInstr &MI) const
Return true if the instruction requires an NTL hint to be emitted.
const RISCVRegisterInfo * getRegisterInfo() const override
const RISCVInstrInfo * getInstrInfo() const override
virtual void emitDirectiveVariantCC(MCSymbol &Symbol)
void emitTargetAttributes(const MCSubtargetInfo &STI, bool EmitStackAlign)
void setFlagsFromFeatures(const MCSubtargetInfo &STI)
void setTargetABI(RISCVABI::ABI ABI)
virtual void emitDirectiveOptionArch(ArrayRef< RISCVOptionArchArg > Args)
Wrapper class representing virtual and physical registers.
Definition Register.h:20
reference emplace_back(ArgTypes &&... Args)
std::string str() const
Get the contents as an std::string.
Definition StringRef.h:222
bool consume_front(char Prefix)
Returns true if this StringRef has the given prefix and removes that prefix.
Definition StringRef.h:661
TargetInstrInfo - Interface to description of machine instruction set.
Primary interface to the complete machine description for the target machine.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Align[]
Key for Kernel::Arg::Metadata::mAlign.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
@ SHF_ALLOC
Definition ELF.h:1256
@ SHF_GROUP
Definition ELF.h:1278
@ SHF_EXECINSTR
Definition ELF.h:1259
@ SHT_PROGBITS
Definition ELF.h:1155
@ GNU_PROPERTY_RISCV_FEATURE_1_CFI_LP_UNLABELED
Definition ELF.h:1921
@ GNU_PROPERTY_RISCV_FEATURE_1_CFI_SS
Definition ELF.h:1922
ABI getTargetABI(StringRef ABIName)
ZicfilpLabelSchemeKind getZicfilpLabelScheme(const StringRef CFBranchLabelScheme)
static bool hasRoundModeOp(uint64_t TSFlags)
static bool hasTWidenOp(uint64_t TSFlags)
static bool isTiedPseudo(uint64_t TSFlags)
static bool hasTKOp(uint64_t TSFlags)
static bool hasVLOp(uint64_t TSFlags)
static bool hasTMOp(uint64_t TSFlags)
static bool hasVecPolicyOp(uint64_t TSFlags)
static bool hasSEWOp(uint64_t TSFlags)
void generateMCInstSeq(int64_t Val, const MCSubtargetInfo &STI, MCRegister DestReg, SmallVectorImpl< MCInst > &Insts)
bool compress(MCInst &OutInst, const MCInst &MI, const MCSubtargetInfo &STI)
uint16_t Specifier
void emitInstruction(MCObjectStreamer &, const MCInst &Inst, const MCSubtargetInfo &STI)
std::enable_if_t< detail::IsValidPointer< X, Y >::value, X * > extract(Y &&MD)
Extract a Value from Metadata.
Definition Metadata.h:668
This is an optimization pass for GlobalISel generic memory operations.
bool errorToBool(Error Err)
Helper for converting an Error to a bool.
Definition Error.h:1129
@ Offset
Definition DWP.cpp:573
static const MachineMemOperand::Flags MONontemporalBit1
Target & getTheRISCV32Target()
static const MachineMemOperand::Flags MONontemporalBit0
std::string utostr(uint64_t X, bool isNeg=false)
Target & getTheRISCV64beTarget()
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
LLVM_ABI void report_fatal_error(Error Err, bool gen_crash_diag=true)
Definition Error.cpp:163
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
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:1917
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:559
constexpr int64_t SignExtend64(uint64_t x)
Sign-extend the number in the bottom B bits of X to a 64-bit integer.
Definition MathExtras.h:572
@ MCSA_Weak
.weak
@ MCSA_ELF_TypeFunction
.type _foo, STT_FUNC # aka @function
@ MCSA_Hidden
.hidden (ELF)
Target & getTheRISCV32beTarget()
LLVM_ABI void reportFatalUsageError(Error Err)
Report a fatal error that does not indicate a bug in LLVM.
Definition Error.cpp:177
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:860
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...