xref: /freebsd/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===-- RISCVAsmPrinter.cpp - RISC-V LLVM assembly writer -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file contains a printer that converts from our internal representation
1006c3fb27SDimitry Andric // of machine-dependent LLVM code to the RISC-V assembly language.
110b57cec5SDimitry Andric //
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
1406c3fb27SDimitry Andric #include "MCTargetDesc/RISCVBaseInfo.h"
150b57cec5SDimitry Andric #include "MCTargetDesc/RISCVInstPrinter.h"
160b57cec5SDimitry Andric #include "MCTargetDesc/RISCVMCExpr.h"
17*0fca6ea1SDimitry Andric #include "MCTargetDesc/RISCVMatInt.h"
185ffd83dbSDimitry Andric #include "MCTargetDesc/RISCVTargetStreamer.h"
195ffd83dbSDimitry Andric #include "RISCV.h"
20bdd1243dSDimitry Andric #include "RISCVMachineFunctionInfo.h"
210b57cec5SDimitry Andric #include "RISCVTargetMachine.h"
220b57cec5SDimitry Andric #include "TargetInfo/RISCVTargetInfo.h"
2306c3fb27SDimitry Andric #include "llvm/ADT/APInt.h"
24480093f4SDimitry Andric #include "llvm/ADT/Statistic.h"
25bdd1243dSDimitry Andric #include "llvm/BinaryFormat/ELF.h"
260b57cec5SDimitry Andric #include "llvm/CodeGen/AsmPrinter.h"
270b57cec5SDimitry Andric #include "llvm/CodeGen/MachineConstantPool.h"
280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineModuleInfo.h"
31*0fca6ea1SDimitry Andric #include "llvm/IR/Module.h"
320b57cec5SDimitry Andric #include "llvm/MC/MCAsmInfo.h"
33bdd1243dSDimitry Andric #include "llvm/MC/MCContext.h"
340b57cec5SDimitry Andric #include "llvm/MC/MCInst.h"
35bdd1243dSDimitry Andric #include "llvm/MC/MCInstBuilder.h"
36bdd1243dSDimitry Andric #include "llvm/MC/MCObjectFileInfo.h"
37bdd1243dSDimitry Andric #include "llvm/MC/MCSectionELF.h"
380b57cec5SDimitry Andric #include "llvm/MC/MCStreamer.h"
390b57cec5SDimitry Andric #include "llvm/MC/MCSymbol.h"
40349cc55cSDimitry Andric #include "llvm/MC/TargetRegistry.h"
410b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
42*0fca6ea1SDimitry Andric #include "llvm/TargetParser/RISCVISAInfo.h"
43bdd1243dSDimitry Andric #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
44bdd1243dSDimitry Andric 
450b57cec5SDimitry Andric using namespace llvm;
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric #define DEBUG_TYPE "asm-printer"
480b57cec5SDimitry Andric 
49480093f4SDimitry Andric STATISTIC(RISCVNumInstrsCompressed,
50480093f4SDimitry Andric           "Number of RISC-V Compressed instructions emitted");
51480093f4SDimitry Andric 
525f757f3fSDimitry Andric namespace llvm {
535f757f3fSDimitry Andric extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];
545f757f3fSDimitry Andric } // namespace llvm
555f757f3fSDimitry Andric 
560b57cec5SDimitry Andric namespace {
570b57cec5SDimitry Andric class RISCVAsmPrinter : public AsmPrinter {
5881ad6265SDimitry Andric   const RISCVSubtarget *STI;
595ffd83dbSDimitry Andric 
600b57cec5SDimitry Andric public:
RISCVAsmPrinter(TargetMachine & TM,std::unique_ptr<MCStreamer> Streamer)610b57cec5SDimitry Andric   explicit RISCVAsmPrinter(TargetMachine &TM,
620b57cec5SDimitry Andric                            std::unique_ptr<MCStreamer> Streamer)
63bdd1243dSDimitry Andric       : AsmPrinter(TM, std::move(Streamer)) {}
640b57cec5SDimitry Andric 
getPassName() const6506c3fb27SDimitry Andric   StringRef getPassName() const override { return "RISC-V Assembly Printer"; }
660b57cec5SDimitry Andric 
675f757f3fSDimitry Andric   void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
685f757f3fSDimitry Andric                      const MachineInstr &MI);
695f757f3fSDimitry Andric 
705f757f3fSDimitry Andric   void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
715f757f3fSDimitry Andric                        const MachineInstr &MI);
725f757f3fSDimitry Andric 
735f757f3fSDimitry Andric   void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
745f757f3fSDimitry Andric                        const MachineInstr &MI);
755f757f3fSDimitry Andric 
765ffd83dbSDimitry Andric   bool runOnMachineFunction(MachineFunction &MF) override;
775ffd83dbSDimitry Andric 
785ffd83dbSDimitry Andric   void emitInstruction(const MachineInstr *MI) override;
790b57cec5SDimitry Andric 
800b57cec5SDimitry Andric   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
810b57cec5SDimitry Andric                        const char *ExtraCode, raw_ostream &OS) override;
820b57cec5SDimitry Andric   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
830b57cec5SDimitry Andric                              const char *ExtraCode, raw_ostream &OS) override;
840b57cec5SDimitry Andric 
85*0fca6ea1SDimitry Andric   // Returns whether Inst is compressed.
86*0fca6ea1SDimitry Andric   bool EmitToStreamer(MCStreamer &S, const MCInst &Inst);
870b57cec5SDimitry Andric   bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
880b57cec5SDimitry Andric                                    const MachineInstr *MI);
890b57cec5SDimitry Andric 
90bdd1243dSDimitry Andric   typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
91bdd1243dSDimitry Andric   std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
92bdd1243dSDimitry Andric   void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
9306c3fb27SDimitry Andric   void LowerKCFI_CHECK(const MachineInstr &MI);
94bdd1243dSDimitry Andric   void EmitHwasanMemaccessSymbols(Module &M);
95bdd1243dSDimitry Andric 
960b57cec5SDimitry Andric   // Wrapper needed for tblgenned pseudo lowering.
9706c3fb27SDimitry Andric   bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;
985ffd83dbSDimitry Andric 
995ffd83dbSDimitry Andric   void emitStartOfAsmFile(Module &M) override;
1005ffd83dbSDimitry Andric   void emitEndOfAsmFile(Module &M) override;
1015ffd83dbSDimitry Andric 
10281ad6265SDimitry Andric   void emitFunctionEntryLabel() override;
1035f757f3fSDimitry Andric   bool emitDirectiveOptionArch();
10481ad6265SDimitry Andric 
1055ffd83dbSDimitry Andric private:
1063a079333SDimitry Andric   void emitAttributes(const MCSubtargetInfo &SubtargetInfo);
10706c3fb27SDimitry Andric 
10806c3fb27SDimitry Andric   void emitNTLHint(const MachineInstr *MI);
10906c3fb27SDimitry Andric 
11006c3fb27SDimitry Andric   bool lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);
1110b57cec5SDimitry Andric };
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric 
LowerSTACKMAP(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)1145f757f3fSDimitry Andric void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,
1155f757f3fSDimitry Andric                                     const MachineInstr &MI) {
116*0fca6ea1SDimitry Andric   unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
1175f757f3fSDimitry Andric   unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();
1185f757f3fSDimitry Andric 
1195f757f3fSDimitry Andric   auto &Ctx = OutStreamer.getContext();
1205f757f3fSDimitry Andric   MCSymbol *MILabel = Ctx.createTempSymbol();
1215f757f3fSDimitry Andric   OutStreamer.emitLabel(MILabel);
1225f757f3fSDimitry Andric 
1235f757f3fSDimitry Andric   SM.recordStackMap(*MILabel, MI);
1245f757f3fSDimitry Andric   assert(NumNOPBytes % NOPBytes == 0 &&
1255f757f3fSDimitry Andric          "Invalid number of NOP bytes requested!");
1265f757f3fSDimitry Andric 
1275f757f3fSDimitry Andric   // Scan ahead to trim the shadow.
1285f757f3fSDimitry Andric   const MachineBasicBlock &MBB = *MI.getParent();
1295f757f3fSDimitry Andric   MachineBasicBlock::const_iterator MII(MI);
1305f757f3fSDimitry Andric   ++MII;
1315f757f3fSDimitry Andric   while (NumNOPBytes > 0) {
1325f757f3fSDimitry Andric     if (MII == MBB.end() || MII->isCall() ||
1335f757f3fSDimitry Andric         MII->getOpcode() == RISCV::DBG_VALUE ||
1345f757f3fSDimitry Andric         MII->getOpcode() == TargetOpcode::PATCHPOINT ||
1355f757f3fSDimitry Andric         MII->getOpcode() == TargetOpcode::STACKMAP)
1365f757f3fSDimitry Andric       break;
1375f757f3fSDimitry Andric     ++MII;
1385f757f3fSDimitry Andric     NumNOPBytes -= 4;
1395f757f3fSDimitry Andric   }
1405f757f3fSDimitry Andric 
1415f757f3fSDimitry Andric   // Emit nops.
1425f757f3fSDimitry Andric   emitNops(NumNOPBytes / NOPBytes);
1435f757f3fSDimitry Andric }
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric // Lower a patchpoint of the form:
1465f757f3fSDimitry Andric // [<def>], <id>, <numBytes>, <target>, <numArgs>
LowerPATCHPOINT(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)1475f757f3fSDimitry Andric void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1485f757f3fSDimitry Andric                                       const MachineInstr &MI) {
149*0fca6ea1SDimitry Andric   unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
1505f757f3fSDimitry Andric 
1515f757f3fSDimitry Andric   auto &Ctx = OutStreamer.getContext();
1525f757f3fSDimitry Andric   MCSymbol *MILabel = Ctx.createTempSymbol();
1535f757f3fSDimitry Andric   OutStreamer.emitLabel(MILabel);
1545f757f3fSDimitry Andric   SM.recordPatchPoint(*MILabel, MI);
1555f757f3fSDimitry Andric 
1565f757f3fSDimitry Andric   PatchPointOpers Opers(&MI);
1575f757f3fSDimitry Andric 
158*0fca6ea1SDimitry Andric   const MachineOperand &CalleeMO = Opers.getCallTarget();
1595f757f3fSDimitry Andric   unsigned EncodedBytes = 0;
1605f757f3fSDimitry Andric 
161*0fca6ea1SDimitry Andric   if (CalleeMO.isImm()) {
162*0fca6ea1SDimitry Andric     uint64_t CallTarget = CalleeMO.getImm();
163*0fca6ea1SDimitry Andric     if (CallTarget) {
164*0fca6ea1SDimitry Andric       assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget &&
165*0fca6ea1SDimitry Andric              "High 16 bits of call target should be zero.");
166*0fca6ea1SDimitry Andric       // Materialize the jump address:
167*0fca6ea1SDimitry Andric       SmallVector<MCInst, 8> Seq;
168*0fca6ea1SDimitry Andric       RISCVMatInt::generateMCInstSeq(CallTarget, *STI, RISCV::X1, Seq);
169*0fca6ea1SDimitry Andric       for (MCInst &Inst : Seq) {
170*0fca6ea1SDimitry Andric         bool Compressed = EmitToStreamer(OutStreamer, Inst);
171*0fca6ea1SDimitry Andric         EncodedBytes += Compressed ? 2 : 4;
172*0fca6ea1SDimitry Andric       }
173*0fca6ea1SDimitry Andric       bool Compressed = EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)
174*0fca6ea1SDimitry Andric                                                         .addReg(RISCV::X1)
175*0fca6ea1SDimitry Andric                                                         .addReg(RISCV::X1)
176*0fca6ea1SDimitry Andric                                                         .addImm(0));
177*0fca6ea1SDimitry Andric       EncodedBytes += Compressed ? 2 : 4;
178*0fca6ea1SDimitry Andric     }
179*0fca6ea1SDimitry Andric   } else if (CalleeMO.isGlobal()) {
180*0fca6ea1SDimitry Andric     MCOperand CallTargetMCOp;
181*0fca6ea1SDimitry Andric     lowerOperand(CalleeMO, CallTargetMCOp);
182*0fca6ea1SDimitry Andric     EmitToStreamer(OutStreamer,
183*0fca6ea1SDimitry Andric                    MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));
184*0fca6ea1SDimitry Andric     EncodedBytes += 8;
185*0fca6ea1SDimitry Andric   }
186*0fca6ea1SDimitry Andric 
1875f757f3fSDimitry Andric   // Emit padding.
1885f757f3fSDimitry Andric   unsigned NumBytes = Opers.getNumPatchBytes();
1895f757f3fSDimitry Andric   assert(NumBytes >= EncodedBytes &&
1905f757f3fSDimitry Andric          "Patchpoint can't request size less than the length of a call.");
1915f757f3fSDimitry Andric   assert((NumBytes - EncodedBytes) % NOPBytes == 0 &&
1925f757f3fSDimitry Andric          "Invalid number of NOP bytes requested!");
1935f757f3fSDimitry Andric   emitNops((NumBytes - EncodedBytes) / NOPBytes);
1945f757f3fSDimitry Andric }
1955f757f3fSDimitry Andric 
LowerSTATEPOINT(MCStreamer & OutStreamer,StackMaps & SM,const MachineInstr & MI)1965f757f3fSDimitry Andric void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
1975f757f3fSDimitry Andric                                       const MachineInstr &MI) {
198*0fca6ea1SDimitry Andric   unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;
1995f757f3fSDimitry Andric 
2005f757f3fSDimitry Andric   StatepointOpers SOpers(&MI);
2015f757f3fSDimitry Andric   if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {
2025f757f3fSDimitry Andric     assert(PatchBytes % NOPBytes == 0 &&
2035f757f3fSDimitry Andric            "Invalid number of NOP bytes requested!");
2045f757f3fSDimitry Andric     emitNops(PatchBytes / NOPBytes);
205*0fca6ea1SDimitry Andric   } else {
206*0fca6ea1SDimitry Andric     // Lower call target and choose correct opcode
207*0fca6ea1SDimitry Andric     const MachineOperand &CallTarget = SOpers.getCallTarget();
208*0fca6ea1SDimitry Andric     MCOperand CallTargetMCOp;
209*0fca6ea1SDimitry Andric     switch (CallTarget.getType()) {
210*0fca6ea1SDimitry Andric     case MachineOperand::MO_GlobalAddress:
211*0fca6ea1SDimitry Andric     case MachineOperand::MO_ExternalSymbol:
212*0fca6ea1SDimitry Andric       lowerOperand(CallTarget, CallTargetMCOp);
213*0fca6ea1SDimitry Andric       EmitToStreamer(
214*0fca6ea1SDimitry Andric           OutStreamer,
215*0fca6ea1SDimitry Andric           MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));
216*0fca6ea1SDimitry Andric       break;
217*0fca6ea1SDimitry Andric     case MachineOperand::MO_Immediate:
218*0fca6ea1SDimitry Andric       CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());
219*0fca6ea1SDimitry Andric       EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JAL)
220*0fca6ea1SDimitry Andric                                       .addReg(RISCV::X1)
221*0fca6ea1SDimitry Andric                                       .addOperand(CallTargetMCOp));
222*0fca6ea1SDimitry Andric       break;
223*0fca6ea1SDimitry Andric     case MachineOperand::MO_Register:
224*0fca6ea1SDimitry Andric       CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());
225*0fca6ea1SDimitry Andric       EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)
226*0fca6ea1SDimitry Andric                                       .addReg(RISCV::X1)
227*0fca6ea1SDimitry Andric                                       .addOperand(CallTargetMCOp)
228*0fca6ea1SDimitry Andric                                       .addImm(0));
229*0fca6ea1SDimitry Andric       break;
230*0fca6ea1SDimitry Andric     default:
231*0fca6ea1SDimitry Andric       llvm_unreachable("Unsupported operand type in statepoint call target");
232*0fca6ea1SDimitry Andric       break;
233*0fca6ea1SDimitry Andric     }
2345f757f3fSDimitry Andric   }
2355f757f3fSDimitry Andric 
2365f757f3fSDimitry Andric   auto &Ctx = OutStreamer.getContext();
2375f757f3fSDimitry Andric   MCSymbol *MILabel = Ctx.createTempSymbol();
2385f757f3fSDimitry Andric   OutStreamer.emitLabel(MILabel);
2395f757f3fSDimitry Andric   SM.recordStatepoint(*MILabel, MI);
2405f757f3fSDimitry Andric }
2415f757f3fSDimitry Andric 
EmitToStreamer(MCStreamer & S,const MCInst & Inst)242*0fca6ea1SDimitry Andric bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
2430b57cec5SDimitry Andric   MCInst CInst;
244bdd1243dSDimitry Andric   bool Res = RISCVRVC::compress(CInst, Inst, *STI);
245480093f4SDimitry Andric   if (Res)
246480093f4SDimitry Andric     ++RISCVNumInstrsCompressed;
2470b57cec5SDimitry Andric   AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
248*0fca6ea1SDimitry Andric   return Res;
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric // Simple pseudo-instructions have their lowering (with expansion to real
2520b57cec5SDimitry Andric // instructions) auto-generated.
2530b57cec5SDimitry Andric #include "RISCVGenMCPseudoLowering.inc"
2540b57cec5SDimitry Andric 
25506c3fb27SDimitry Andric // If the target supports Zihintntl and the instruction has a nontemporal
25606c3fb27SDimitry Andric // MachineMemOperand, emit an NTLH hint instruction before it.
emitNTLHint(const MachineInstr * MI)25706c3fb27SDimitry Andric void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {
25806c3fb27SDimitry Andric   if (!STI->hasStdExtZihintntl())
25906c3fb27SDimitry Andric     return;
26006c3fb27SDimitry Andric 
26106c3fb27SDimitry Andric   if (MI->memoperands_empty())
26206c3fb27SDimitry Andric     return;
26306c3fb27SDimitry Andric 
26406c3fb27SDimitry Andric   MachineMemOperand *MMO = *(MI->memoperands_begin());
26506c3fb27SDimitry Andric   if (!MMO->isNonTemporal())
26606c3fb27SDimitry Andric     return;
26706c3fb27SDimitry Andric 
26806c3fb27SDimitry Andric   unsigned NontemporalMode = 0;
26906c3fb27SDimitry Andric   if (MMO->getFlags() & MONontemporalBit0)
27006c3fb27SDimitry Andric     NontemporalMode += 0b1;
27106c3fb27SDimitry Andric   if (MMO->getFlags() & MONontemporalBit1)
27206c3fb27SDimitry Andric     NontemporalMode += 0b10;
27306c3fb27SDimitry Andric 
27406c3fb27SDimitry Andric   MCInst Hint;
27506c3fb27SDimitry Andric   if (STI->hasStdExtCOrZca() && STI->enableRVCHintInstrs())
27606c3fb27SDimitry Andric     Hint.setOpcode(RISCV::C_ADD_HINT);
27706c3fb27SDimitry Andric   else
27806c3fb27SDimitry Andric     Hint.setOpcode(RISCV::ADD);
27906c3fb27SDimitry Andric 
28006c3fb27SDimitry Andric   Hint.addOperand(MCOperand::createReg(RISCV::X0));
28106c3fb27SDimitry Andric   Hint.addOperand(MCOperand::createReg(RISCV::X0));
28206c3fb27SDimitry Andric   Hint.addOperand(MCOperand::createReg(RISCV::X2 + NontemporalMode));
28306c3fb27SDimitry Andric 
28406c3fb27SDimitry Andric   EmitToStreamer(*OutStreamer, Hint);
28506c3fb27SDimitry Andric }
28606c3fb27SDimitry Andric 
emitInstruction(const MachineInstr * MI)2875ffd83dbSDimitry Andric void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
288753f127fSDimitry Andric   RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),
289753f127fSDimitry Andric                                         getSubtargetInfo().getFeatureBits());
290753f127fSDimitry Andric 
29106c3fb27SDimitry Andric   emitNTLHint(MI);
29206c3fb27SDimitry Andric 
2930b57cec5SDimitry Andric   // Do any auto-generated pseudo lowerings.
2940b57cec5SDimitry Andric   if (emitPseudoExpansionLowering(*OutStreamer, MI))
2950b57cec5SDimitry Andric     return;
2960b57cec5SDimitry Andric 
297bdd1243dSDimitry Andric 
298bdd1243dSDimitry Andric   switch (MI->getOpcode()) {
299bdd1243dSDimitry Andric   case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
300bdd1243dSDimitry Andric     LowerHWASAN_CHECK_MEMACCESS(*MI);
301bdd1243dSDimitry Andric     return;
30206c3fb27SDimitry Andric   case RISCV::KCFI_CHECK:
30306c3fb27SDimitry Andric     LowerKCFI_CHECK(*MI);
30406c3fb27SDimitry Andric     return;
30506c3fb27SDimitry Andric   case RISCV::PseudoRVVInitUndefM1:
30606c3fb27SDimitry Andric   case RISCV::PseudoRVVInitUndefM2:
30706c3fb27SDimitry Andric   case RISCV::PseudoRVVInitUndefM4:
30806c3fb27SDimitry Andric   case RISCV::PseudoRVVInitUndefM8:
30906c3fb27SDimitry Andric     return;
3105f757f3fSDimitry Andric   case TargetOpcode::STACKMAP:
3115f757f3fSDimitry Andric     return LowerSTACKMAP(*OutStreamer, SM, *MI);
3125f757f3fSDimitry Andric   case TargetOpcode::PATCHPOINT:
3135f757f3fSDimitry Andric     return LowerPATCHPOINT(*OutStreamer, SM, *MI);
3145f757f3fSDimitry Andric   case TargetOpcode::STATEPOINT:
3155f757f3fSDimitry Andric     return LowerSTATEPOINT(*OutStreamer, SM, *MI);
316bdd1243dSDimitry Andric   }
317bdd1243dSDimitry Andric 
31806c3fb27SDimitry Andric   MCInst OutInst;
31906c3fb27SDimitry Andric   if (!lowerToMCInst(MI, OutInst))
32006c3fb27SDimitry Andric     EmitToStreamer(*OutStreamer, OutInst);
3210b57cec5SDimitry Andric }
3220b57cec5SDimitry Andric 
PrintAsmOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)3230b57cec5SDimitry Andric bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
3240b57cec5SDimitry Andric                                       const char *ExtraCode, raw_ostream &OS) {
3250b57cec5SDimitry Andric   // First try the generic code, which knows about modifiers like 'c' and 'n'.
3260b57cec5SDimitry Andric   if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
3270b57cec5SDimitry Andric     return false;
3280b57cec5SDimitry Andric 
3290b57cec5SDimitry Andric   const MachineOperand &MO = MI->getOperand(OpNo);
3300b57cec5SDimitry Andric   if (ExtraCode && ExtraCode[0]) {
3310b57cec5SDimitry Andric     if (ExtraCode[1] != 0)
3320b57cec5SDimitry Andric       return true; // Unknown modifier.
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric     switch (ExtraCode[0]) {
3350b57cec5SDimitry Andric     default:
3360b57cec5SDimitry Andric       return true; // Unknown modifier.
3370b57cec5SDimitry Andric     case 'z':      // Print zero register if zero, regular printing otherwise.
3380b57cec5SDimitry Andric       if (MO.isImm() && MO.getImm() == 0) {
3390b57cec5SDimitry Andric         OS << RISCVInstPrinter::getRegisterName(RISCV::X0);
3400b57cec5SDimitry Andric         return false;
3410b57cec5SDimitry Andric       }
3420b57cec5SDimitry Andric       break;
3430b57cec5SDimitry Andric     case 'i': // Literal 'i' if operand is not a register.
3440b57cec5SDimitry Andric       if (!MO.isReg())
3450b57cec5SDimitry Andric         OS << 'i';
3460b57cec5SDimitry Andric       return false;
3470b57cec5SDimitry Andric     }
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
3500b57cec5SDimitry Andric   switch (MO.getType()) {
3510b57cec5SDimitry Andric   case MachineOperand::MO_Immediate:
3520b57cec5SDimitry Andric     OS << MO.getImm();
3530b57cec5SDimitry Andric     return false;
3540b57cec5SDimitry Andric   case MachineOperand::MO_Register:
3550b57cec5SDimitry Andric     OS << RISCVInstPrinter::getRegisterName(MO.getReg());
3560b57cec5SDimitry Andric     return false;
357480093f4SDimitry Andric   case MachineOperand::MO_GlobalAddress:
358480093f4SDimitry Andric     PrintSymbolOperand(MO, OS);
359480093f4SDimitry Andric     return false;
360480093f4SDimitry Andric   case MachineOperand::MO_BlockAddress: {
361480093f4SDimitry Andric     MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
362480093f4SDimitry Andric     Sym->print(OS, MAI);
363480093f4SDimitry Andric     return false;
364480093f4SDimitry Andric   }
3650b57cec5SDimitry Andric   default:
3660b57cec5SDimitry Andric     break;
3670b57cec5SDimitry Andric   }
3680b57cec5SDimitry Andric 
3690b57cec5SDimitry Andric   return true;
3700b57cec5SDimitry Andric }
3710b57cec5SDimitry Andric 
PrintAsmMemoryOperand(const MachineInstr * MI,unsigned OpNo,const char * ExtraCode,raw_ostream & OS)3720b57cec5SDimitry Andric bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
3730b57cec5SDimitry Andric                                             unsigned OpNo,
3740b57cec5SDimitry Andric                                             const char *ExtraCode,
3750b57cec5SDimitry Andric                                             raw_ostream &OS) {
37606c3fb27SDimitry Andric   if (ExtraCode)
37706c3fb27SDimitry Andric     return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
37806c3fb27SDimitry Andric 
37906c3fb27SDimitry Andric   const MachineOperand &AddrReg = MI->getOperand(OpNo);
38006c3fb27SDimitry Andric   assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");
3818a4dda33SDimitry Andric   const MachineOperand &Offset = MI->getOperand(OpNo + 1);
38206c3fb27SDimitry Andric   // All memory operands should have a register and an immediate operand (see
38306c3fb27SDimitry Andric   // RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).
38406c3fb27SDimitry Andric   if (!AddrReg.isReg())
38506c3fb27SDimitry Andric     return true;
3867a6dacacSDimitry Andric   if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() &&
3877a6dacacSDimitry Andric       !Offset.isMCSymbol())
3880b57cec5SDimitry Andric     return true;
3890b57cec5SDimitry Andric 
3908a4dda33SDimitry Andric   MCOperand MCO;
3918a4dda33SDimitry Andric   if (!lowerOperand(Offset, MCO))
3928a4dda33SDimitry Andric     return true;
3938a4dda33SDimitry Andric 
3948a4dda33SDimitry Andric   if (Offset.isImm())
3958a4dda33SDimitry Andric     OS << MCO.getImm();
3967a6dacacSDimitry Andric   else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol())
3978a4dda33SDimitry Andric     OS << *MCO.getExpr();
3988a4dda33SDimitry Andric   OS << "(" << RISCVInstPrinter::getRegisterName(AddrReg.getReg()) << ")";
3990b57cec5SDimitry Andric   return false;
4000b57cec5SDimitry Andric }
4010b57cec5SDimitry Andric 
emitDirectiveOptionArch()4025f757f3fSDimitry Andric bool RISCVAsmPrinter::emitDirectiveOptionArch() {
4035f757f3fSDimitry Andric   RISCVTargetStreamer &RTS =
4045f757f3fSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
4055f757f3fSDimitry Andric   SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
4065f757f3fSDimitry Andric   const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
4075f757f3fSDimitry Andric   for (const auto &Feature : RISCVFeatureKV) {
4085f757f3fSDimitry Andric     if (STI->hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
4095f757f3fSDimitry Andric       continue;
4105f757f3fSDimitry Andric 
4115f757f3fSDimitry Andric     if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.Key))
4125f757f3fSDimitry Andric       continue;
4135f757f3fSDimitry Andric 
4145f757f3fSDimitry Andric     auto Delta = STI->hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus
4155f757f3fSDimitry Andric                                                 : RISCVOptionArchArgType::Minus;
4165f757f3fSDimitry Andric     NeedEmitStdOptionArgs.emplace_back(Delta, Feature.Key);
4175f757f3fSDimitry Andric   }
4185f757f3fSDimitry Andric   if (!NeedEmitStdOptionArgs.empty()) {
4195f757f3fSDimitry Andric     RTS.emitDirectiveOptionPush();
4205f757f3fSDimitry Andric     RTS.emitDirectiveOptionArch(NeedEmitStdOptionArgs);
4215f757f3fSDimitry Andric     return true;
4225f757f3fSDimitry Andric   }
4235f757f3fSDimitry Andric 
4245f757f3fSDimitry Andric   return false;
4255f757f3fSDimitry Andric }
4265f757f3fSDimitry Andric 
runOnMachineFunction(MachineFunction & MF)4275ffd83dbSDimitry Andric bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
42881ad6265SDimitry Andric   STI = &MF.getSubtarget<RISCVSubtarget>();
4295f757f3fSDimitry Andric   RISCVTargetStreamer &RTS =
4305f757f3fSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
4315f757f3fSDimitry Andric 
4325f757f3fSDimitry Andric   bool EmittedOptionArch = emitDirectiveOptionArch();
4335ffd83dbSDimitry Andric 
4345ffd83dbSDimitry Andric   SetupMachineFunction(MF);
4355ffd83dbSDimitry Andric   emitFunctionBody();
4365f757f3fSDimitry Andric 
4375f757f3fSDimitry Andric   if (EmittedOptionArch)
4385f757f3fSDimitry Andric     RTS.emitDirectiveOptionPop();
4395ffd83dbSDimitry Andric   return false;
4405ffd83dbSDimitry Andric }
4415ffd83dbSDimitry Andric 
emitStartOfAsmFile(Module & M)4425ffd83dbSDimitry Andric void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
443bdd1243dSDimitry Andric   RISCVTargetStreamer &RTS =
444bdd1243dSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
445bdd1243dSDimitry Andric   if (const MDString *ModuleTargetABI =
446bdd1243dSDimitry Andric           dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
447bdd1243dSDimitry Andric     RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
4483a079333SDimitry Andric 
4493a079333SDimitry Andric   MCSubtargetInfo SubtargetInfo = *TM.getMCSubtargetInfo();
4503a079333SDimitry Andric 
4513a079333SDimitry Andric   // Use module flag to update feature bits.
4523a079333SDimitry Andric   if (auto *MD = dyn_cast_or_null<MDNode>(M.getModuleFlag("riscv-isa"))) {
4533a079333SDimitry Andric     for (auto &ISA : MD->operands()) {
4543a079333SDimitry Andric       if (auto *ISAString = dyn_cast_or_null<MDString>(ISA)) {
4553a079333SDimitry Andric         auto ParseResult = llvm::RISCVISAInfo::parseArchString(
4563a079333SDimitry Andric             ISAString->getString(), /*EnableExperimentalExtension=*/true,
4573a079333SDimitry Andric             /*ExperimentalExtensionVersionCheck=*/true);
4583a079333SDimitry Andric         if (!errorToBool(ParseResult.takeError())) {
4593a079333SDimitry Andric           auto &ISAInfo = *ParseResult;
4603a079333SDimitry Andric           for (const auto &Feature : RISCVFeatureKV) {
4613a079333SDimitry Andric             if (ISAInfo->hasExtension(Feature.Key) &&
4623a079333SDimitry Andric                 !SubtargetInfo.hasFeature(Feature.Value))
4633a079333SDimitry Andric               SubtargetInfo.ToggleFeature(Feature.Key);
4643a079333SDimitry Andric           }
4653a079333SDimitry Andric         }
4663a079333SDimitry Andric       }
4673a079333SDimitry Andric     }
4683a079333SDimitry Andric 
4693a079333SDimitry Andric     RTS.setFlagsFromFeatures(SubtargetInfo);
4703a079333SDimitry Andric   }
4713a079333SDimitry Andric 
4725ffd83dbSDimitry Andric   if (TM.getTargetTriple().isOSBinFormatELF())
4733a079333SDimitry Andric     emitAttributes(SubtargetInfo);
4745ffd83dbSDimitry Andric }
4755ffd83dbSDimitry Andric 
emitEndOfAsmFile(Module & M)4765ffd83dbSDimitry Andric void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
4775ffd83dbSDimitry Andric   RISCVTargetStreamer &RTS =
4785ffd83dbSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
4795ffd83dbSDimitry Andric 
4805ffd83dbSDimitry Andric   if (TM.getTargetTriple().isOSBinFormatELF())
4815ffd83dbSDimitry Andric     RTS.finishAttributeSection();
482bdd1243dSDimitry Andric   EmitHwasanMemaccessSymbols(M);
4835ffd83dbSDimitry Andric }
4845ffd83dbSDimitry Andric 
emitAttributes(const MCSubtargetInfo & SubtargetInfo)4853a079333SDimitry Andric void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) {
4865ffd83dbSDimitry Andric   RISCVTargetStreamer &RTS =
4875ffd83dbSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
488bdd1243dSDimitry Andric   // Use MCSubtargetInfo from TargetMachine. Individual functions may have
489bdd1243dSDimitry Andric   // attributes that differ from other functions in the module and we have no
490bdd1243dSDimitry Andric   // way to know which function is correct.
4913a079333SDimitry Andric   RTS.emitTargetAttributes(SubtargetInfo, /*EmitStackAlign*/ true);
49281ad6265SDimitry Andric }
49381ad6265SDimitry Andric 
emitFunctionEntryLabel()49481ad6265SDimitry Andric void RISCVAsmPrinter::emitFunctionEntryLabel() {
495bdd1243dSDimitry Andric   const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
496bdd1243dSDimitry Andric   if (RMFI->isVectorCall()) {
497bdd1243dSDimitry Andric     auto &RTS =
49881ad6265SDimitry Andric         static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
499bdd1243dSDimitry Andric     RTS.emitDirectiveVariantCC(*CurrentFnSym);
500bdd1243dSDimitry Andric   }
501bdd1243dSDimitry Andric   return AsmPrinter::emitFunctionEntryLabel();
5025ffd83dbSDimitry Andric }
5035ffd83dbSDimitry Andric 
5040b57cec5SDimitry Andric // Force static initialization.
LLVMInitializeRISCVAsmPrinter()505480093f4SDimitry Andric extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
5060b57cec5SDimitry Andric   RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
5070b57cec5SDimitry Andric   RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
5080b57cec5SDimitry Andric }
509bdd1243dSDimitry Andric 
LowerHWASAN_CHECK_MEMACCESS(const MachineInstr & MI)510bdd1243dSDimitry Andric void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
511bdd1243dSDimitry Andric   Register Reg = MI.getOperand(0).getReg();
512bdd1243dSDimitry Andric   uint32_t AccessInfo = MI.getOperand(1).getImm();
513bdd1243dSDimitry Andric   MCSymbol *&Sym =
514bdd1243dSDimitry Andric       HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
515bdd1243dSDimitry Andric   if (!Sym) {
516bdd1243dSDimitry Andric     // FIXME: Make this work on non-ELF.
517bdd1243dSDimitry Andric     if (!TM.getTargetTriple().isOSBinFormatELF())
518bdd1243dSDimitry Andric       report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
519bdd1243dSDimitry Andric 
520bdd1243dSDimitry Andric     std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
521bdd1243dSDimitry Andric                           utostr(AccessInfo) + "_short";
522bdd1243dSDimitry Andric     Sym = OutContext.getOrCreateSymbol(SymName);
523bdd1243dSDimitry Andric   }
524bdd1243dSDimitry Andric   auto Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext);
525bdd1243dSDimitry Andric   auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);
526bdd1243dSDimitry Andric 
527bdd1243dSDimitry Andric   EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
528bdd1243dSDimitry Andric }
529bdd1243dSDimitry Andric 
LowerKCFI_CHECK(const MachineInstr & MI)53006c3fb27SDimitry Andric void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {
53106c3fb27SDimitry Andric   Register AddrReg = MI.getOperand(0).getReg();
53206c3fb27SDimitry Andric   assert(std::next(MI.getIterator())->isCall() &&
53306c3fb27SDimitry Andric          "KCFI_CHECK not followed by a call instruction");
53406c3fb27SDimitry Andric   assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&
53506c3fb27SDimitry Andric          "KCFI_CHECK call target doesn't match call operand");
53606c3fb27SDimitry Andric 
53706c3fb27SDimitry Andric   // Temporary registers for comparing the hashes. If a register is used
53806c3fb27SDimitry Andric   // for the call target, or reserved by the user, we can clobber another
53906c3fb27SDimitry Andric   // temporary register as the check is immediately followed by the
54006c3fb27SDimitry Andric   // call. The check defaults to X6/X7, but can fall back to X28-X31 if
54106c3fb27SDimitry Andric   // needed.
54206c3fb27SDimitry Andric   unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};
54306c3fb27SDimitry Andric   unsigned NextReg = RISCV::X28;
54406c3fb27SDimitry Andric   auto isRegAvailable = [&](unsigned Reg) {
54506c3fb27SDimitry Andric     return Reg != AddrReg && !STI->isRegisterReservedByUser(Reg);
54606c3fb27SDimitry Andric   };
54706c3fb27SDimitry Andric   for (auto &Reg : ScratchRegs) {
54806c3fb27SDimitry Andric     if (isRegAvailable(Reg))
54906c3fb27SDimitry Andric       continue;
55006c3fb27SDimitry Andric     while (!isRegAvailable(NextReg))
55106c3fb27SDimitry Andric       ++NextReg;
55206c3fb27SDimitry Andric     Reg = NextReg++;
55306c3fb27SDimitry Andric     if (Reg > RISCV::X31)
55406c3fb27SDimitry Andric       report_fatal_error("Unable to find scratch registers for KCFI_CHECK");
55506c3fb27SDimitry Andric   }
55606c3fb27SDimitry Andric 
55706c3fb27SDimitry Andric   if (AddrReg == RISCV::X0) {
55806c3fb27SDimitry Andric     // Checking X0 makes no sense. Instead of emitting a load, zero
55906c3fb27SDimitry Andric     // ScratchRegs[0].
56006c3fb27SDimitry Andric     EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::ADDI)
56106c3fb27SDimitry Andric                                      .addReg(ScratchRegs[0])
56206c3fb27SDimitry Andric                                      .addReg(RISCV::X0)
56306c3fb27SDimitry Andric                                      .addImm(0));
56406c3fb27SDimitry Andric   } else {
56506c3fb27SDimitry Andric     // Adjust the offset for patchable-function-prefix. This assumes that
56606c3fb27SDimitry Andric     // patchable-function-prefix is the same for all functions.
56706c3fb27SDimitry Andric     int NopSize = STI->hasStdExtCOrZca() ? 2 : 4;
56806c3fb27SDimitry Andric     int64_t PrefixNops = 0;
56906c3fb27SDimitry Andric     (void)MI.getMF()
57006c3fb27SDimitry Andric         ->getFunction()
57106c3fb27SDimitry Andric         .getFnAttribute("patchable-function-prefix")
57206c3fb27SDimitry Andric         .getValueAsString()
57306c3fb27SDimitry Andric         .getAsInteger(10, PrefixNops);
57406c3fb27SDimitry Andric 
57506c3fb27SDimitry Andric     // Load the target function type hash.
57606c3fb27SDimitry Andric     EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)
57706c3fb27SDimitry Andric                                      .addReg(ScratchRegs[0])
57806c3fb27SDimitry Andric                                      .addReg(AddrReg)
57906c3fb27SDimitry Andric                                      .addImm(-(PrefixNops * NopSize + 4)));
58006c3fb27SDimitry Andric   }
58106c3fb27SDimitry Andric 
58206c3fb27SDimitry Andric   // Load the expected 32-bit type hash.
58306c3fb27SDimitry Andric   const int64_t Type = MI.getOperand(1).getImm();
58406c3fb27SDimitry Andric   const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;
58506c3fb27SDimitry Andric   const int64_t Lo12 = SignExtend64<12>(Type);
58606c3fb27SDimitry Andric   if (Hi20) {
58706c3fb27SDimitry Andric     EmitToStreamer(
58806c3fb27SDimitry Andric         *OutStreamer,
58906c3fb27SDimitry Andric         MCInstBuilder(RISCV::LUI).addReg(ScratchRegs[1]).addImm(Hi20));
59006c3fb27SDimitry Andric   }
59106c3fb27SDimitry Andric   if (Lo12 || Hi20 == 0) {
59206c3fb27SDimitry Andric     EmitToStreamer(*OutStreamer,
59306c3fb27SDimitry Andric                    MCInstBuilder((STI->hasFeature(RISCV::Feature64Bit) && Hi20)
59406c3fb27SDimitry Andric                                      ? RISCV::ADDIW
59506c3fb27SDimitry Andric                                      : RISCV::ADDI)
59606c3fb27SDimitry Andric                        .addReg(ScratchRegs[1])
59706c3fb27SDimitry Andric                        .addReg(ScratchRegs[1])
59806c3fb27SDimitry Andric                        .addImm(Lo12));
59906c3fb27SDimitry Andric   }
60006c3fb27SDimitry Andric 
60106c3fb27SDimitry Andric   // Compare the hashes and trap if there's a mismatch.
60206c3fb27SDimitry Andric   MCSymbol *Pass = OutContext.createTempSymbol();
60306c3fb27SDimitry Andric   EmitToStreamer(*OutStreamer,
60406c3fb27SDimitry Andric                  MCInstBuilder(RISCV::BEQ)
60506c3fb27SDimitry Andric                      .addReg(ScratchRegs[0])
60606c3fb27SDimitry Andric                      .addReg(ScratchRegs[1])
60706c3fb27SDimitry Andric                      .addExpr(MCSymbolRefExpr::create(Pass, OutContext)));
60806c3fb27SDimitry Andric 
60906c3fb27SDimitry Andric   MCSymbol *Trap = OutContext.createTempSymbol();
61006c3fb27SDimitry Andric   OutStreamer->emitLabel(Trap);
61106c3fb27SDimitry Andric   EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::EBREAK));
61206c3fb27SDimitry Andric   emitKCFITrapEntry(*MI.getMF(), Trap);
61306c3fb27SDimitry Andric   OutStreamer->emitLabel(Pass);
61406c3fb27SDimitry Andric }
61506c3fb27SDimitry Andric 
EmitHwasanMemaccessSymbols(Module & M)616bdd1243dSDimitry Andric void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
617bdd1243dSDimitry Andric   if (HwasanMemaccessSymbols.empty())
618bdd1243dSDimitry Andric     return;
619bdd1243dSDimitry Andric 
620bdd1243dSDimitry Andric   assert(TM.getTargetTriple().isOSBinFormatELF());
621bdd1243dSDimitry Andric   // Use MCSubtargetInfo from TargetMachine. Individual functions may have
622bdd1243dSDimitry Andric   // attributes that differ from other functions in the module and we have no
623bdd1243dSDimitry Andric   // way to know which function is correct.
624bdd1243dSDimitry Andric   const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
625bdd1243dSDimitry Andric 
626bdd1243dSDimitry Andric   MCSymbol *HwasanTagMismatchV2Sym =
627bdd1243dSDimitry Andric       OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
628bdd1243dSDimitry Andric   // Annotate symbol as one having incompatible calling convention, so
629bdd1243dSDimitry Andric   // run-time linkers can instead eagerly bind this function.
630bdd1243dSDimitry Andric   auto &RTS =
631bdd1243dSDimitry Andric       static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
632bdd1243dSDimitry Andric   RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
633bdd1243dSDimitry Andric 
634bdd1243dSDimitry Andric   const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
635bdd1243dSDimitry Andric       MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
636bdd1243dSDimitry Andric   auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,
637bdd1243dSDimitry Andric                                   RISCVMCExpr::VK_RISCV_CALL, OutContext);
638bdd1243dSDimitry Andric 
639bdd1243dSDimitry Andric   for (auto &P : HwasanMemaccessSymbols) {
640bdd1243dSDimitry Andric     unsigned Reg = std::get<0>(P.first);
641bdd1243dSDimitry Andric     uint32_t AccessInfo = std::get<1>(P.first);
642bdd1243dSDimitry Andric     MCSymbol *Sym = P.second;
643bdd1243dSDimitry Andric 
644bdd1243dSDimitry Andric     unsigned Size =
645bdd1243dSDimitry Andric         1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
646bdd1243dSDimitry Andric     OutStreamer->switchSection(OutContext.getELFSection(
647bdd1243dSDimitry Andric         ".text.hot", ELF::SHT_PROGBITS,
648bdd1243dSDimitry Andric         ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
649bdd1243dSDimitry Andric         /*IsComdat=*/true));
650bdd1243dSDimitry Andric 
651bdd1243dSDimitry Andric     OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
652bdd1243dSDimitry Andric     OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
653bdd1243dSDimitry Andric     OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
654bdd1243dSDimitry Andric     OutStreamer->emitLabel(Sym);
655bdd1243dSDimitry Andric 
656bdd1243dSDimitry Andric     // Extract shadow offset from ptr
657bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
658bdd1243dSDimitry Andric         MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
659bdd1243dSDimitry Andric         MCSTI);
660bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)
661bdd1243dSDimitry Andric                                      .addReg(RISCV::X6)
662bdd1243dSDimitry Andric                                      .addReg(RISCV::X6)
663bdd1243dSDimitry Andric                                      .addImm(12),
664bdd1243dSDimitry Andric                                  MCSTI);
665bdd1243dSDimitry Andric     // load shadow tag in X6, X5 contains shadow base
666bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)
667bdd1243dSDimitry Andric                                      .addReg(RISCV::X6)
668bdd1243dSDimitry Andric                                      .addReg(RISCV::X5)
669bdd1243dSDimitry Andric                                      .addReg(RISCV::X6),
670bdd1243dSDimitry Andric                                  MCSTI);
671bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
672bdd1243dSDimitry Andric         MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
673bdd1243dSDimitry Andric         MCSTI);
674bdd1243dSDimitry Andric     // Extract tag from X5 and compare it with loaded tag from shadow
675bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
676bdd1243dSDimitry Andric         MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
677bdd1243dSDimitry Andric         MCSTI);
678bdd1243dSDimitry Andric     MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
679bdd1243dSDimitry Andric     // X7 contains tag from memory, while X6 contains tag from the pointer
680bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
681bdd1243dSDimitry Andric         MCInstBuilder(RISCV::BNE)
682bdd1243dSDimitry Andric             .addReg(RISCV::X7)
683bdd1243dSDimitry Andric             .addReg(RISCV::X6)
684bdd1243dSDimitry Andric             .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
685bdd1243dSDimitry Andric                                              OutContext)),
686bdd1243dSDimitry Andric         MCSTI);
687bdd1243dSDimitry Andric     MCSymbol *ReturnSym = OutContext.createTempSymbol();
688bdd1243dSDimitry Andric     OutStreamer->emitLabel(ReturnSym);
689bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)
690bdd1243dSDimitry Andric                                      .addReg(RISCV::X0)
691bdd1243dSDimitry Andric                                      .addReg(RISCV::X1)
692bdd1243dSDimitry Andric                                      .addImm(0),
693bdd1243dSDimitry Andric                                  MCSTI);
694bdd1243dSDimitry Andric     OutStreamer->emitLabel(HandleMismatchOrPartialSym);
695bdd1243dSDimitry Andric 
696bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
697bdd1243dSDimitry Andric                                      .addReg(RISCV::X28)
698bdd1243dSDimitry Andric                                      .addReg(RISCV::X0)
699bdd1243dSDimitry Andric                                      .addImm(16),
700bdd1243dSDimitry Andric                                  MCSTI);
701bdd1243dSDimitry Andric     MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
702bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
703bdd1243dSDimitry Andric         MCInstBuilder(RISCV::BGEU)
704bdd1243dSDimitry Andric             .addReg(RISCV::X6)
705bdd1243dSDimitry Andric             .addReg(RISCV::X28)
706bdd1243dSDimitry Andric             .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
707bdd1243dSDimitry Andric         MCSTI);
708bdd1243dSDimitry Andric 
709bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
710bdd1243dSDimitry Andric         MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
711bdd1243dSDimitry Andric         MCSTI);
712bdd1243dSDimitry Andric 
713bdd1243dSDimitry Andric     if (Size != 1)
714bdd1243dSDimitry Andric       OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
715bdd1243dSDimitry Andric                                        .addReg(RISCV::X28)
716bdd1243dSDimitry Andric                                        .addReg(RISCV::X28)
717bdd1243dSDimitry Andric                                        .addImm(Size - 1),
718bdd1243dSDimitry Andric                                    MCSTI);
719bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
720bdd1243dSDimitry Andric         MCInstBuilder(RISCV::BGE)
721bdd1243dSDimitry Andric             .addReg(RISCV::X28)
722bdd1243dSDimitry Andric             .addReg(RISCV::X6)
723bdd1243dSDimitry Andric             .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
724bdd1243dSDimitry Andric         MCSTI);
725bdd1243dSDimitry Andric 
726bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
727bdd1243dSDimitry Andric         MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
728bdd1243dSDimitry Andric         MCSTI);
729bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
730bdd1243dSDimitry Andric         MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
731bdd1243dSDimitry Andric         MCSTI);
732bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
733bdd1243dSDimitry Andric         MCInstBuilder(RISCV::BEQ)
734bdd1243dSDimitry Andric             .addReg(RISCV::X6)
735bdd1243dSDimitry Andric             .addReg(RISCV::X7)
736bdd1243dSDimitry Andric             .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
737bdd1243dSDimitry Andric         MCSTI);
738bdd1243dSDimitry Andric 
739bdd1243dSDimitry Andric     OutStreamer->emitLabel(HandleMismatchSym);
740bdd1243dSDimitry Andric 
741bdd1243dSDimitry Andric     // | Previous stack frames...        |
742bdd1243dSDimitry Andric     // +=================================+ <-- [SP + 256]
743bdd1243dSDimitry Andric     // |              ...                |
744bdd1243dSDimitry Andric     // |                                 |
745bdd1243dSDimitry Andric     // | Stack frame space for x12 - x31.|
746bdd1243dSDimitry Andric     // |                                 |
747bdd1243dSDimitry Andric     // |              ...                |
748bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 96]
749bdd1243dSDimitry Andric     // | Saved x11(arg1), as             |
750bdd1243dSDimitry Andric     // | __hwasan_check_* clobbers it.   |
751bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 88]
752bdd1243dSDimitry Andric     // | Saved x10(arg0), as             |
753bdd1243dSDimitry Andric     // | __hwasan_check_* clobbers it.   |
754bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 80]
755bdd1243dSDimitry Andric     // |                                 |
756bdd1243dSDimitry Andric     // | Stack frame space for x9.       |
757bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 72]
758bdd1243dSDimitry Andric     // |                                 |
759bdd1243dSDimitry Andric     // | Saved x8(fp), as                |
760bdd1243dSDimitry Andric     // | __hwasan_check_* clobbers it.   |
761bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 64]
762bdd1243dSDimitry Andric     // |              ...                |
763bdd1243dSDimitry Andric     // |                                 |
764bdd1243dSDimitry Andric     // | Stack frame space for x2 - x7.  |
765bdd1243dSDimitry Andric     // |                                 |
766bdd1243dSDimitry Andric     // |              ...                |
767bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 16]
768bdd1243dSDimitry Andric     // | Return address (x1) for caller  |
769bdd1243dSDimitry Andric     // | of __hwasan_check_*.            |
770bdd1243dSDimitry Andric     // +---------------------------------+ <-- [SP + 8]
771bdd1243dSDimitry Andric     // | Reserved place for x0, possibly |
772bdd1243dSDimitry Andric     // | junk, since we don't save it.   |
773bdd1243dSDimitry Andric     // +---------------------------------+ <-- [x2 / SP]
774bdd1243dSDimitry Andric 
775bdd1243dSDimitry Andric     // Adjust sp
776bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
777bdd1243dSDimitry Andric                                      .addReg(RISCV::X2)
778bdd1243dSDimitry Andric                                      .addReg(RISCV::X2)
779bdd1243dSDimitry Andric                                      .addImm(-256),
780bdd1243dSDimitry Andric                                  MCSTI);
781bdd1243dSDimitry Andric 
782bdd1243dSDimitry Andric     // store x10(arg0) by new sp
783bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
784bdd1243dSDimitry Andric                                      .addReg(RISCV::X10)
785bdd1243dSDimitry Andric                                      .addReg(RISCV::X2)
786bdd1243dSDimitry Andric                                      .addImm(8 * 10),
787bdd1243dSDimitry Andric                                  MCSTI);
788bdd1243dSDimitry Andric     // store x11(arg1) by new sp
789bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
790bdd1243dSDimitry Andric                                      .addReg(RISCV::X11)
791bdd1243dSDimitry Andric                                      .addReg(RISCV::X2)
792bdd1243dSDimitry Andric                                      .addImm(8 * 11),
793bdd1243dSDimitry Andric                                  MCSTI);
794bdd1243dSDimitry Andric 
795bdd1243dSDimitry Andric     // store x8(fp) by new sp
796bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
797bdd1243dSDimitry Andric         MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
798bdd1243dSDimitry Andric                                                                             8),
799bdd1243dSDimitry Andric         MCSTI);
800bdd1243dSDimitry Andric     // store x1(ra) by new sp
801bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
802bdd1243dSDimitry Andric         MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
803bdd1243dSDimitry Andric                                                                             8),
804bdd1243dSDimitry Andric         MCSTI);
805bdd1243dSDimitry Andric     if (Reg != RISCV::X10)
806bdd1243dSDimitry Andric       OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
807bdd1243dSDimitry Andric                                        .addReg(RISCV::X10)
808bdd1243dSDimitry Andric                                        .addReg(Reg)
809bdd1243dSDimitry Andric                                        .addImm(0),
810bdd1243dSDimitry Andric                                    MCSTI);
811bdd1243dSDimitry Andric     OutStreamer->emitInstruction(
812bdd1243dSDimitry Andric         MCInstBuilder(RISCV::ADDI)
813bdd1243dSDimitry Andric             .addReg(RISCV::X11)
814bdd1243dSDimitry Andric             .addReg(RISCV::X0)
815bdd1243dSDimitry Andric             .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),
816bdd1243dSDimitry Andric         MCSTI);
817bdd1243dSDimitry Andric 
818bdd1243dSDimitry Andric     OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
819bdd1243dSDimitry Andric                                  MCSTI);
820bdd1243dSDimitry Andric   }
821bdd1243dSDimitry Andric }
82206c3fb27SDimitry Andric 
lowerSymbolOperand(const MachineOperand & MO,MCSymbol * Sym,const AsmPrinter & AP)82306c3fb27SDimitry Andric static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
82406c3fb27SDimitry Andric                                     const AsmPrinter &AP) {
82506c3fb27SDimitry Andric   MCContext &Ctx = AP.OutContext;
82606c3fb27SDimitry Andric   RISCVMCExpr::VariantKind Kind;
82706c3fb27SDimitry Andric 
82806c3fb27SDimitry Andric   switch (MO.getTargetFlags()) {
82906c3fb27SDimitry Andric   default:
83006c3fb27SDimitry Andric     llvm_unreachable("Unknown target flag on GV operand");
83106c3fb27SDimitry Andric   case RISCVII::MO_None:
83206c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_None;
83306c3fb27SDimitry Andric     break;
83406c3fb27SDimitry Andric   case RISCVII::MO_CALL:
83506c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_CALL_PLT;
83606c3fb27SDimitry Andric     break;
83706c3fb27SDimitry Andric   case RISCVII::MO_LO:
83806c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_LO;
83906c3fb27SDimitry Andric     break;
84006c3fb27SDimitry Andric   case RISCVII::MO_HI:
84106c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_HI;
84206c3fb27SDimitry Andric     break;
84306c3fb27SDimitry Andric   case RISCVII::MO_PCREL_LO:
84406c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;
84506c3fb27SDimitry Andric     break;
84606c3fb27SDimitry Andric   case RISCVII::MO_PCREL_HI:
84706c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;
84806c3fb27SDimitry Andric     break;
84906c3fb27SDimitry Andric   case RISCVII::MO_GOT_HI:
85006c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_GOT_HI;
85106c3fb27SDimitry Andric     break;
85206c3fb27SDimitry Andric   case RISCVII::MO_TPREL_LO:
85306c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TPREL_LO;
85406c3fb27SDimitry Andric     break;
85506c3fb27SDimitry Andric   case RISCVII::MO_TPREL_HI:
85606c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TPREL_HI;
85706c3fb27SDimitry Andric     break;
85806c3fb27SDimitry Andric   case RISCVII::MO_TPREL_ADD:
85906c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TPREL_ADD;
86006c3fb27SDimitry Andric     break;
86106c3fb27SDimitry Andric   case RISCVII::MO_TLS_GOT_HI:
86206c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLS_GOT_HI;
86306c3fb27SDimitry Andric     break;
86406c3fb27SDimitry Andric   case RISCVII::MO_TLS_GD_HI:
86506c3fb27SDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI;
86606c3fb27SDimitry Andric     break;
8677a6dacacSDimitry Andric   case RISCVII::MO_TLSDESC_HI:
8687a6dacacSDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLSDESC_HI;
8697a6dacacSDimitry Andric     break;
8707a6dacacSDimitry Andric   case RISCVII::MO_TLSDESC_LOAD_LO:
8717a6dacacSDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO;
8727a6dacacSDimitry Andric     break;
8737a6dacacSDimitry Andric   case RISCVII::MO_TLSDESC_ADD_LO:
8747a6dacacSDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO;
8757a6dacacSDimitry Andric     break;
8767a6dacacSDimitry Andric   case RISCVII::MO_TLSDESC_CALL:
8777a6dacacSDimitry Andric     Kind = RISCVMCExpr::VK_RISCV_TLSDESC_CALL;
8787a6dacacSDimitry Andric     break;
87906c3fb27SDimitry Andric   }
88006c3fb27SDimitry Andric 
88106c3fb27SDimitry Andric   const MCExpr *ME =
88206c3fb27SDimitry Andric       MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);
88306c3fb27SDimitry Andric 
88406c3fb27SDimitry Andric   if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())
88506c3fb27SDimitry Andric     ME = MCBinaryExpr::createAdd(
88606c3fb27SDimitry Andric         ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);
88706c3fb27SDimitry Andric 
88806c3fb27SDimitry Andric   if (Kind != RISCVMCExpr::VK_RISCV_None)
88906c3fb27SDimitry Andric     ME = RISCVMCExpr::create(ME, Kind, Ctx);
89006c3fb27SDimitry Andric   return MCOperand::createExpr(ME);
89106c3fb27SDimitry Andric }
89206c3fb27SDimitry Andric 
lowerOperand(const MachineOperand & MO,MCOperand & MCOp) const89306c3fb27SDimitry Andric bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,
89406c3fb27SDimitry Andric                                    MCOperand &MCOp) const {
89506c3fb27SDimitry Andric   switch (MO.getType()) {
89606c3fb27SDimitry Andric   default:
89706c3fb27SDimitry Andric     report_fatal_error("lowerOperand: unknown operand type");
89806c3fb27SDimitry Andric   case MachineOperand::MO_Register:
89906c3fb27SDimitry Andric     // Ignore all implicit register operands.
90006c3fb27SDimitry Andric     if (MO.isImplicit())
90106c3fb27SDimitry Andric       return false;
90206c3fb27SDimitry Andric     MCOp = MCOperand::createReg(MO.getReg());
90306c3fb27SDimitry Andric     break;
90406c3fb27SDimitry Andric   case MachineOperand::MO_RegisterMask:
90506c3fb27SDimitry Andric     // Regmasks are like implicit defs.
90606c3fb27SDimitry Andric     return false;
90706c3fb27SDimitry Andric   case MachineOperand::MO_Immediate:
90806c3fb27SDimitry Andric     MCOp = MCOperand::createImm(MO.getImm());
90906c3fb27SDimitry Andric     break;
91006c3fb27SDimitry Andric   case MachineOperand::MO_MachineBasicBlock:
91106c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), *this);
91206c3fb27SDimitry Andric     break;
91306c3fb27SDimitry Andric   case MachineOperand::MO_GlobalAddress:
91406c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, getSymbolPreferLocal(*MO.getGlobal()), *this);
91506c3fb27SDimitry Andric     break;
91606c3fb27SDimitry Andric   case MachineOperand::MO_BlockAddress:
91706c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, GetBlockAddressSymbol(MO.getBlockAddress()),
91806c3fb27SDimitry Andric                               *this);
91906c3fb27SDimitry Andric     break;
92006c3fb27SDimitry Andric   case MachineOperand::MO_ExternalSymbol:
92106c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO.getSymbolName()),
92206c3fb27SDimitry Andric                               *this);
92306c3fb27SDimitry Andric     break;
92406c3fb27SDimitry Andric   case MachineOperand::MO_ConstantPoolIndex:
92506c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, GetCPISymbol(MO.getIndex()), *this);
92606c3fb27SDimitry Andric     break;
92706c3fb27SDimitry Andric   case MachineOperand::MO_JumpTableIndex:
92806c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, GetJTISymbol(MO.getIndex()), *this);
92906c3fb27SDimitry Andric     break;
93006c3fb27SDimitry Andric   case MachineOperand::MO_MCSymbol:
93106c3fb27SDimitry Andric     MCOp = lowerSymbolOperand(MO, MO.getMCSymbol(), *this);
93206c3fb27SDimitry Andric     break;
93306c3fb27SDimitry Andric   }
93406c3fb27SDimitry Andric   return true;
93506c3fb27SDimitry Andric }
93606c3fb27SDimitry Andric 
lowerRISCVVMachineInstrToMCInst(const MachineInstr * MI,MCInst & OutMI)93706c3fb27SDimitry Andric static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI,
93806c3fb27SDimitry Andric                                             MCInst &OutMI) {
93906c3fb27SDimitry Andric   const RISCVVPseudosTable::PseudoInfo *RVV =
94006c3fb27SDimitry Andric       RISCVVPseudosTable::getPseudoInfo(MI->getOpcode());
94106c3fb27SDimitry Andric   if (!RVV)
94206c3fb27SDimitry Andric     return false;
94306c3fb27SDimitry Andric 
94406c3fb27SDimitry Andric   OutMI.setOpcode(RVV->BaseInstr);
94506c3fb27SDimitry Andric 
94606c3fb27SDimitry Andric   const MachineBasicBlock *MBB = MI->getParent();
94706c3fb27SDimitry Andric   assert(MBB && "MI expected to be in a basic block");
94806c3fb27SDimitry Andric   const MachineFunction *MF = MBB->getParent();
94906c3fb27SDimitry Andric   assert(MF && "MBB expected to be in a machine function");
95006c3fb27SDimitry Andric 
95106c3fb27SDimitry Andric   const RISCVSubtarget &Subtarget = MF->getSubtarget<RISCVSubtarget>();
95206c3fb27SDimitry Andric   const TargetInstrInfo *TII = Subtarget.getInstrInfo();
95306c3fb27SDimitry Andric   const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();
95406c3fb27SDimitry Andric   assert(TRI && "TargetRegisterInfo expected");
95506c3fb27SDimitry Andric 
95606c3fb27SDimitry Andric   const MCInstrDesc &MCID = MI->getDesc();
95706c3fb27SDimitry Andric   uint64_t TSFlags = MCID.TSFlags;
95806c3fb27SDimitry Andric   unsigned NumOps = MI->getNumExplicitOperands();
95906c3fb27SDimitry Andric 
9605f757f3fSDimitry Andric   // Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if
9615f757f3fSDimitry Andric   // present.
96206c3fb27SDimitry Andric   if (RISCVII::hasVecPolicyOp(TSFlags))
96306c3fb27SDimitry Andric     --NumOps;
96406c3fb27SDimitry Andric   if (RISCVII::hasSEWOp(TSFlags))
96506c3fb27SDimitry Andric     --NumOps;
9665f757f3fSDimitry Andric   if (RISCVII::hasVLOp(TSFlags))
9675f757f3fSDimitry Andric     --NumOps;
96806c3fb27SDimitry Andric   if (RISCVII::hasRoundModeOp(TSFlags))
96906c3fb27SDimitry Andric     --NumOps;
97006c3fb27SDimitry Andric 
97106c3fb27SDimitry Andric   bool hasVLOutput = RISCV::isFaultFirstLoad(*MI);
97206c3fb27SDimitry Andric   for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {
97306c3fb27SDimitry Andric     const MachineOperand &MO = MI->getOperand(OpNo);
97406c3fb27SDimitry Andric     // Skip vl ouput. It should be the second output.
97506c3fb27SDimitry Andric     if (hasVLOutput && OpNo == 1)
97606c3fb27SDimitry Andric       continue;
97706c3fb27SDimitry Andric 
97806c3fb27SDimitry Andric     // Skip merge op. It should be the first operand after the defs.
97906c3fb27SDimitry Andric     if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {
98006c3fb27SDimitry Andric       assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&
98106c3fb27SDimitry Andric              "Expected tied to first def.");
98206c3fb27SDimitry Andric       const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
98306c3fb27SDimitry Andric       // Skip if the next operand in OutMI is not supposed to be tied. Unless it
98406c3fb27SDimitry Andric       // is a _TIED instruction.
98506c3fb27SDimitry Andric       if (OutMCID.getOperandConstraint(OutMI.getNumOperands(), MCOI::TIED_TO) <
98606c3fb27SDimitry Andric               0 &&
98706c3fb27SDimitry Andric           !RISCVII::isTiedPseudo(TSFlags))
98806c3fb27SDimitry Andric         continue;
98906c3fb27SDimitry Andric     }
99006c3fb27SDimitry Andric 
99106c3fb27SDimitry Andric     MCOperand MCOp;
99206c3fb27SDimitry Andric     switch (MO.getType()) {
99306c3fb27SDimitry Andric     default:
99406c3fb27SDimitry Andric       llvm_unreachable("Unknown operand type");
99506c3fb27SDimitry Andric     case MachineOperand::MO_Register: {
99606c3fb27SDimitry Andric       Register Reg = MO.getReg();
99706c3fb27SDimitry Andric 
99806c3fb27SDimitry Andric       if (RISCV::VRM2RegClass.contains(Reg) ||
99906c3fb27SDimitry Andric           RISCV::VRM4RegClass.contains(Reg) ||
100006c3fb27SDimitry Andric           RISCV::VRM8RegClass.contains(Reg)) {
100106c3fb27SDimitry Andric         Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
100206c3fb27SDimitry Andric         assert(Reg && "Subregister does not exist");
100306c3fb27SDimitry Andric       } else if (RISCV::FPR16RegClass.contains(Reg)) {
100406c3fb27SDimitry Andric         Reg =
100506c3fb27SDimitry Andric             TRI->getMatchingSuperReg(Reg, RISCV::sub_16, &RISCV::FPR32RegClass);
100606c3fb27SDimitry Andric         assert(Reg && "Subregister does not exist");
100706c3fb27SDimitry Andric       } else if (RISCV::FPR64RegClass.contains(Reg)) {
100806c3fb27SDimitry Andric         Reg = TRI->getSubReg(Reg, RISCV::sub_32);
100906c3fb27SDimitry Andric         assert(Reg && "Superregister does not exist");
101006c3fb27SDimitry Andric       } else if (RISCV::VRN2M1RegClass.contains(Reg) ||
101106c3fb27SDimitry Andric                  RISCV::VRN2M2RegClass.contains(Reg) ||
101206c3fb27SDimitry Andric                  RISCV::VRN2M4RegClass.contains(Reg) ||
101306c3fb27SDimitry Andric                  RISCV::VRN3M1RegClass.contains(Reg) ||
101406c3fb27SDimitry Andric                  RISCV::VRN3M2RegClass.contains(Reg) ||
101506c3fb27SDimitry Andric                  RISCV::VRN4M1RegClass.contains(Reg) ||
101606c3fb27SDimitry Andric                  RISCV::VRN4M2RegClass.contains(Reg) ||
101706c3fb27SDimitry Andric                  RISCV::VRN5M1RegClass.contains(Reg) ||
101806c3fb27SDimitry Andric                  RISCV::VRN6M1RegClass.contains(Reg) ||
101906c3fb27SDimitry Andric                  RISCV::VRN7M1RegClass.contains(Reg) ||
102006c3fb27SDimitry Andric                  RISCV::VRN8M1RegClass.contains(Reg)) {
102106c3fb27SDimitry Andric         Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);
102206c3fb27SDimitry Andric         assert(Reg && "Subregister does not exist");
102306c3fb27SDimitry Andric       }
102406c3fb27SDimitry Andric 
102506c3fb27SDimitry Andric       MCOp = MCOperand::createReg(Reg);
102606c3fb27SDimitry Andric       break;
102706c3fb27SDimitry Andric     }
102806c3fb27SDimitry Andric     case MachineOperand::MO_Immediate:
102906c3fb27SDimitry Andric       MCOp = MCOperand::createImm(MO.getImm());
103006c3fb27SDimitry Andric       break;
103106c3fb27SDimitry Andric     }
103206c3fb27SDimitry Andric     OutMI.addOperand(MCOp);
103306c3fb27SDimitry Andric   }
103406c3fb27SDimitry Andric 
103506c3fb27SDimitry Andric   // Unmasked pseudo instructions need to append dummy mask operand to
103606c3fb27SDimitry Andric   // V instructions. All V instructions are modeled as the masked version.
103706c3fb27SDimitry Andric   const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());
103806c3fb27SDimitry Andric   if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {
103906c3fb27SDimitry Andric     assert(OutMCID.operands()[OutMI.getNumOperands()].RegClass ==
104006c3fb27SDimitry Andric                RISCV::VMV0RegClassID &&
104106c3fb27SDimitry Andric            "Expected only mask operand to be missing");
104206c3fb27SDimitry Andric     OutMI.addOperand(MCOperand::createReg(RISCV::NoRegister));
104306c3fb27SDimitry Andric   }
104406c3fb27SDimitry Andric 
104506c3fb27SDimitry Andric   assert(OutMI.getNumOperands() == OutMCID.getNumOperands());
104606c3fb27SDimitry Andric   return true;
104706c3fb27SDimitry Andric }
104806c3fb27SDimitry Andric 
lowerToMCInst(const MachineInstr * MI,MCInst & OutMI)104906c3fb27SDimitry Andric bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {
105006c3fb27SDimitry Andric   if (lowerRISCVVMachineInstrToMCInst(MI, OutMI))
105106c3fb27SDimitry Andric     return false;
105206c3fb27SDimitry Andric 
105306c3fb27SDimitry Andric   OutMI.setOpcode(MI->getOpcode());
105406c3fb27SDimitry Andric 
105506c3fb27SDimitry Andric   for (const MachineOperand &MO : MI->operands()) {
105606c3fb27SDimitry Andric     MCOperand MCOp;
105706c3fb27SDimitry Andric     if (lowerOperand(MO, MCOp))
105806c3fb27SDimitry Andric       OutMI.addOperand(MCOp);
105906c3fb27SDimitry Andric   }
106006c3fb27SDimitry Andric 
106106c3fb27SDimitry Andric   switch (OutMI.getOpcode()) {
106206c3fb27SDimitry Andric   case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {
106306c3fb27SDimitry Andric     const Function &F = MI->getParent()->getParent()->getFunction();
106406c3fb27SDimitry Andric     if (F.hasFnAttribute("patchable-function-entry")) {
106506c3fb27SDimitry Andric       unsigned Num;
106606c3fb27SDimitry Andric       if (F.getFnAttribute("patchable-function-entry")
106706c3fb27SDimitry Andric               .getValueAsString()
106806c3fb27SDimitry Andric               .getAsInteger(10, Num))
106906c3fb27SDimitry Andric         return false;
107006c3fb27SDimitry Andric       emitNops(Num);
107106c3fb27SDimitry Andric       return true;
107206c3fb27SDimitry Andric     }
107306c3fb27SDimitry Andric     break;
107406c3fb27SDimitry Andric   }
107506c3fb27SDimitry Andric   }
107606c3fb27SDimitry Andric   return false;
107706c3fb27SDimitry Andric }
1078