1 //===-- RISCVAsmPrinter.cpp - RISCV 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 RISCV assembly language.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "MCTargetDesc/RISCVInstPrinter.h"
15 #include "MCTargetDesc/RISCVMCExpr.h"
16 #include "MCTargetDesc/RISCVTargetStreamer.h"
17 #include "RISCV.h"
18 #include "RISCVMachineFunctionInfo.h"
19 #include "RISCVTargetMachine.h"
20 #include "TargetInfo/RISCVTargetInfo.h"
21 #include "llvm/ADT/Statistic.h"
22 #include "llvm/BinaryFormat/ELF.h"
23 #include "llvm/CodeGen/AsmPrinter.h"
24 #include "llvm/CodeGen/MachineConstantPool.h"
25 #include "llvm/CodeGen/MachineFunctionPass.h"
26 #include "llvm/CodeGen/MachineInstr.h"
27 #include "llvm/CodeGen/MachineModuleInfo.h"
28 #include "llvm/MC/MCAsmInfo.h"
29 #include "llvm/MC/MCContext.h"
30 #include "llvm/MC/MCInst.h"
31 #include "llvm/MC/MCInstBuilder.h"
32 #include "llvm/MC/MCObjectFileInfo.h"
33 #include "llvm/MC/MCSectionELF.h"
34 #include "llvm/MC/MCStreamer.h"
35 #include "llvm/MC/MCSymbol.h"
36 #include "llvm/MC/TargetRegistry.h"
37 #include "llvm/Support/raw_ostream.h"
38 #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
39
40 using namespace llvm;
41
42 #define DEBUG_TYPE "asm-printer"
43
44 STATISTIC(RISCVNumInstrsCompressed,
45 "Number of RISC-V Compressed instructions emitted");
46
47 namespace {
48 class RISCVAsmPrinter : public AsmPrinter {
49 const RISCVSubtarget *STI;
50
51 public:
RISCVAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)52 explicit RISCVAsmPrinter(TargetMachine &TM,
53 std::unique_ptr<MCStreamer> Streamer)
54 : AsmPrinter(TM, std::move(Streamer)) {}
55
getPassName() const56 StringRef getPassName() const override { return "RISCV Assembly Printer"; }
57
58 bool runOnMachineFunction(MachineFunction &MF) override;
59
60 void emitInstruction(const MachineInstr *MI) override;
61
62 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
63 const char *ExtraCode, raw_ostream &OS) override;
64 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
65 const char *ExtraCode, raw_ostream &OS) override;
66
67 void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
68 bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
69 const MachineInstr *MI);
70
71 typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
72 std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
73 void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
74 void EmitHwasanMemaccessSymbols(Module &M);
75
76 // Wrapper needed for tblgenned pseudo lowering.
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const77 bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
78 return lowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
79 }
80
81 void emitStartOfAsmFile(Module &M) override;
82 void emitEndOfAsmFile(Module &M) override;
83
84 void emitFunctionEntryLabel() override;
85
86 private:
87 void emitAttributes();
88 };
89 }
90
EmitToStreamer(MCStreamer & S,const MCInst & Inst)91 void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
92 MCInst CInst;
93 bool Res = RISCVRVC::compress(CInst, Inst, *STI);
94 if (Res)
95 ++RISCVNumInstrsCompressed;
96 AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
97 }
98
99 // Simple pseudo-instructions have their lowering (with expansion to real
100 // instructions) auto-generated.
101 #include "RISCVGenMCPseudoLowering.inc"
102
emitInstruction(const MachineInstr * MI)103 void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
104 RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),
105 getSubtargetInfo().getFeatureBits());
106
107 // Do any auto-generated pseudo lowerings.
108 if (emitPseudoExpansionLowering(*OutStreamer, MI))
109 return;
110
111
112 switch (MI->getOpcode()) {
113 case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
114 LowerHWASAN_CHECK_MEMACCESS(*MI);
115 return;
116 }
117
118 MCInst TmpInst;
119 if (!lowerRISCVMachineInstrToMCInst(MI, TmpInst, *this))
120 EmitToStreamer(*OutStreamer, TmpInst);
121 }
122
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)123 bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
124 const char *ExtraCode, raw_ostream &OS) {
125 // First try the generic code, which knows about modifiers like 'c' and 'n'.
126 if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
127 return false;
128
129 const MachineOperand &MO = MI->getOperand(OpNo);
130 if (ExtraCode && ExtraCode[0]) {
131 if (ExtraCode[1] != 0)
132 return true; // Unknown modifier.
133
134 switch (ExtraCode[0]) {
135 default:
136 return true; // Unknown modifier.
137 case 'z': // Print zero register if zero, regular printing otherwise.
138 if (MO.isImm() && MO.getImm() == 0) {
139 OS << RISCVInstPrinter::getRegisterName(RISCV::X0);
140 return false;
141 }
142 break;
143 case 'i': // Literal 'i' if operand is not a register.
144 if (!MO.isReg())
145 OS << 'i';
146 return false;
147 }
148 }
149
150 switch (MO.getType()) {
151 case MachineOperand::MO_Immediate:
152 OS << MO.getImm();
153 return false;
154 case MachineOperand::MO_Register:
155 OS << RISCVInstPrinter::getRegisterName(MO.getReg());
156 return false;
157 case MachineOperand::MO_GlobalAddress:
158 PrintSymbolOperand(MO, OS);
159 return false;
160 case MachineOperand::MO_BlockAddress: {
161 MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
162 Sym->print(OS, MAI);
163 return false;
164 }
165 default:
166 break;
167 }
168
169 return true;
170 }
171
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)172 bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
173 unsigned OpNo,
174 const char *ExtraCode,
175 raw_ostream &OS) {
176 if (!ExtraCode) {
177 const MachineOperand &MO = MI->getOperand(OpNo);
178 // For now, we only support register memory operands in registers and
179 // assume there is no addend
180 if (!MO.isReg())
181 return true;
182
183 OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
184 return false;
185 }
186
187 return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
188 }
189
runOnMachineFunction(MachineFunction & MF)190 bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
191 STI = &MF.getSubtarget<RISCVSubtarget>();
192
193 SetupMachineFunction(MF);
194 emitFunctionBody();
195 return false;
196 }
197
emitStartOfAsmFile(Module & M)198 void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
199 RISCVTargetStreamer &RTS =
200 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
201 if (const MDString *ModuleTargetABI =
202 dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
203 RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
204 if (TM.getTargetTriple().isOSBinFormatELF())
205 emitAttributes();
206 }
207
emitEndOfAsmFile(Module & M)208 void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
209 RISCVTargetStreamer &RTS =
210 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
211
212 if (TM.getTargetTriple().isOSBinFormatELF())
213 RTS.finishAttributeSection();
214 EmitHwasanMemaccessSymbols(M);
215 }
216
emitAttributes()217 void RISCVAsmPrinter::emitAttributes() {
218 RISCVTargetStreamer &RTS =
219 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
220 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
221 // attributes that differ from other functions in the module and we have no
222 // way to know which function is correct.
223 RTS.emitTargetAttributes(*TM.getMCSubtargetInfo());
224 }
225
emitFunctionEntryLabel()226 void RISCVAsmPrinter::emitFunctionEntryLabel() {
227 const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
228 if (RMFI->isVectorCall()) {
229 auto &RTS =
230 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
231 RTS.emitDirectiveVariantCC(*CurrentFnSym);
232 }
233 return AsmPrinter::emitFunctionEntryLabel();
234 }
235
236 // Force static initialization.
LLVMInitializeRISCVAsmPrinter()237 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
238 RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
239 RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
240 }
241
LowerHWASAN_CHECK_MEMACCESS(const MachineInstr & MI)242 void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
243 Register Reg = MI.getOperand(0).getReg();
244 uint32_t AccessInfo = MI.getOperand(1).getImm();
245 MCSymbol *&Sym =
246 HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
247 if (!Sym) {
248 // FIXME: Make this work on non-ELF.
249 if (!TM.getTargetTriple().isOSBinFormatELF())
250 report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
251
252 std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
253 utostr(AccessInfo) + "_short";
254 Sym = OutContext.getOrCreateSymbol(SymName);
255 }
256 auto Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext);
257 auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);
258
259 EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
260 }
261
EmitHwasanMemaccessSymbols(Module & M)262 void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
263 if (HwasanMemaccessSymbols.empty())
264 return;
265
266 assert(TM.getTargetTriple().isOSBinFormatELF());
267 // Use MCSubtargetInfo from TargetMachine. Individual functions may have
268 // attributes that differ from other functions in the module and we have no
269 // way to know which function is correct.
270 const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
271
272 MCSymbol *HwasanTagMismatchV2Sym =
273 OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
274 // Annotate symbol as one having incompatible calling convention, so
275 // run-time linkers can instead eagerly bind this function.
276 auto &RTS =
277 static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
278 RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
279
280 const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
281 MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
282 auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,
283 RISCVMCExpr::VK_RISCV_CALL, OutContext);
284
285 for (auto &P : HwasanMemaccessSymbols) {
286 unsigned Reg = std::get<0>(P.first);
287 uint32_t AccessInfo = std::get<1>(P.first);
288 MCSymbol *Sym = P.second;
289
290 unsigned Size =
291 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
292 OutStreamer->switchSection(OutContext.getELFSection(
293 ".text.hot", ELF::SHT_PROGBITS,
294 ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
295 /*IsComdat=*/true));
296
297 OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
298 OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
299 OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
300 OutStreamer->emitLabel(Sym);
301
302 // Extract shadow offset from ptr
303 OutStreamer->emitInstruction(
304 MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
305 MCSTI);
306 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)
307 .addReg(RISCV::X6)
308 .addReg(RISCV::X6)
309 .addImm(12),
310 MCSTI);
311 // load shadow tag in X6, X5 contains shadow base
312 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)
313 .addReg(RISCV::X6)
314 .addReg(RISCV::X5)
315 .addReg(RISCV::X6),
316 MCSTI);
317 OutStreamer->emitInstruction(
318 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
319 MCSTI);
320 // Extract tag from X5 and compare it with loaded tag from shadow
321 OutStreamer->emitInstruction(
322 MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
323 MCSTI);
324 MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
325 // X7 contains tag from memory, while X6 contains tag from the pointer
326 OutStreamer->emitInstruction(
327 MCInstBuilder(RISCV::BNE)
328 .addReg(RISCV::X7)
329 .addReg(RISCV::X6)
330 .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
331 OutContext)),
332 MCSTI);
333 MCSymbol *ReturnSym = OutContext.createTempSymbol();
334 OutStreamer->emitLabel(ReturnSym);
335 OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)
336 .addReg(RISCV::X0)
337 .addReg(RISCV::X1)
338 .addImm(0),
339 MCSTI);
340 OutStreamer->emitLabel(HandleMismatchOrPartialSym);
341
342 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
343 .addReg(RISCV::X28)
344 .addReg(RISCV::X0)
345 .addImm(16),
346 MCSTI);
347 MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
348 OutStreamer->emitInstruction(
349 MCInstBuilder(RISCV::BGEU)
350 .addReg(RISCV::X6)
351 .addReg(RISCV::X28)
352 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
353 MCSTI);
354
355 OutStreamer->emitInstruction(
356 MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
357 MCSTI);
358
359 if (Size != 1)
360 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
361 .addReg(RISCV::X28)
362 .addReg(RISCV::X28)
363 .addImm(Size - 1),
364 MCSTI);
365 OutStreamer->emitInstruction(
366 MCInstBuilder(RISCV::BGE)
367 .addReg(RISCV::X28)
368 .addReg(RISCV::X6)
369 .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
370 MCSTI);
371
372 OutStreamer->emitInstruction(
373 MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
374 MCSTI);
375 OutStreamer->emitInstruction(
376 MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
377 MCSTI);
378 OutStreamer->emitInstruction(
379 MCInstBuilder(RISCV::BEQ)
380 .addReg(RISCV::X6)
381 .addReg(RISCV::X7)
382 .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
383 MCSTI);
384
385 OutStreamer->emitLabel(HandleMismatchSym);
386
387 // | Previous stack frames... |
388 // +=================================+ <-- [SP + 256]
389 // | ... |
390 // | |
391 // | Stack frame space for x12 - x31.|
392 // | |
393 // | ... |
394 // +---------------------------------+ <-- [SP + 96]
395 // | Saved x11(arg1), as |
396 // | __hwasan_check_* clobbers it. |
397 // +---------------------------------+ <-- [SP + 88]
398 // | Saved x10(arg0), as |
399 // | __hwasan_check_* clobbers it. |
400 // +---------------------------------+ <-- [SP + 80]
401 // | |
402 // | Stack frame space for x9. |
403 // +---------------------------------+ <-- [SP + 72]
404 // | |
405 // | Saved x8(fp), as |
406 // | __hwasan_check_* clobbers it. |
407 // +---------------------------------+ <-- [SP + 64]
408 // | ... |
409 // | |
410 // | Stack frame space for x2 - x7. |
411 // | |
412 // | ... |
413 // +---------------------------------+ <-- [SP + 16]
414 // | Return address (x1) for caller |
415 // | of __hwasan_check_*. |
416 // +---------------------------------+ <-- [SP + 8]
417 // | Reserved place for x0, possibly |
418 // | junk, since we don't save it. |
419 // +---------------------------------+ <-- [x2 / SP]
420
421 // Adjust sp
422 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
423 .addReg(RISCV::X2)
424 .addReg(RISCV::X2)
425 .addImm(-256),
426 MCSTI);
427
428 // store x10(arg0) by new sp
429 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
430 .addReg(RISCV::X10)
431 .addReg(RISCV::X2)
432 .addImm(8 * 10),
433 MCSTI);
434 // store x11(arg1) by new sp
435 OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
436 .addReg(RISCV::X11)
437 .addReg(RISCV::X2)
438 .addImm(8 * 11),
439 MCSTI);
440
441 // store x8(fp) by new sp
442 OutStreamer->emitInstruction(
443 MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
444 8),
445 MCSTI);
446 // store x1(ra) by new sp
447 OutStreamer->emitInstruction(
448 MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
449 8),
450 MCSTI);
451 if (Reg != RISCV::X10)
452 OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
453 .addReg(RISCV::X10)
454 .addReg(Reg)
455 .addImm(0),
456 MCSTI);
457 OutStreamer->emitInstruction(
458 MCInstBuilder(RISCV::ADDI)
459 .addReg(RISCV::X11)
460 .addReg(RISCV::X0)
461 .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),
462 MCSTI);
463
464 OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
465 MCSTI);
466 }
467 }
468