123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467 |
- //===-- RISCVAsmPrinter.cpp - RISCV LLVM assembly writer ------------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- //
- // This file contains a printer that converts from our internal representation
- // of machine-dependent LLVM code to the RISCV assembly language.
- //
- //===----------------------------------------------------------------------===//
- #include "MCTargetDesc/RISCVInstPrinter.h"
- #include "MCTargetDesc/RISCVMCExpr.h"
- #include "MCTargetDesc/RISCVTargetStreamer.h"
- #include "RISCV.h"
- #include "RISCVMachineFunctionInfo.h"
- #include "RISCVTargetMachine.h"
- #include "TargetInfo/RISCVTargetInfo.h"
- #include "llvm/ADT/Statistic.h"
- #include "llvm/BinaryFormat/ELF.h"
- #include "llvm/CodeGen/AsmPrinter.h"
- #include "llvm/CodeGen/MachineConstantPool.h"
- #include "llvm/CodeGen/MachineFunctionPass.h"
- #include "llvm/CodeGen/MachineInstr.h"
- #include "llvm/CodeGen/MachineModuleInfo.h"
- #include "llvm/MC/MCAsmInfo.h"
- #include "llvm/MC/MCContext.h"
- #include "llvm/MC/MCInst.h"
- #include "llvm/MC/MCInstBuilder.h"
- #include "llvm/MC/MCObjectFileInfo.h"
- #include "llvm/MC/MCSectionELF.h"
- #include "llvm/MC/MCStreamer.h"
- #include "llvm/MC/MCSymbol.h"
- #include "llvm/MC/TargetRegistry.h"
- #include "llvm/Support/raw_ostream.h"
- #include "llvm/Transforms/Instrumentation/HWAddressSanitizer.h"
- using namespace llvm;
- #define DEBUG_TYPE "asm-printer"
- STATISTIC(RISCVNumInstrsCompressed,
- "Number of RISC-V Compressed instructions emitted");
- namespace {
- class RISCVAsmPrinter : public AsmPrinter {
- const RISCVSubtarget *STI;
- public:
- explicit RISCVAsmPrinter(TargetMachine &TM,
- std::unique_ptr<MCStreamer> Streamer)
- : AsmPrinter(TM, std::move(Streamer)) {}
- StringRef getPassName() const override { return "RISCV Assembly Printer"; }
- bool runOnMachineFunction(MachineFunction &MF) override;
- void emitInstruction(const MachineInstr *MI) override;
- bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
- const char *ExtraCode, raw_ostream &OS) override;
- bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
- const char *ExtraCode, raw_ostream &OS) override;
- void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
- bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
- const MachineInstr *MI);
- typedef std::tuple<unsigned, uint32_t> HwasanMemaccessTuple;
- std::map<HwasanMemaccessTuple, MCSymbol *> HwasanMemaccessSymbols;
- void LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI);
- void EmitHwasanMemaccessSymbols(Module &M);
- // Wrapper needed for tblgenned pseudo lowering.
- bool lowerOperand(const MachineOperand &MO, MCOperand &MCOp) const {
- return lowerRISCVMachineOperandToMCOperand(MO, MCOp, *this);
- }
- void emitStartOfAsmFile(Module &M) override;
- void emitEndOfAsmFile(Module &M) override;
- void emitFunctionEntryLabel() override;
- private:
- void emitAttributes();
- };
- }
- void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
- MCInst CInst;
- bool Res = RISCVRVC::compress(CInst, Inst, *STI);
- if (Res)
- ++RISCVNumInstrsCompressed;
- AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
- }
- // Simple pseudo-instructions have their lowering (with expansion to real
- // instructions) auto-generated.
- #include "RISCVGenMCPseudoLowering.inc"
- void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) {
- RISCV_MC::verifyInstructionPredicates(MI->getOpcode(),
- getSubtargetInfo().getFeatureBits());
- // Do any auto-generated pseudo lowerings.
- if (emitPseudoExpansionLowering(*OutStreamer, MI))
- return;
- switch (MI->getOpcode()) {
- case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES:
- LowerHWASAN_CHECK_MEMACCESS(*MI);
- return;
- }
- MCInst TmpInst;
- if (!lowerRISCVMachineInstrToMCInst(MI, TmpInst, *this))
- EmitToStreamer(*OutStreamer, TmpInst);
- }
- bool RISCVAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
- const char *ExtraCode, raw_ostream &OS) {
- // First try the generic code, which knows about modifiers like 'c' and 'n'.
- if (!AsmPrinter::PrintAsmOperand(MI, OpNo, ExtraCode, OS))
- return false;
- const MachineOperand &MO = MI->getOperand(OpNo);
- if (ExtraCode && ExtraCode[0]) {
- if (ExtraCode[1] != 0)
- return true; // Unknown modifier.
- switch (ExtraCode[0]) {
- default:
- return true; // Unknown modifier.
- case 'z': // Print zero register if zero, regular printing otherwise.
- if (MO.isImm() && MO.getImm() == 0) {
- OS << RISCVInstPrinter::getRegisterName(RISCV::X0);
- return false;
- }
- break;
- case 'i': // Literal 'i' if operand is not a register.
- if (!MO.isReg())
- OS << 'i';
- return false;
- }
- }
- switch (MO.getType()) {
- case MachineOperand::MO_Immediate:
- OS << MO.getImm();
- return false;
- case MachineOperand::MO_Register:
- OS << RISCVInstPrinter::getRegisterName(MO.getReg());
- return false;
- case MachineOperand::MO_GlobalAddress:
- PrintSymbolOperand(MO, OS);
- return false;
- case MachineOperand::MO_BlockAddress: {
- MCSymbol *Sym = GetBlockAddressSymbol(MO.getBlockAddress());
- Sym->print(OS, MAI);
- return false;
- }
- default:
- break;
- }
- return true;
- }
- bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
- unsigned OpNo,
- const char *ExtraCode,
- raw_ostream &OS) {
- if (!ExtraCode) {
- const MachineOperand &MO = MI->getOperand(OpNo);
- // For now, we only support register memory operands in registers and
- // assume there is no addend
- if (!MO.isReg())
- return true;
- OS << "0(" << RISCVInstPrinter::getRegisterName(MO.getReg()) << ")";
- return false;
- }
- return AsmPrinter::PrintAsmMemoryOperand(MI, OpNo, ExtraCode, OS);
- }
- bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
- STI = &MF.getSubtarget<RISCVSubtarget>();
- SetupMachineFunction(MF);
- emitFunctionBody();
- return false;
- }
- void RISCVAsmPrinter::emitStartOfAsmFile(Module &M) {
- RISCVTargetStreamer &RTS =
- static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
- if (const MDString *ModuleTargetABI =
- dyn_cast_or_null<MDString>(M.getModuleFlag("target-abi")))
- RTS.setTargetABI(RISCVABI::getTargetABI(ModuleTargetABI->getString()));
- if (TM.getTargetTriple().isOSBinFormatELF())
- emitAttributes();
- }
- void RISCVAsmPrinter::emitEndOfAsmFile(Module &M) {
- RISCVTargetStreamer &RTS =
- static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
- if (TM.getTargetTriple().isOSBinFormatELF())
- RTS.finishAttributeSection();
- EmitHwasanMemaccessSymbols(M);
- }
- void RISCVAsmPrinter::emitAttributes() {
- RISCVTargetStreamer &RTS =
- static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
- // Use MCSubtargetInfo from TargetMachine. Individual functions may have
- // attributes that differ from other functions in the module and we have no
- // way to know which function is correct.
- RTS.emitTargetAttributes(*TM.getMCSubtargetInfo());
- }
- void RISCVAsmPrinter::emitFunctionEntryLabel() {
- const auto *RMFI = MF->getInfo<RISCVMachineFunctionInfo>();
- if (RMFI->isVectorCall()) {
- auto &RTS =
- static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
- RTS.emitDirectiveVariantCC(*CurrentFnSym);
- }
- return AsmPrinter::emitFunctionEntryLabel();
- }
- // Force static initialization.
- extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() {
- RegisterAsmPrinter<RISCVAsmPrinter> X(getTheRISCV32Target());
- RegisterAsmPrinter<RISCVAsmPrinter> Y(getTheRISCV64Target());
- }
- void RISCVAsmPrinter::LowerHWASAN_CHECK_MEMACCESS(const MachineInstr &MI) {
- Register Reg = MI.getOperand(0).getReg();
- uint32_t AccessInfo = MI.getOperand(1).getImm();
- MCSymbol *&Sym =
- HwasanMemaccessSymbols[HwasanMemaccessTuple(Reg, AccessInfo)];
- if (!Sym) {
- // FIXME: Make this work on non-ELF.
- if (!TM.getTargetTriple().isOSBinFormatELF())
- report_fatal_error("llvm.hwasan.check.memaccess only supported on ELF");
- std::string SymName = "__hwasan_check_x" + utostr(Reg - RISCV::X0) + "_" +
- utostr(AccessInfo) + "_short";
- Sym = OutContext.getOrCreateSymbol(SymName);
- }
- auto Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, OutContext);
- auto Expr = RISCVMCExpr::create(Res, RISCVMCExpr::VK_RISCV_CALL, OutContext);
- EmitToStreamer(*OutStreamer, MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr));
- }
- void RISCVAsmPrinter::EmitHwasanMemaccessSymbols(Module &M) {
- if (HwasanMemaccessSymbols.empty())
- return;
- assert(TM.getTargetTriple().isOSBinFormatELF());
- // Use MCSubtargetInfo from TargetMachine. Individual functions may have
- // attributes that differ from other functions in the module and we have no
- // way to know which function is correct.
- const MCSubtargetInfo &MCSTI = *TM.getMCSubtargetInfo();
- MCSymbol *HwasanTagMismatchV2Sym =
- OutContext.getOrCreateSymbol("__hwasan_tag_mismatch_v2");
- // Annotate symbol as one having incompatible calling convention, so
- // run-time linkers can instead eagerly bind this function.
- auto &RTS =
- static_cast<RISCVTargetStreamer &>(*OutStreamer->getTargetStreamer());
- RTS.emitDirectiveVariantCC(*HwasanTagMismatchV2Sym);
- const MCSymbolRefExpr *HwasanTagMismatchV2Ref =
- MCSymbolRefExpr::create(HwasanTagMismatchV2Sym, OutContext);
- auto Expr = RISCVMCExpr::create(HwasanTagMismatchV2Ref,
- RISCVMCExpr::VK_RISCV_CALL, OutContext);
- for (auto &P : HwasanMemaccessSymbols) {
- unsigned Reg = std::get<0>(P.first);
- uint32_t AccessInfo = std::get<1>(P.first);
- MCSymbol *Sym = P.second;
- unsigned Size =
- 1 << ((AccessInfo >> HWASanAccessInfo::AccessSizeShift) & 0xf);
- OutStreamer->switchSection(OutContext.getELFSection(
- ".text.hot", ELF::SHT_PROGBITS,
- ELF::SHF_EXECINSTR | ELF::SHF_ALLOC | ELF::SHF_GROUP, 0, Sym->getName(),
- /*IsComdat=*/true));
- OutStreamer->emitSymbolAttribute(Sym, MCSA_ELF_TypeFunction);
- OutStreamer->emitSymbolAttribute(Sym, MCSA_Weak);
- OutStreamer->emitSymbolAttribute(Sym, MCSA_Hidden);
- OutStreamer->emitLabel(Sym);
- // Extract shadow offset from ptr
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::SLLI).addReg(RISCV::X6).addReg(Reg).addImm(8),
- MCSTI);
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::SRLI)
- .addReg(RISCV::X6)
- .addReg(RISCV::X6)
- .addImm(12),
- MCSTI);
- // load shadow tag in X6, X5 contains shadow base
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADD)
- .addReg(RISCV::X6)
- .addReg(RISCV::X5)
- .addReg(RISCV::X6),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
- MCSTI);
- // Extract tag from X5 and compare it with loaded tag from shadow
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::SRLI).addReg(RISCV::X7).addReg(Reg).addImm(56),
- MCSTI);
- MCSymbol *HandleMismatchOrPartialSym = OutContext.createTempSymbol();
- // X7 contains tag from memory, while X6 contains tag from the pointer
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::BNE)
- .addReg(RISCV::X7)
- .addReg(RISCV::X6)
- .addExpr(MCSymbolRefExpr::create(HandleMismatchOrPartialSym,
- OutContext)),
- MCSTI);
- MCSymbol *ReturnSym = OutContext.createTempSymbol();
- OutStreamer->emitLabel(ReturnSym);
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::JALR)
- .addReg(RISCV::X0)
- .addReg(RISCV::X1)
- .addImm(0),
- MCSTI);
- OutStreamer->emitLabel(HandleMismatchOrPartialSym);
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
- .addReg(RISCV::X28)
- .addReg(RISCV::X0)
- .addImm(16),
- MCSTI);
- MCSymbol *HandleMismatchSym = OutContext.createTempSymbol();
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::BGEU)
- .addReg(RISCV::X6)
- .addReg(RISCV::X28)
- .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::ANDI).addReg(RISCV::X28).addReg(Reg).addImm(0xF),
- MCSTI);
- if (Size != 1)
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
- .addReg(RISCV::X28)
- .addReg(RISCV::X28)
- .addImm(Size - 1),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::BGE)
- .addReg(RISCV::X28)
- .addReg(RISCV::X6)
- .addExpr(MCSymbolRefExpr::create(HandleMismatchSym, OutContext)),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::ORI).addReg(RISCV::X6).addReg(Reg).addImm(0xF),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::LBU).addReg(RISCV::X6).addReg(RISCV::X6).addImm(0),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::BEQ)
- .addReg(RISCV::X6)
- .addReg(RISCV::X7)
- .addExpr(MCSymbolRefExpr::create(ReturnSym, OutContext)),
- MCSTI);
- OutStreamer->emitLabel(HandleMismatchSym);
- // | Previous stack frames... |
- // +=================================+ <-- [SP + 256]
- // | ... |
- // | |
- // | Stack frame space for x12 - x31.|
- // | |
- // | ... |
- // +---------------------------------+ <-- [SP + 96]
- // | Saved x11(arg1), as |
- // | __hwasan_check_* clobbers it. |
- // +---------------------------------+ <-- [SP + 88]
- // | Saved x10(arg0), as |
- // | __hwasan_check_* clobbers it. |
- // +---------------------------------+ <-- [SP + 80]
- // | |
- // | Stack frame space for x9. |
- // +---------------------------------+ <-- [SP + 72]
- // | |
- // | Saved x8(fp), as |
- // | __hwasan_check_* clobbers it. |
- // +---------------------------------+ <-- [SP + 64]
- // | ... |
- // | |
- // | Stack frame space for x2 - x7. |
- // | |
- // | ... |
- // +---------------------------------+ <-- [SP + 16]
- // | Return address (x1) for caller |
- // | of __hwasan_check_*. |
- // +---------------------------------+ <-- [SP + 8]
- // | Reserved place for x0, possibly |
- // | junk, since we don't save it. |
- // +---------------------------------+ <-- [x2 / SP]
- // Adjust sp
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
- .addReg(RISCV::X2)
- .addReg(RISCV::X2)
- .addImm(-256),
- MCSTI);
- // store x10(arg0) by new sp
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
- .addReg(RISCV::X10)
- .addReg(RISCV::X2)
- .addImm(8 * 10),
- MCSTI);
- // store x11(arg1) by new sp
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::SD)
- .addReg(RISCV::X11)
- .addReg(RISCV::X2)
- .addImm(8 * 11),
- MCSTI);
- // store x8(fp) by new sp
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::SD).addReg(RISCV::X8).addReg(RISCV::X2).addImm(8 *
- 8),
- MCSTI);
- // store x1(ra) by new sp
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::SD).addReg(RISCV::X1).addReg(RISCV::X2).addImm(1 *
- 8),
- MCSTI);
- if (Reg != RISCV::X10)
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::ADDI)
- .addReg(RISCV::X10)
- .addReg(Reg)
- .addImm(0),
- MCSTI);
- OutStreamer->emitInstruction(
- MCInstBuilder(RISCV::ADDI)
- .addReg(RISCV::X11)
- .addReg(RISCV::X0)
- .addImm(AccessInfo & HWASanAccessInfo::RuntimeMask),
- MCSTI);
- OutStreamer->emitInstruction(MCInstBuilder(RISCV::PseudoCALL).addExpr(Expr),
- MCSTI);
- }
- }
|