xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (revision 525fe93dc7487a1e63a90f6a2b956abc601963c1)
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:
52   explicit RISCVAsmPrinter(TargetMachine &TM,
53                            std::unique_ptr<MCStreamer> Streamer)
54       : AsmPrinter(TM, std::move(Streamer)) {}
55 
56   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.
77   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 
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 
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 
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 
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 
190 bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
191   STI = &MF.getSubtarget<RISCVSubtarget>();
192 
193   SetupMachineFunction(MF);
194   emitFunctionBody();
195   return false;
196 }
197 
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 
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 
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 
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.
237 extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
238   RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
239   RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
240 }
241 
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 
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