Path: blob/main/contrib/llvm-project/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
35294 views
//===-- RISCVAsmPrinter.cpp - RISC-V LLVM assembly writer -----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file contains a printer that converts from our internal representation9// of machine-dependent LLVM code to the RISC-V assembly language.10//11//===----------------------------------------------------------------------===//1213#include "MCTargetDesc/RISCVBaseInfo.h"14#include "MCTargetDesc/RISCVInstPrinter.h"15#include "MCTargetDesc/RISCVMCExpr.h"16#include "MCTargetDesc/RISCVMatInt.h"17#include "MCTargetDesc/RISCVTargetStreamer.h"18#include "RISCV.h"19#include "RISCVMachineFunctionInfo.h"20#include "RISCVTargetMachine.h"21#include "TargetInfo/RISCVTargetInfo.h"22#include "llvm/ADT/APInt.h"23#include "llvm/ADT/Statistic.h"24#include "llvm/BinaryFormat/ELF.h"25#include "llvm/CodeGen/AsmPrinter.h"26#include "llvm/CodeGen/MachineConstantPool.h"27#include "llvm/CodeGen/MachineFunctionPass.h"28#include "llvm/CodeGen/MachineInstr.h"29#include "llvm/CodeGen/MachineModuleInfo.h"30#include "llvm/IR/Module.h"31#include "llvm/MC/MCAsmInfo.h"32#include "llvm/MC/MCContext.h"33#include "llvm/MC/MCInst.h"34#include "llvm/MC/MCInstBuilder.h"35#include "llvm/MC/MCObjectFileInfo.h"36#include "llvm/MC/MCSectionELF.h"37#include "llvm/MC/MCStreamer.h"38#include "llvm/MC/MCSymbol.h"39#include "llvm/MC/TargetRegistry.h"40#include "llvm/Support/raw_ostream.h"41#include "llvm/TargetParser/RISCVISAInfo.h"42#include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"4344using namespace llvm;4546#define DEBUG_TYPE "asm-printer"4748STATISTIC(RISCVNumInstrsCompressed,49"Number of RISC-V Compressed instructions emitted");5051namespace llvm {52extern const SubtargetFeatureKV RISCVFeatureKV[RISCV::NumSubtargetFeatures];53} // namespace llvm5455namespace {56class RISCVAsmPrinter : public AsmPrinter {57const RISCVSubtarget *STI;5859public:60explicit RISCVAsmPrinter(TargetMachine &TM,61std::unique_ptr<MCStreamer> Streamer)62: AsmPrinter(TM, std::move(Streamer)) {}6364StringRef getPassName() const override { return "RISC-V Assembly Printer"; }6566void LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,67const MachineInstr &MI);6869void LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,70const MachineInstr &MI);7172void LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,73const MachineInstr &MI);7475bool runOnMachineFunction(MachineFunction &MF) override;7677void emitInstruction(const MachineInstr *MI) override;7879bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,80const char *ExtraCode, raw_ostream &OS) override;81bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,82const char *ExtraCode, raw_ostream &OS) override;8384// Returns whether Inst is compressed.85bool EmitToStreamer(MCStreamer &S, const MCInst &Inst);86bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,87const MachineInstr *MI);8889typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;90std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;91void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);92void LowerKCFI_CHECK(const MachineInstr &MI);93void EmitHwasanMemaccessSymbols(Module &M);9495// Wrapper needed for tblgenned pseudo lowering.96bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const;9798void emitStartOfAsmFile(Module &M) override;99void emitEndOfAsmFile(Module &M) override;100101void emitFunctionEntryLabel() override;102bool emitDirectiveOptionArch();103104private:105void emitAttributes(const MCSubtargetInfo &SubtargetInfo);106107void emitNTLHint(const MachineInstr *MI);108109bool lowerToMCInst(const MachineInstr *MI, MCInst &OutMI);110};111}112113void RISCVAsmPrinter::LowerSTACKMAP(MCStreamer &OutStreamer, StackMaps &SM,114const MachineInstr &MI) {115unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;116unsigned NumNOPBytes = StackMapOpers(&MI).getNumPatchBytes();117118auto &Ctx = OutStreamer.getContext();119MCSymbol *MILabel = Ctx.createTempSymbol();120OutStreamer.emitLabel(MILabel);121122SM.recordStackMap(*MILabel, MI);123assert(NumNOPBytes % NOPBytes == 0 &&124"Invalid number of NOP bytes requested!");125126// Scan ahead to trim the shadow.127const MachineBasicBlock &MBB = *MI.getParent();128MachineBasicBlock::const_iterator MII(MI);129++MII;130while (NumNOPBytes > 0) {131if (MII == MBB.end() || MII->isCall() ||132MII->getOpcode() == RISCV::DBG_VALUE ||133MII->getOpcode() == TargetOpcode::PATCHPOINT ||134MII->getOpcode() == TargetOpcode::STACKMAP)135break;136++MII;137NumNOPBytes -= 4;138}139140// Emit nops.141emitNops(NumNOPBytes / NOPBytes);142}143144// Lower a patchpoint of the form:145// [<def>], <id>, <numBytes>, <target>, <numArgs>146void RISCVAsmPrinter::LowerPATCHPOINT(MCStreamer &OutStreamer, StackMaps &SM,147const MachineInstr &MI) {148unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;149150auto &Ctx = OutStreamer.getContext();151MCSymbol *MILabel = Ctx.createTempSymbol();152OutStreamer.emitLabel(MILabel);153SM.recordPatchPoint(*MILabel, MI);154155PatchPointOpers Opers(&MI);156157const MachineOperand &CalleeMO = Opers.getCallTarget();158unsigned EncodedBytes = 0;159160if (CalleeMO.isImm()) {161uint64_t CallTarget = CalleeMO.getImm();162if (CallTarget) {163assert((CallTarget & 0xFFFF'FFFF'FFFF) == CallTarget &&164"High 16 bits of call target should be zero.");165// Materialize the jump address:166SmallVector<MCInst, 8> Seq;167RISCVMatInt::generateMCInstSeq(CallTarget, *STI, RISCV::X1, Seq);168for (MCInst &Inst : Seq) {169bool Compressed = EmitToStreamer(OutStreamer, Inst);170EncodedBytes += Compressed ? 2 : 4;171}172bool Compressed = EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)173.addReg(RISCV::X1)174.addReg(RISCV::X1)175.addImm(0));176EncodedBytes += Compressed ? 2 : 4;177}178} else if (CalleeMO.isGlobal()) {179MCOperand CallTargetMCOp;180lowerOperand(CalleeMO, CallTargetMCOp);181EmitToStreamer(OutStreamer,182MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));183EncodedBytes += 8;184}185186// Emit padding.187unsigned NumBytes = Opers.getNumPatchBytes();188assert(NumBytes >= EncodedBytes &&189"Patchpoint can't request size less than the length of a call.");190assert((NumBytes - EncodedBytes) % NOPBytes == 0 &&191"Invalid number of NOP bytes requested!");192emitNops((NumBytes - EncodedBytes) / NOPBytes);193}194195void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,196const MachineInstr &MI) {197unsigned NOPBytes = STI->hasStdExtCOrZca() ? 2 : 4;198199StatepointOpers SOpers(&MI);200if (unsigned PatchBytes = SOpers.getNumPatchBytes()) {201assert(PatchBytes % NOPBytes == 0 &&202"Invalid number of NOP bytes requested!");203emitNops(PatchBytes / NOPBytes);204} else {205// Lower call target and choose correct opcode206const MachineOperand &CallTarget = SOpers.getCallTarget();207MCOperand CallTargetMCOp;208switch (CallTarget.getType()) {209case MachineOperand::MO_GlobalAddress:210case MachineOperand::MO_ExternalSymbol:211lowerOperand(CallTarget, CallTargetMCOp);212EmitToStreamer(213OutStreamer,214MCInstBuilder(RISCV::PseudoCALL).addOperand(CallTargetMCOp));215break;216case MachineOperand::MO_Immediate:217CallTargetMCOp = MCOperand::createImm(CallTarget.getImm());218EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JAL)219.addReg(RISCV::X1)220.addOperand(CallTargetMCOp));221break;222case MachineOperand::MO_Register:223CallTargetMCOp = MCOperand::createReg(CallTarget.getReg());224EmitToStreamer(OutStreamer, MCInstBuilder(RISCV::JALR)225.addReg(RISCV::X1)226.addOperand(CallTargetMCOp)227.addImm(0));228break;229default:230llvm_unreachable("Unsupported operand type in statepoint call target");231break;232}233}234235auto &Ctx = OutStreamer.getContext();236MCSymbol *MILabel = Ctx.createTempSymbol();237OutStreamer.emitLabel(MILabel);238SM.recordStatepoint(*MILabel, MI);239}240241bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {242MCInst CInst;243bool Res = RISCVRVC::compress(CInst, Inst, *STI);244if (Res)245++RISCVNumInstrsCompressed;246AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);247return Res;248}249250// Simple pseudo-instructions have their lowering (with expansion to real251// instructions) auto-generated.252#include "RISCVGenMCPseudoLowering.inc"253254// If the target supports Zihintntl and the instruction has a nontemporal255// MachineMemOperand, emit an NTLH hint instruction before it.256void RISCVAsmPrinter::emitNTLHint(const MachineInstr *MI) {257if (!STI->hasStdExtZihintntl())258return;259260if (MI->memoperands_empty())261return;262263MachineMemOperand *MMO = *(MI->memoperands_begin());264if (!MMO->isNonTemporal())265return;266267unsigned NontemporalMode = 0;268if (MMO->getFlags() & MONontemporalBit0)269NontemporalMode += 0b1;270if (MMO->getFlags() & MONontemporalBit1)271NontemporalMode += 0b10;272273MCInst Hint;274if (STI->hasStdExtCOrZca() && STI->enableRVCHintInstrs())275Hint.setOpcode(RISCV::C_ADD_HINT);276else277Hint.setOpcode(RISCV::ADD);278279Hint.addOperand(MCOperand::createReg(RISCV::X0));280Hint.addOperand(MCOperand::createReg(RISCV::X0));281Hint.addOperand(MCOperand::createReg(RISCV::X2 + NontemporalMode));282283EmitToStreamer(*OutStreamer, Hint);284}285286void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {287RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),288getSubtargetInfo().getFeatureBits());289290emitNTLHint(MI);291292// Do any auto-generated pseudo lowerings.293if (emitPseudoExpansionLowering(*OutStreamer, MI))294return;295296297switch (MI->getOpcode()) {298case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:299LowerHWASAN_CHECK_MEMACCESS(*MI);300return;301case RISCV::KCFI_CHECK:302LowerKCFI_CHECK(*MI);303return;304case RISCV::PseudoRVVInitUndefM1:305case RISCV::PseudoRVVInitUndefM2:306case RISCV::PseudoRVVInitUndefM4:307case RISCV::PseudoRVVInitUndefM8:308return;309case TargetOpcode::STACKMAP:310return LowerSTACKMAP(*OutStreamer, SM, *MI);311case TargetOpcode::PATCHPOINT:312return LowerPATCHPOINT(*OutStreamer, SM, *MI);313case TargetOpcode::STATEPOINT:314return LowerSTATEPOINT(*OutStreamer, SM, *MI);315}316317MCInst OutInst;318if (!lowerToMCInst(MI, OutInst))319EmitToStreamer(*OutStreamer, OutInst);320}321322bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,323const char *ExtraCode, raw_ostream &OS) {324// First try the generic code, which knows about modifiers like 'c' and 'n'.325if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))326return false;327328const MachineOperand &MO = MI->getOperand(OpNo);329if (ExtraCode && ExtraCode[0]) {330if (ExtraCode[1] != 0)331return true; // Unknown modifier.332333switch (ExtraCode[0]) {334default:335return true; // Unknown modifier.336case 'z': // Print zero register if zero, regular printing otherwise.337if (MO.isImm() && MO.getImm() == 0) {338OS << RISCVInstPrinter::getRegisterName(RISCV::X0);339return false;340}341break;342case 'i': // Literal 'i' if operand is not a register.343if (!MO.isReg())344OS << 'i';345return false;346}347}348349switch (MO.getType()) {350case MachineOperand::MO_Immediate:351OS << MO.getImm();352return false;353case MachineOperand::MO_Register:354OS << RISCVInstPrinter::getRegisterName(MO.getReg());355return false;356case MachineOperand::MO_GlobalAddress:357PrintSymbolOperand(MO, OS);358return false;359case MachineOperand::MO_BlockAddress: {360MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());361Sym->print(OS, MAI);362return false;363}364default:365break;366}367368return true;369}370371bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,372unsigned OpNo,373const char *ExtraCode,374raw_ostream &OS) {375if (ExtraCode)376return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);377378const MachineOperand &AddrReg = MI->getOperand(OpNo);379assert(MI->getNumOperands() > OpNo + 1 && "Expected additional operand");380const MachineOperand &Offset = MI->getOperand(OpNo + 1);381// All memory operands should have a register and an immediate operand (see382// RISCVDAGToDAGISel::SelectInlineAsmMemoryOperand).383if (!AddrReg.isReg())384return true;385if (!Offset.isImm() && !Offset.isGlobal() && !Offset.isBlockAddress() &&386!Offset.isMCSymbol())387return true;388389MCOperand MCO;390if (!lowerOperand(Offset, MCO))391return true;392393if (Offset.isImm())394OS << MCO.getImm();395else if (Offset.isGlobal() || Offset.isBlockAddress() || Offset.isMCSymbol())396OS << *MCO.getExpr();397OS << "(" << RISCVInstPrinter::getRegisterName(AddrReg.getReg()) << ")";398return false;399}400401bool RISCVAsmPrinter::emitDirectiveOptionArch() {402RISCVTargetStreamer &RTS =403static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());404SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;405const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();406for (const auto &Feature : RISCVFeatureKV) {407if (STI->hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))408continue;409410if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.Key))411continue;412413auto Delta = STI->hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus414: RISCVOptionArchArgType::Minus;415NeedEmitStdOptionArgs.emplace_back(Delta, Feature.Key);416}417if (!NeedEmitStdOptionArgs.empty()) {418RTS.emitDirectiveOptionPush();419RTS.emitDirectiveOptionArch(NeedEmitStdOptionArgs);420return true;421}422423return false;424}425426bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {427STI = &MF.getSubtarget<RISCVSubtarget>();428RISCVTargetStreamer &RTS =429static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());430431bool EmittedOptionArch = emitDirectiveOptionArch();432433SetupMachineFunction(MF);434emitFunctionBody();435436if (EmittedOptionArch)437RTS.emitDirectiveOptionPop();438return false;439}440441void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {442RISCVTargetStreamer &RTS =443static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());444if (const MDString *ModuleTargetABI =445dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))446RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));447448MCSubtargetInfo SubtargetInfo = *TM.getMCSubtargetInfo();449450// Use module flag to update feature bits.451if (auto *MD = dyn_cast_or_null<MDNode>(M.getModuleFlag("riscv-isa"))) {452for (auto &ISA : MD->operands()) {453if (auto *ISAString = dyn_cast_or_null<MDString>(ISA)) {454auto ParseResult = llvm::RISCVISAInfo::parseArchString(455ISAString->getString(), /*EnableExperimentalExtension=*/true,456/*ExperimentalExtensionVersionCheck=*/true);457if (!errorToBool(ParseResult.takeError())) {458auto &ISAInfo = *ParseResult;459for (const auto &Feature : RISCVFeatureKV) {460if (ISAInfo->hasExtension(Feature.Key) &&461!SubtargetInfo.hasFeature(Feature.Value))462SubtargetInfo.ToggleFeature(Feature.Key);463}464}465}466}467468RTS.setFlagsFromFeatures(SubtargetInfo);469}470471if (TM.getTargetTriple().isOSBinFormatELF())472emitAttributes(SubtargetInfo);473}474475void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {476RISCVTargetStreamer &RTS =477static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());478479if (TM.getTargetTriple().isOSBinFormatELF())480RTS.finishAttributeSection();481EmitHwasanMemaccessSymbols(M);482}483484void RISCVAsmPrinter::emitAttributes(const MCSubtargetInfo &SubtargetInfo) {485RISCVTargetStreamer &RTS =486static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());487// Use MCSubtargetInfo from TargetMachine. Individual functions may have488// attributes that differ from other functions in the module and we have no489// way to know which function is correct.490RTS.emitTargetAttributes(SubtargetInfo, /*EmitStackAlign*/ true);491}492493void RISCVAsmPrinter::emitFunctionEntryLabel() {494const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();495if (RMFI->isVectorCall()) {496auto &RTS =497static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());498RTS.emitDirectiveVariantCC(*CurrentFnSym);499}500return AsmPrinter::emitFunctionEntryLabel();501}502503// Force static initialization.504extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {505RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());506RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());507}508509void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {510Register Reg = MI.getOperand(0).getReg();511uint32_t AccessInfo = MI.getOperand(1).getImm();512MCSymbol *&Sym =513HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];514if (!Sym) {515// FIXME: Make this work on non-ELF.516if (!TM.getTargetTriple().isOSBinFormatELF())517report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");518519std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +520utostr(AccessInfo) + "_short";521Sym = OutContext.getOrCreateSymbol(SymName);522}523auto Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext);524auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);525526EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));527}528529void RISCVAsmPrinter::LowerKCFI_CHECK(const MachineInstr &MI) {530Register AddrReg = MI.getOperand(0).getReg();531assert(std::next(MI.getIterator())->isCall() &&532"KCFI_CHECK not followed by a call instruction");533assert(std::next(MI.getIterator())->getOperand(0).getReg() == AddrReg &&534"KCFI_CHECK call target doesn't match call operand");535536// Temporary registers for comparing the hashes. If a register is used537// for the call target, or reserved by the user, we can clobber another538// temporary register as the check is immediately followed by the539// call. The check defaults to X6/X7, but can fall back to X28-X31 if540// needed.541unsigned ScratchRegs[] = {RISCV::X6, RISCV::X7};542unsigned NextReg = RISCV::X28;543auto isRegAvailable = [&](unsigned Reg) {544return Reg != AddrReg && !STI->isRegisterReservedByUser(Reg);545};546for (auto &Reg : ScratchRegs) {547if (isRegAvailable(Reg))548continue;549while (!isRegAvailable(NextReg))550++NextReg;551Reg = NextReg++;552if (Reg > RISCV::X31)553report_fatal_error("Unable to find scratch registers for KCFI_CHECK");554}555556if (AddrReg == RISCV::X0) {557// Checking X0 makes no sense. Instead of emitting a load, zero558// ScratchRegs[0].559EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::ADDI)560.addReg(ScratchRegs[0])561.addReg(RISCV::X0)562.addImm(0));563} else {564// Adjust the offset for patchable-function-prefix. This assumes that565// patchable-function-prefix is the same for all functions.566int NopSize = STI->hasStdExtCOrZca() ? 2 : 4;567int64_t PrefixNops = 0;568(void)MI.getMF()569->getFunction()570.getFnAttribute("patchable-function-prefix")571.getValueAsString()572.getAsInteger(10, PrefixNops);573574// Load the target function type hash.575EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::LW)576.addReg(ScratchRegs[0])577.addReg(AddrReg)578.addImm(-(PrefixNops * NopSize + 4)));579}580581// Load the expected 32-bit type hash.582const int64_t Type = MI.getOperand(1).getImm();583const int64_t Hi20 = ((Type + 0x800) >> 12) & 0xFFFFF;584const int64_t Lo12 = SignExtend64<12>(Type);585if (Hi20) {586EmitToStreamer(587*OutStreamer,588MCInstBuilder(RISCV::LUI).addReg(ScratchRegs[1]).addImm(Hi20));589}590if (Lo12 || Hi20 == 0) {591EmitToStreamer(*OutStreamer,592MCInstBuilder((STI->hasFeature(RISCV::Feature64Bit) && Hi20)593? RISCV::ADDIW594: RISCV::ADDI)595.addReg(ScratchRegs[1])596.addReg(ScratchRegs[1])597.addImm(Lo12));598}599600// Compare the hashes and trap if there's a mismatch.601MCSymbol *Pass = OutContext.createTempSymbol();602EmitToStreamer(*OutStreamer,603MCInstBuilder(RISCV::BEQ)604.addReg(ScratchRegs[0])605.addReg(ScratchRegs[1])606.addExpr(MCSymbolRefExpr::create(Pass, OutContext)));607608MCSymbol *Trap = OutContext.createTempSymbol();609OutStreamer->emitLabel(Trap);610EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::EBREAK));611emitKCFITrapEntry(*MI.getMF(), Trap);612OutStreamer->emitLabel(Pass);613}614615void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {616if (HwasanMemaccessSymbols.empty())617return;618619assert(TM.getTargetTriple().isOSBinFormatELF());620// Use MCSubtargetInfo from TargetMachine. Individual functions may have621// attributes that differ from other functions in the module and we have no622// way to know which function is correct.623const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();624625MCSymbol *HwasanTagMismatchV2Sym =626OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");627// Annotate symbol as one having incompatible calling convention, so628// run-time linkers can instead eagerly bind this function.629auto &RTS =630static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());631RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);632633const MCSymbolRefExpr *HwasanTagMismatchV2Ref =634MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);635auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,636RISCVMCExpr::VK_RISCV_CALL, OutContext);637638for (auto &P : HwasanMemaccessSymbols) {639unsigned Reg = std::get<0>(P.first);640uint32_t AccessInfo = std::get<1>(P.first);641MCSymbol *Sym = P.second;642643unsigned Size =6441 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);645OutStreamer->switchSection(OutContext.getELFSection(646".text.hot", ELF::SHT_PROGBITS,647ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),648/*IsComdat=*/true));649650OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);651OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);652OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);653OutStreamer->emitLabel(Sym);654655// Extract shadow offset from ptr656OutStreamer->emitInstruction(657MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),658MCSTI);659OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)660.addReg(RISCV::X6)661.addReg(RISCV::X6)662.addImm(12),663MCSTI);664// load shadow tag in X6, X5 contains shadow base665OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)666.addReg(RISCV::X6)667.addReg(RISCV::X5)668.addReg(RISCV::X6),669MCSTI);670OutStreamer->emitInstruction(671MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),672MCSTI);673// Extract tag from X5 and compare it with loaded tag from shadow674OutStreamer->emitInstruction(675MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),676MCSTI);677MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();678// X7 contains tag from memory, while X6 contains tag from the pointer679OutStreamer->emitInstruction(680MCInstBuilder(RISCV::BNE)681.addReg(RISCV::X7)682.addReg(RISCV::X6)683.addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,684OutContext)),685MCSTI);686MCSymbol *ReturnSym = OutContext.createTempSymbol();687OutStreamer->emitLabel(ReturnSym);688OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)689.addReg(RISCV::X0)690.addReg(RISCV::X1)691.addImm(0),692MCSTI);693OutStreamer->emitLabel(HandleMismatchOrPartialSym);694695OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)696.addReg(RISCV::X28)697.addReg(RISCV::X0)698.addImm(16),699MCSTI);700MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();701OutStreamer->emitInstruction(702MCInstBuilder(RISCV::BGEU)703.addReg(RISCV::X6)704.addReg(RISCV::X28)705.addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),706MCSTI);707708OutStreamer->emitInstruction(709MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),710MCSTI);711712if (Size != 1)713OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)714.addReg(RISCV::X28)715.addReg(RISCV::X28)716.addImm(Size - 1),717MCSTI);718OutStreamer->emitInstruction(719MCInstBuilder(RISCV::BGE)720.addReg(RISCV::X28)721.addReg(RISCV::X6)722.addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),723MCSTI);724725OutStreamer->emitInstruction(726MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),727MCSTI);728OutStreamer->emitInstruction(729MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),730MCSTI);731OutStreamer->emitInstruction(732MCInstBuilder(RISCV::BEQ)733.addReg(RISCV::X6)734.addReg(RISCV::X7)735.addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),736MCSTI);737738OutStreamer->emitLabel(HandleMismatchSym);739740// | Previous stack frames... |741// +=================================+ <-- [SP + 256]742// | ... |743// | |744// | Stack frame space for x12 - x31.|745// | |746// | ... |747// +---------------------------------+ <-- [SP + 96]748// | Saved x11(arg1), as |749// | __hwasan_check_* clobbers it. |750// +---------------------------------+ <-- [SP + 88]751// | Saved x10(arg0), as |752// | __hwasan_check_* clobbers it. |753// +---------------------------------+ <-- [SP + 80]754// | |755// | Stack frame space for x9. |756// +---------------------------------+ <-- [SP + 72]757// | |758// | Saved x8(fp), as |759// | __hwasan_check_* clobbers it. |760// +---------------------------------+ <-- [SP + 64]761// | ... |762// | |763// | Stack frame space for x2 - x7. |764// | |765// | ... |766// +---------------------------------+ <-- [SP + 16]767// | Return address (x1) for caller |768// | of __hwasan_check_*. |769// +---------------------------------+ <-- [SP + 8]770// | Reserved place for x0, possibly |771// | junk, since we don't save it. |772// +---------------------------------+ <-- [x2 / SP]773774// Adjust sp775OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)776.addReg(RISCV::X2)777.addReg(RISCV::X2)778.addImm(-256),779MCSTI);780781// store x10(arg0) by new sp782OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)783.addReg(RISCV::X10)784.addReg(RISCV::X2)785.addImm(8 * 10),786MCSTI);787// store x11(arg1) by new sp788OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)789.addReg(RISCV::X11)790.addReg(RISCV::X2)791.addImm(8 * 11),792MCSTI);793794// store x8(fp) by new sp795OutStreamer->emitInstruction(796MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *7978),798MCSTI);799// store x1(ra) by new sp800OutStreamer->emitInstruction(801MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *8028),803MCSTI);804if (Reg != RISCV::X10)805OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)806.addReg(RISCV::X10)807.addReg(Reg)808.addImm(0),809MCSTI);810OutStreamer->emitInstruction(811MCInstBuilder(RISCV::ADDI)812.addReg(RISCV::X11)813.addReg(RISCV::X0)814.addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),815MCSTI);816817OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),818MCSTI);819}820}821822static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,823const AsmPrinter &AP) {824MCContext &Ctx = AP.OutContext;825RISCVMCExpr::VariantKind Kind;826827switch (MO.getTargetFlags()) {828default:829llvm_unreachable("Unknown target flag on GV operand");830case RISCVII::MO_None:831Kind = RISCVMCExpr::VK_RISCV_None;832break;833case RISCVII::MO_CALL:834Kind = RISCVMCExpr::VK_RISCV_CALL_PLT;835break;836case RISCVII::MO_LO:837Kind = RISCVMCExpr::VK_RISCV_LO;838break;839case RISCVII::MO_HI:840Kind = RISCVMCExpr::VK_RISCV_HI;841break;842case RISCVII::MO_PCREL_LO:843Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;844break;845case RISCVII::MO_PCREL_HI:846Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;847break;848case RISCVII::MO_GOT_HI:849Kind = RISCVMCExpr::VK_RISCV_GOT_HI;850break;851case RISCVII::MO_TPREL_LO:852Kind = RISCVMCExpr::VK_RISCV_TPREL_LO;853break;854case RISCVII::MO_TPREL_HI:855Kind = RISCVMCExpr::VK_RISCV_TPREL_HI;856break;857case RISCVII::MO_TPREL_ADD:858Kind = RISCVMCExpr::VK_RISCV_TPREL_ADD;859break;860case RISCVII::MO_TLS_GOT_HI:861Kind = RISCVMCExpr::VK_RISCV_TLS_GOT_HI;862break;863case RISCVII::MO_TLS_GD_HI:864Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI;865break;866case RISCVII::MO_TLSDESC_HI:867Kind = RISCVMCExpr::VK_RISCV_TLSDESC_HI;868break;869case RISCVII::MO_TLSDESC_LOAD_LO:870Kind = RISCVMCExpr::VK_RISCV_TLSDESC_LOAD_LO;871break;872case RISCVII::MO_TLSDESC_ADD_LO:873Kind = RISCVMCExpr::VK_RISCV_TLSDESC_ADD_LO;874break;875case RISCVII::MO_TLSDESC_CALL:876Kind = RISCVMCExpr::VK_RISCV_TLSDESC_CALL;877break;878}879880const MCExpr *ME =881MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, Ctx);882883if (!MO.isJTI() && !MO.isMBB() && MO.getOffset())884ME = MCBinaryExpr::createAdd(885ME, MCConstantExpr::create(MO.getOffset(), Ctx), Ctx);886887if (Kind != RISCVMCExpr::VK_RISCV_None)888ME = RISCVMCExpr::create(ME, Kind, Ctx);889return MCOperand::createExpr(ME);890}891892bool RISCVAsmPrinter::lowerOperand(const MachineOperand &MO,893MCOperand &MCOp) const {894switch (MO.getType()) {895default:896report_fatal_error("lowerOperand: unknown operand type");897case MachineOperand::MO_Register:898// Ignore all implicit register operands.899if (MO.isImplicit())900return false;901MCOp = MCOperand::createReg(MO.getReg());902break;903case MachineOperand::MO_RegisterMask:904// Regmasks are like implicit defs.905return false;906case MachineOperand::MO_Immediate:907MCOp = MCOperand::createImm(MO.getImm());908break;909case MachineOperand::MO_MachineBasicBlock:910MCOp = lowerSymbolOperand(MO, MO.getMBB()->getSymbol(), *this);911break;912case MachineOperand::MO_GlobalAddress:913MCOp = lowerSymbolOperand(MO, getSymbolPreferLocal(*MO.getGlobal()), *this);914break;915case MachineOperand::MO_BlockAddress:916MCOp = lowerSymbolOperand(MO, GetBlockAddressSymbol(MO.getBlockAddress()),917*this);918break;919case MachineOperand::MO_ExternalSymbol:920MCOp = lowerSymbolOperand(MO, GetExternalSymbolSymbol(MO.getSymbolName()),921*this);922break;923case MachineOperand::MO_ConstantPoolIndex:924MCOp = lowerSymbolOperand(MO, GetCPISymbol(MO.getIndex()), *this);925break;926case MachineOperand::MO_JumpTableIndex:927MCOp = lowerSymbolOperand(MO, GetJTISymbol(MO.getIndex()), *this);928break;929case MachineOperand::MO_MCSymbol:930MCOp = lowerSymbolOperand(MO, MO.getMCSymbol(), *this);931break;932}933return true;934}935936static bool lowerRISCVVMachineInstrToMCInst(const MachineInstr *MI,937MCInst &OutMI) {938const RISCVVPseudosTable::PseudoInfo *RVV =939RISCVVPseudosTable::getPseudoInfo(MI->getOpcode());940if (!RVV)941return false;942943OutMI.setOpcode(RVV->BaseInstr);944945const MachineBasicBlock *MBB = MI->getParent();946assert(MBB && "MI expected to be in a basic block");947const MachineFunction *MF = MBB->getParent();948assert(MF && "MBB expected to be in a machine function");949950const RISCVSubtarget &Subtarget = MF->getSubtarget<RISCVSubtarget>();951const TargetInstrInfo *TII = Subtarget.getInstrInfo();952const TargetRegisterInfo *TRI = Subtarget.getRegisterInfo();953assert(TRI && "TargetRegisterInfo expected");954955const MCInstrDesc &MCID = MI->getDesc();956uint64_t TSFlags = MCID.TSFlags;957unsigned NumOps = MI->getNumExplicitOperands();958959// Skip policy, SEW, VL, VXRM/FRM operands which are the last operands if960// present.961if (RISCVII::hasVecPolicyOp(TSFlags))962--NumOps;963if (RISCVII::hasSEWOp(TSFlags))964--NumOps;965if (RISCVII::hasVLOp(TSFlags))966--NumOps;967if (RISCVII::hasRoundModeOp(TSFlags))968--NumOps;969970bool hasVLOutput = RISCV::isFaultFirstLoad(*MI);971for (unsigned OpNo = 0; OpNo != NumOps; ++OpNo) {972const MachineOperand &MO = MI->getOperand(OpNo);973// Skip vl ouput. It should be the second output.974if (hasVLOutput && OpNo == 1)975continue;976977// Skip merge op. It should be the first operand after the defs.978if (OpNo == MI->getNumExplicitDefs() && MO.isReg() && MO.isTied()) {979assert(MCID.getOperandConstraint(OpNo, MCOI::TIED_TO) == 0 &&980"Expected tied to first def.");981const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());982// Skip if the next operand in OutMI is not supposed to be tied. Unless it983// is a _TIED instruction.984if (OutMCID.getOperandConstraint(OutMI.getNumOperands(), MCOI::TIED_TO) <9850 &&986!RISCVII::isTiedPseudo(TSFlags))987continue;988}989990MCOperand MCOp;991switch (MO.getType()) {992default:993llvm_unreachable("Unknown operand type");994case MachineOperand::MO_Register: {995Register Reg = MO.getReg();996997if (RISCV::VRM2RegClass.contains(Reg) ||998RISCV::VRM4RegClass.contains(Reg) ||999RISCV::VRM8RegClass.contains(Reg)) {1000Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);1001assert(Reg && "Subregister does not exist");1002} else if (RISCV::FPR16RegClass.contains(Reg)) {1003Reg =1004TRI->getMatchingSuperReg(Reg, RISCV::sub_16, &RISCV::FPR32RegClass);1005assert(Reg && "Subregister does not exist");1006} else if (RISCV::FPR64RegClass.contains(Reg)) {1007Reg = TRI->getSubReg(Reg, RISCV::sub_32);1008assert(Reg && "Superregister does not exist");1009} else if (RISCV::VRN2M1RegClass.contains(Reg) ||1010RISCV::VRN2M2RegClass.contains(Reg) ||1011RISCV::VRN2M4RegClass.contains(Reg) ||1012RISCV::VRN3M1RegClass.contains(Reg) ||1013RISCV::VRN3M2RegClass.contains(Reg) ||1014RISCV::VRN4M1RegClass.contains(Reg) ||1015RISCV::VRN4M2RegClass.contains(Reg) ||1016RISCV::VRN5M1RegClass.contains(Reg) ||1017RISCV::VRN6M1RegClass.contains(Reg) ||1018RISCV::VRN7M1RegClass.contains(Reg) ||1019RISCV::VRN8M1RegClass.contains(Reg)) {1020Reg = TRI->getSubReg(Reg, RISCV::sub_vrm1_0);1021assert(Reg && "Subregister does not exist");1022}10231024MCOp = MCOperand::createReg(Reg);1025break;1026}1027case MachineOperand::MO_Immediate:1028MCOp = MCOperand::createImm(MO.getImm());1029break;1030}1031OutMI.addOperand(MCOp);1032}10331034// Unmasked pseudo instructions need to append dummy mask operand to1035// V instructions. All V instructions are modeled as the masked version.1036const MCInstrDesc &OutMCID = TII->get(OutMI.getOpcode());1037if (OutMI.getNumOperands() < OutMCID.getNumOperands()) {1038assert(OutMCID.operands()[OutMI.getNumOperands()].RegClass ==1039RISCV::VMV0RegClassID &&1040"Expected only mask operand to be missing");1041OutMI.addOperand(MCOperand::createReg(RISCV::NoRegister));1042}10431044assert(OutMI.getNumOperands() == OutMCID.getNumOperands());1045return true;1046}10471048bool RISCVAsmPrinter::lowerToMCInst(const MachineInstr *MI, MCInst &OutMI) {1049if (lowerRISCVVMachineInstrToMCInst(MI, OutMI))1050return false;10511052OutMI.setOpcode(MI->getOpcode());10531054for (const MachineOperand &MO : MI->operands()) {1055MCOperand MCOp;1056if (lowerOperand(MO, MCOp))1057OutMI.addOperand(MCOp);1058}10591060switch (OutMI.getOpcode()) {1061case TargetOpcode::PATCHABLE_FUNCTION_ENTER: {1062const Function &F = MI->getParent()->getParent()->getFunction();1063if (F.hasFnAttribute("patchable-function-entry")) {1064unsigned Num;1065if (F.getFnAttribute("patchable-function-entry")1066.getValueAsString()1067.getAsInteger(10, Num))1068return false;1069emitNops(Num);1070return true;1071}1072break;1073}1074}1075return false;1076}107710781079