xref: /openbsd-src/gnu/llvm/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (revision d415bd752c734aee168c4ee86ff32e8cc249eb16)
109467b48Spatrick //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains a printer that converts from our internal representation
1009467b48Spatrick // of machine-dependent LLVM code to the RISCV assembly language.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick 
1409467b48Spatrick #include "MCTargetDesc/RISCVInstPrinter.h"
1509467b48Spatrick #include "MCTargetDesc/RISCVMCExpr.h"
16097a140dSpatrick #include "MCTargetDesc/RISCVTargetStreamer.h"
17097a140dSpatrick #include "RISCV.h"
18*d415bd75Srobert #include "RISCVMachineFunctionInfo.h"
1909467b48Spatrick #include "RISCVTargetMachine.h"
2009467b48Spatrick #include "TargetInfo/RISCVTargetInfo.h"
2109467b48Spatrick #include "llvm/ADT/Statistic.h"
22*d415bd75Srobert #include "llvm/BinaryFormat/ELF.h"
2309467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
2409467b48Spatrick #include "llvm/CodeGen/MachineConstantPool.h"
2509467b48Spatrick #include "llvm/CodeGen/MachineFunctionPass.h"
2609467b48Spatrick #include "llvm/CodeGen/MachineInstr.h"
2709467b48Spatrick #include "llvm/CodeGen/MachineModuleInfo.h"
2809467b48Spatrick #include "llvm/MC/MCAsmInfo.h"
29*d415bd75Srobert #include "llvm/MC/MCContext.h"
3009467b48Spatrick #include "llvm/MC/MCInst.h"
31*d415bd75Srobert #include "llvm/MC/MCInstBuilder.h"
32*d415bd75Srobert #include "llvm/MC/MCObjectFileInfo.h"
33*d415bd75Srobert #include "llvm/MC/MCSectionELF.h"
3409467b48Spatrick #include "llvm/MC/MCStreamer.h"
3509467b48Spatrick #include "llvm/MC/MCSymbol.h"
36*d415bd75Srobert #include "llvm/MC/TargetRegistry.h"
3709467b48Spatrick #include "llvm/Support/raw_ostream.h"
38*d415bd75Srobert #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
39*d415bd75Srobert 
4009467b48Spatrick using namespace llvm;
4109467b48Spatrick 
4209467b48Spatrick #define DEBUG_TYPE "asm-printer"
4309467b48Spatrick 
4409467b48Spatrick STATISTIC(RISCVNumInstrsCompressed,
4509467b48Spatrick           "Number of RISC-V Compressed instructions emitted");
4609467b48Spatrick 
4709467b48Spatrick namespace {
4809467b48Spatrick class RISCVAsmPrinter : public AsmPrinter {
49*d415bd75Srobert   const RISCVSubtarget *STI;
50097a140dSpatrick 
5109467b48Spatrick public:
RISCVAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)5209467b48Spatrick   explicit RISCVAsmPrinter(TargetMachine &TM,
5309467b48Spatrick                            std::unique_ptr<MCStreamer> Streamer)
54*d415bd75Srobert       : AsmPrinter(TM, std::move(Streamer)) {}
5509467b48Spatrick 
getPassName() const5609467b48Spatrick   StringRef getPassName() const override { return "RISCV Assembly Printer"; }
5709467b48Spatrick 
58097a140dSpatrick   bool runOnMachineFunction(MachineFunction &MF) override;
59097a140dSpatrick 
60097a140dSpatrick   void emitInstruction(const MachineInstr *MI) override;
6109467b48Spatrick 
6209467b48Spatrick   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
6309467b48Spatrick                        const char *ExtraCode, raw_ostream &OS) override;
6409467b48Spatrick   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
6509467b48Spatrick                              const char *ExtraCode, raw_ostream &OS) override;
6609467b48Spatrick 
6709467b48Spatrick   void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
6809467b48Spatrick   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
6909467b48Spatrick                                    const MachineInstr *MI);
7009467b48Spatrick 
71*d415bd75Srobert   typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
72*d415bd75Srobert   std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
73*d415bd75Srobert   void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
74*d415bd75Srobert   void EmitHwasanMemaccessSymbols(Module &M);
75*d415bd75Srobert 
7609467b48Spatrick   // Wrapper needed for tblgenned pseudo lowering.
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const7709467b48Spatrick   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
78*d415bd75Srobert     return lowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
7909467b48Spatrick   }
80097a140dSpatrick 
81097a140dSpatrick   void emitStartOfAsmFile(Module &M) override;
82097a140dSpatrick   void emitEndOfAsmFile(Module &M) override;
83097a140dSpatrick 
84*d415bd75Srobert   void emitFunctionEntryLabel() override;
85*d415bd75Srobert 
86097a140dSpatrick private:
87097a140dSpatrick   void emitAttributes();
8809467b48Spatrick };
8909467b48Spatrick }
9009467b48Spatrick 
EmitToStreamer(MCStreamer & S,const MCInst & Inst)9109467b48Spatrick void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
9209467b48Spatrick   MCInst CInst;
93*d415bd75Srobert   bool Res = RISCVRVC::compress(CInst, Inst, *STI);
9409467b48Spatrick   if (Res)
9509467b48Spatrick     ++RISCVNumInstrsCompressed;
9609467b48Spatrick   AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
9709467b48Spatrick }
9809467b48Spatrick 
9909467b48Spatrick // Simple pseudo-instructions have their lowering (with expansion to real
10009467b48Spatrick // instructions) auto-generated.
10109467b48Spatrick #include "RISCVGenMCPseudoLowering.inc"
10209467b48Spatrick 
emitInstruction(const MachineInstr * MI)103097a140dSpatrick void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
104*d415bd75Srobert   RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),
105*d415bd75Srobert                                         getSubtargetInfo().getFeatureBits());
106*d415bd75Srobert 
10709467b48Spatrick   // Do any auto-generated pseudo lowerings.
10809467b48Spatrick   if (emitPseudoExpansionLowering(*OutStreamer, MI))
10909467b48Spatrick     return;
11009467b48Spatrick 
111*d415bd75Srobert 
112*d415bd75Srobert   switch (MI->getOpcode()) {
113*d415bd75Srobert   case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
114*d415bd75Srobert     LowerHWASAN_CHECK_MEMACCESS(*MI);
115*d415bd75Srobert     return;
116*d415bd75Srobert   }
117*d415bd75Srobert 
11809467b48Spatrick   MCInst TmpInst;
11973471bf0Spatrick   if (!lowerRISCVMachineInstrToMCInst(MI, TmpInst, *this))
12009467b48Spatrick     EmitToStreamer(*OutStreamer, TmpInst);
12109467b48Spatrick }
12209467b48Spatrick 
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)12309467b48Spatrick bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
12409467b48Spatrick                                       const char *ExtraCode, raw_ostream &OS) {
12509467b48Spatrick   // First try the generic code, which knows about modifiers like 'c' and 'n'.
12609467b48Spatrick   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
12709467b48Spatrick     return false;
12809467b48Spatrick 
12909467b48Spatrick   const MachineOperand &MO = MI->getOperand(OpNo);
13009467b48Spatrick   if (ExtraCode && ExtraCode[0]) {
13109467b48Spatrick     if (ExtraCode[1] != 0)
13209467b48Spatrick       return true; // Unknown modifier.
13309467b48Spatrick 
13409467b48Spatrick     switch (ExtraCode[0]) {
13509467b48Spatrick     default:
13609467b48Spatrick       return true; // Unknown modifier.
13709467b48Spatrick     case 'z':      // Print zero register if zero, regular printing otherwise.
13809467b48Spatrick       if (MO.isImm() && MO.getImm() == 0) {
13909467b48Spatrick         OS << RISCVInstPrinter::getRegisterName(RISCV::X0);
14009467b48Spatrick         return false;
14109467b48Spatrick       }
14209467b48Spatrick       break;
14309467b48Spatrick     case 'i': // Literal 'i' if operand is not a register.
14409467b48Spatrick       if (!MO.isReg())
14509467b48Spatrick         OS << 'i';
14609467b48Spatrick       return false;
14709467b48Spatrick     }
14809467b48Spatrick   }
14909467b48Spatrick 
15009467b48Spatrick   switch (MO.getType()) {
15109467b48Spatrick   case MachineOperand::MO_Immediate:
15209467b48Spatrick     OS << MO.getImm();
15309467b48Spatrick     return false;
15409467b48Spatrick   case MachineOperand::MO_Register:
15509467b48Spatrick     OS << RISCVInstPrinter::getRegisterName(MO.getReg());
15609467b48Spatrick     return false;
15709467b48Spatrick   case MachineOperand::MO_GlobalAddress:
15809467b48Spatrick     PrintSymbolOperand(MO, OS);
15909467b48Spatrick     return false;
16009467b48Spatrick   case MachineOperand::MO_BlockAddress: {
16109467b48Spatrick     MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
16209467b48Spatrick     Sym->print(OS, MAI);
16309467b48Spatrick     return false;
16409467b48Spatrick   }
16509467b48Spatrick   default:
16609467b48Spatrick     break;
16709467b48Spatrick   }
16809467b48Spatrick 
16909467b48Spatrick   return true;
17009467b48Spatrick }
17109467b48Spatrick 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)17209467b48Spatrick bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
17309467b48Spatrick                                             unsigned OpNo,
17409467b48Spatrick                                             const char *ExtraCode,
17509467b48Spatrick                                             raw_ostream &OS) {
17609467b48Spatrick   if (!ExtraCode) {
17709467b48Spatrick     const MachineOperand &MO = MI->getOperand(OpNo);
17809467b48Spatrick     // For now, we only support register memory operands in registers and
17909467b48Spatrick     // assume there is no addend
18009467b48Spatrick     if (!MO.isReg())
18109467b48Spatrick       return true;
18209467b48Spatrick 
18309467b48Spatrick     OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
18409467b48Spatrick     return false;
18509467b48Spatrick   }
18609467b48Spatrick 
18709467b48Spatrick   return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
18809467b48Spatrick }
18909467b48Spatrick 
runOnMachineFunction(MachineFunction & MF)190097a140dSpatrick bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
191*d415bd75Srobert   STI = &MF.getSubtarget<RISCVSubtarget>();
192097a140dSpatrick 
193097a140dSpatrick   SetupMachineFunction(MF);
194097a140dSpatrick   emitFunctionBody();
195097a140dSpatrick   return false;
196097a140dSpatrick }
197097a140dSpatrick 
emitStartOfAsmFile(Module & M)198097a140dSpatrick void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
199*d415bd75Srobert   RISCVTargetStreamer &RTS =
200*d415bd75Srobert       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
201*d415bd75Srobert   if (const MDString *ModuleTargetABI =
202*d415bd75Srobert           dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
203*d415bd75Srobert     RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
204097a140dSpatrick   if (TM.getTargetTriple().isOSBinFormatELF())
205097a140dSpatrick     emitAttributes();
206097a140dSpatrick }
207097a140dSpatrick 
emitEndOfAsmFile(Module & M)208097a140dSpatrick void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
209097a140dSpatrick   RISCVTargetStreamer &RTS =
210097a140dSpatrick       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
211097a140dSpatrick 
212097a140dSpatrick   if (TM.getTargetTriple().isOSBinFormatELF())
213097a140dSpatrick     RTS.finishAttributeSection();
214*d415bd75Srobert   EmitHwasanMemaccessSymbols(M);
215097a140dSpatrick }
216097a140dSpatrick 
emitAttributes()217097a140dSpatrick void RISCVAsmPrinter::emitAttributes() {
218097a140dSpatrick   RISCVTargetStreamer &RTS =
219097a140dSpatrick       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
220*d415bd75Srobert   // Use MCSubtargetInfo from TargetMachine. Individual functions may have
221*d415bd75Srobert   // attributes that differ from other functions in the module and we have no
222*d415bd75Srobert   // way to know which function is correct.
223*d415bd75Srobert   RTS.emitTargetAttributes(*TM.getMCSubtargetInfo());
224*d415bd75Srobert }
225*d415bd75Srobert 
emitFunctionEntryLabel()226*d415bd75Srobert void RISCVAsmPrinter::emitFunctionEntryLabel() {
227*d415bd75Srobert   const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
228*d415bd75Srobert   if (RMFI->isVectorCall()) {
229*d415bd75Srobert     auto &RTS =
230*d415bd75Srobert         static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
231*d415bd75Srobert     RTS.emitDirectiveVariantCC(*CurrentFnSym);
232*d415bd75Srobert   }
233*d415bd75Srobert   return AsmPrinter::emitFunctionEntryLabel();
234097a140dSpatrick }
235097a140dSpatrick 
23609467b48Spatrick // Force static initialization.
LLVMInitializeRISCVAsmPrinter()23709467b48Spatrick extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
23809467b48Spatrick   RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
23909467b48Spatrick   RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
24009467b48Spatrick }
241*d415bd75Srobert 
LowerHWASAN_CHECK_MEMACCESS(const MachineInstr & MI)242*d415bd75Srobert void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
243*d415bd75Srobert   Register Reg = MI.getOperand(0).getReg();
244*d415bd75Srobert   uint32_t AccessInfo = MI.getOperand(1).getImm();
245*d415bd75Srobert   MCSymbol *&Sym =
246*d415bd75Srobert       HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
247*d415bd75Srobert   if (!Sym) {
248*d415bd75Srobert     // FIXME: Make this work on non-ELF.
249*d415bd75Srobert     if (!TM.getTargetTriple().isOSBinFormatELF())
250*d415bd75Srobert       report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
251*d415bd75Srobert 
252*d415bd75Srobert     std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
253*d415bd75Srobert                           utostr(AccessInfo) + "_short";
254*d415bd75Srobert     Sym = OutContext.getOrCreateSymbol(SymName);
255*d415bd75Srobert   }
256*d415bd75Srobert   auto Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext);
257*d415bd75Srobert   auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);
258*d415bd75Srobert 
259*d415bd75Srobert   EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
260*d415bd75Srobert }
261*d415bd75Srobert 
EmitHwasanMemaccessSymbols(Module & M)262*d415bd75Srobert void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
263*d415bd75Srobert   if (HwasanMemaccessSymbols.empty())
264*d415bd75Srobert     return;
265*d415bd75Srobert 
266*d415bd75Srobert   assert(TM.getTargetTriple().isOSBinFormatELF());
267*d415bd75Srobert   // Use MCSubtargetInfo from TargetMachine. Individual functions may have
268*d415bd75Srobert   // attributes that differ from other functions in the module and we have no
269*d415bd75Srobert   // way to know which function is correct.
270*d415bd75Srobert   const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
271*d415bd75Srobert 
272*d415bd75Srobert   MCSymbol *HwasanTagMismatchV2Sym =
273*d415bd75Srobert       OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
274*d415bd75Srobert   // Annotate symbol as one having incompatible calling convention, so
275*d415bd75Srobert   // run-time linkers can instead eagerly bind this function.
276*d415bd75Srobert   auto &RTS =
277*d415bd75Srobert       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
278*d415bd75Srobert   RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
279*d415bd75Srobert 
280*d415bd75Srobert   const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
281*d415bd75Srobert       MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
282*d415bd75Srobert   auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,
283*d415bd75Srobert                                   RISCVMCExpr::VK_RISCV_CALL, OutContext);
284*d415bd75Srobert 
285*d415bd75Srobert   for (auto &P : HwasanMemaccessSymbols) {
286*d415bd75Srobert     unsigned Reg = std::get<0>(P.first);
287*d415bd75Srobert     uint32_t AccessInfo = std::get<1>(P.first);
288*d415bd75Srobert     MCSymbol *Sym = P.second;
289*d415bd75Srobert 
290*d415bd75Srobert     unsigned Size =
291*d415bd75Srobert         1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
292*d415bd75Srobert     OutStreamer->switchSection(OutContext.getELFSection(
293*d415bd75Srobert         ".text.hot", ELF::SHT_PROGBITS,
294*d415bd75Srobert         ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
295*d415bd75Srobert         /*IsComdat=*/true));
296*d415bd75Srobert 
297*d415bd75Srobert     OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
298*d415bd75Srobert     OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
299*d415bd75Srobert     OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
300*d415bd75Srobert     OutStreamer->emitLabel(Sym);
301*d415bd75Srobert 
302*d415bd75Srobert     // Extract shadow offset from ptr
303*d415bd75Srobert     OutStreamer->emitInstruction(
304*d415bd75Srobert         MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
305*d415bd75Srobert         MCSTI);
306*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)
307*d415bd75Srobert                                      .addReg(RISCV::X6)
308*d415bd75Srobert                                      .addReg(RISCV::X6)
309*d415bd75Srobert                                      .addImm(12),
310*d415bd75Srobert                                  MCSTI);
311*d415bd75Srobert     // load shadow tag in X6, X5 contains shadow base
312*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)
313*d415bd75Srobert                                      .addReg(RISCV::X6)
314*d415bd75Srobert                                      .addReg(RISCV::X5)
315*d415bd75Srobert                                      .addReg(RISCV::X6),
316*d415bd75Srobert                                  MCSTI);
317*d415bd75Srobert     OutStreamer->emitInstruction(
318*d415bd75Srobert         MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
319*d415bd75Srobert         MCSTI);
320*d415bd75Srobert     // Extract tag from X5 and compare it with loaded tag from shadow
321*d415bd75Srobert     OutStreamer->emitInstruction(
322*d415bd75Srobert         MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
323*d415bd75Srobert         MCSTI);
324*d415bd75Srobert     MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
325*d415bd75Srobert     // X7 contains tag from memory, while X6 contains tag from the pointer
326*d415bd75Srobert     OutStreamer->emitInstruction(
327*d415bd75Srobert         MCInstBuilder(RISCV::BNE)
328*d415bd75Srobert             .addReg(RISCV::X7)
329*d415bd75Srobert             .addReg(RISCV::X6)
330*d415bd75Srobert             .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
331*d415bd75Srobert                                              OutContext)),
332*d415bd75Srobert         MCSTI);
333*d415bd75Srobert     MCSymbol *ReturnSym = OutContext.createTempSymbol();
334*d415bd75Srobert     OutStreamer->emitLabel(ReturnSym);
335*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)
336*d415bd75Srobert                                      .addReg(RISCV::X0)
337*d415bd75Srobert                                      .addReg(RISCV::X1)
338*d415bd75Srobert                                      .addImm(0),
339*d415bd75Srobert                                  MCSTI);
340*d415bd75Srobert     OutStreamer->emitLabel(HandleMismatchOrPartialSym);
341*d415bd75Srobert 
342*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
343*d415bd75Srobert                                      .addReg(RISCV::X28)
344*d415bd75Srobert                                      .addReg(RISCV::X0)
345*d415bd75Srobert                                      .addImm(16),
346*d415bd75Srobert                                  MCSTI);
347*d415bd75Srobert     MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
348*d415bd75Srobert     OutStreamer->emitInstruction(
349*d415bd75Srobert         MCInstBuilder(RISCV::BGEU)
350*d415bd75Srobert             .addReg(RISCV::X6)
351*d415bd75Srobert             .addReg(RISCV::X28)
352*d415bd75Srobert             .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
353*d415bd75Srobert         MCSTI);
354*d415bd75Srobert 
355*d415bd75Srobert     OutStreamer->emitInstruction(
356*d415bd75Srobert         MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
357*d415bd75Srobert         MCSTI);
358*d415bd75Srobert 
359*d415bd75Srobert     if (Size != 1)
360*d415bd75Srobert       OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
361*d415bd75Srobert                                        .addReg(RISCV::X28)
362*d415bd75Srobert                                        .addReg(RISCV::X28)
363*d415bd75Srobert                                        .addImm(Size - 1),
364*d415bd75Srobert                                    MCSTI);
365*d415bd75Srobert     OutStreamer->emitInstruction(
366*d415bd75Srobert         MCInstBuilder(RISCV::BGE)
367*d415bd75Srobert             .addReg(RISCV::X28)
368*d415bd75Srobert             .addReg(RISCV::X6)
369*d415bd75Srobert             .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
370*d415bd75Srobert         MCSTI);
371*d415bd75Srobert 
372*d415bd75Srobert     OutStreamer->emitInstruction(
373*d415bd75Srobert         MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
374*d415bd75Srobert         MCSTI);
375*d415bd75Srobert     OutStreamer->emitInstruction(
376*d415bd75Srobert         MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
377*d415bd75Srobert         MCSTI);
378*d415bd75Srobert     OutStreamer->emitInstruction(
379*d415bd75Srobert         MCInstBuilder(RISCV::BEQ)
380*d415bd75Srobert             .addReg(RISCV::X6)
381*d415bd75Srobert             .addReg(RISCV::X7)
382*d415bd75Srobert             .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
383*d415bd75Srobert         MCSTI);
384*d415bd75Srobert 
385*d415bd75Srobert     OutStreamer->emitLabel(HandleMismatchSym);
386*d415bd75Srobert 
387*d415bd75Srobert     // | Previous stack frames...        |
388*d415bd75Srobert     // +=================================+ <-- [SP + 256]
389*d415bd75Srobert     // |              ...                |
390*d415bd75Srobert     // |                                 |
391*d415bd75Srobert     // | Stack frame space for x12 - x31.|
392*d415bd75Srobert     // |                                 |
393*d415bd75Srobert     // |              ...                |
394*d415bd75Srobert     // +---------------------------------+ <-- [SP + 96]
395*d415bd75Srobert     // | Saved x11(arg1), as             |
396*d415bd75Srobert     // | __hwasan_check_* clobbers it.   |
397*d415bd75Srobert     // +---------------------------------+ <-- [SP + 88]
398*d415bd75Srobert     // | Saved x10(arg0), as             |
399*d415bd75Srobert     // | __hwasan_check_* clobbers it.   |
400*d415bd75Srobert     // +---------------------------------+ <-- [SP + 80]
401*d415bd75Srobert     // |                                 |
402*d415bd75Srobert     // | Stack frame space for x9.       |
403*d415bd75Srobert     // +---------------------------------+ <-- [SP + 72]
404*d415bd75Srobert     // |                                 |
405*d415bd75Srobert     // | Saved x8(fp), as                |
406*d415bd75Srobert     // | __hwasan_check_* clobbers it.   |
407*d415bd75Srobert     // +---------------------------------+ <-- [SP + 64]
408*d415bd75Srobert     // |              ...                |
409*d415bd75Srobert     // |                                 |
410*d415bd75Srobert     // | Stack frame space for x2 - x7.  |
411*d415bd75Srobert     // |                                 |
412*d415bd75Srobert     // |              ...                |
413*d415bd75Srobert     // +---------------------------------+ <-- [SP + 16]
414*d415bd75Srobert     // | Return address (x1) for caller  |
415*d415bd75Srobert     // | of __hwasan_check_*.            |
416*d415bd75Srobert     // +---------------------------------+ <-- [SP + 8]
417*d415bd75Srobert     // | Reserved place for x0, possibly |
418*d415bd75Srobert     // | junk, since we don't save it.   |
419*d415bd75Srobert     // +---------------------------------+ <-- [x2 / SP]
420*d415bd75Srobert 
421*d415bd75Srobert     // Adjust sp
422*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
423*d415bd75Srobert                                      .addReg(RISCV::X2)
424*d415bd75Srobert                                      .addReg(RISCV::X2)
425*d415bd75Srobert                                      .addImm(-256),
426*d415bd75Srobert                                  MCSTI);
427*d415bd75Srobert 
428*d415bd75Srobert     // store x10(arg0) by new sp
429*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
430*d415bd75Srobert                                      .addReg(RISCV::X10)
431*d415bd75Srobert                                      .addReg(RISCV::X2)
432*d415bd75Srobert                                      .addImm(8 * 10),
433*d415bd75Srobert                                  MCSTI);
434*d415bd75Srobert     // store x11(arg1) by new sp
435*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
436*d415bd75Srobert                                      .addReg(RISCV::X11)
437*d415bd75Srobert                                      .addReg(RISCV::X2)
438*d415bd75Srobert                                      .addImm(8 * 11),
439*d415bd75Srobert                                  MCSTI);
440*d415bd75Srobert 
441*d415bd75Srobert     // store x8(fp) by new sp
442*d415bd75Srobert     OutStreamer->emitInstruction(
443*d415bd75Srobert         MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
444*d415bd75Srobert                                                                             8),
445*d415bd75Srobert         MCSTI);
446*d415bd75Srobert     // store x1(ra) by new sp
447*d415bd75Srobert     OutStreamer->emitInstruction(
448*d415bd75Srobert         MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
449*d415bd75Srobert                                                                             8),
450*d415bd75Srobert         MCSTI);
451*d415bd75Srobert     if (Reg != RISCV::X10)
452*d415bd75Srobert       OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
453*d415bd75Srobert                                        .addReg(RISCV::X10)
454*d415bd75Srobert                                        .addReg(Reg)
455*d415bd75Srobert                                        .addImm(0),
456*d415bd75Srobert                                    MCSTI);
457*d415bd75Srobert     OutStreamer->emitInstruction(
458*d415bd75Srobert         MCInstBuilder(RISCV::ADDI)
459*d415bd75Srobert             .addReg(RISCV::X11)
460*d415bd75Srobert             .addReg(RISCV::X0)
461*d415bd75Srobert             .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),
462*d415bd75Srobert         MCSTI);
463*d415bd75Srobert 
464*d415bd75Srobert     OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
465*d415bd75Srobert                                  MCSTI);
466*d415bd75Srobert   }
467*d415bd75Srobert }
468