Index: llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def =================================================================== --- llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def +++ llvm/include/llvm/BinaryFormat/ELFRelocs/RISCV.def @@ -58,3 +58,10 @@ ELF_RELOC(R_RISCV_SET32, 56) ELF_RELOC(R_RISCV_32_PCREL, 57) ELF_RELOC(R_RISCV_IRELATIVE, 58) +/* Overlay extension - awaiting real numbers as part of RISC-V psABI */ +ELF_RELOC(R_RISCV_OVLTOK_HI20, 220) +ELF_RELOC(R_RISCV_OVLTOK_LO12_I, 221) +ELF_RELOC(R_RISCV_OVLTOK32, 222) +ELF_RELOC(R_RISCV_OVLPLT_HI20, 223) +ELF_RELOC(R_RISCV_OVLPLT_LO12_I, 224) +ELF_RELOC(R_RISCV_OVLPLT32, 225) Index: llvm/include/llvm/IR/Attributes.td =================================================================== --- llvm/include/llvm/IR/Attributes.td +++ llvm/include/llvm/IR/Attributes.td @@ -320,6 +320,7 @@ def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; def : CompatRule<"isEqual">; +def : CompatRule<"isOverlayInlineCompat">; class MergeRule { // The name of the function called to merge the attributes of the caller and Index: llvm/include/llvm/MC/MCExpr.h =================================================================== --- llvm/include/llvm/MC/MCExpr.h +++ llvm/include/llvm/MC/MCExpr.h @@ -352,6 +352,9 @@ VK_VE_TPOFF_HI32, // symbol@tpoff_hi VK_VE_TPOFF_LO32, // symbol@tpoff_lo + VK_RISCV_OVL, // symbol@ovl + VK_RISCV_OVLPLT, // symbol@ovlplt + VK_TPREL, VK_DTPREL }; Index: llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp =================================================================== --- llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp +++ llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp @@ -624,6 +624,14 @@ Name = getSectionPrefixForGlobal(Kind); } + // For overlay functions or data, prefix the default section name with + // ".ovlinput" + // For overlay functions, replace the default section name with ".ovlinput" + if ((isa(GO) && cast(GO)->hasFnAttribute("overlay")) || + (isa(GO) && + cast(GO)->hasAttribute("overlay"))) + Name = ".ovlinput"; + bool HasPrefix = false; if (const auto *F = dyn_cast(GO)) { if (Optional Prefix = F->getSectionPrefix()) { @@ -885,6 +893,14 @@ EmitUniqueSection = TM.getDataSections(); } EmitUniqueSection |= GO->hasComdat(); + + if (Kind.isText() && isa(GO) && + cast(GO)->hasFnAttribute("overlay")) + EmitUniqueSection = true; + if (isa(GO) && + cast(GO)->hasAttribute("overlay")) + EmitUniqueSection = true; + return selectELFSectionForGlobal(getContext(), GO, Kind, getMangler(), TM, Used.count(GO), EmitUniqueSection, Flags, &NextUniqueID); Index: llvm/lib/IR/Attributes.cpp =================================================================== --- llvm/lib/IR/Attributes.cpp +++ llvm/lib/IR/Attributes.cpp @@ -1961,6 +1961,13 @@ AttrClass::set(Caller, AttrClass::getKind(), true); } +/// Check whether it is safe to inline functions marked with the 'overlay' +/// attribute. +static bool isOverlayInlineCompat(const Function &Caller, + const Function &Callee) { + return !Caller.hasFnAttribute("overlay") && !Callee.hasFnAttribute("overlay"); +} + /// If the inlined function had a higher stack protection level than the /// calling function, then bump up the caller's stack protection level. static void adjustCallerSSPLevel(Function &Caller, const Function &Callee) { Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -1119,7 +1119,9 @@ continue; GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global : GlobalValue::UnnamedAddr::None); - if (EnableLTOInternalization && R.second.Partition == 0) + bool IsOverlay = + isa(GV) && cast(GV)->hasFnAttribute("overlay"); + if (EnableLTOInternalization && R.second.Partition == 0 && !IsOverlay) GV->setLinkage(GlobalValue::InternalLinkage); } Index: llvm/lib/MC/MCExpr.cpp =================================================================== --- llvm/lib/MC/MCExpr.cpp +++ llvm/lib/MC/MCExpr.cpp @@ -379,6 +379,8 @@ case VK_VE_TLS_GD_LO32: return "tls_gd_lo"; case VK_VE_TPOFF_HI32: return "tpoff_hi"; case VK_VE_TPOFF_LO32: return "tpoff_lo"; + case VK_RISCV_OVLPLT: return "ovlplt"; + case VK_RISCV_OVL: return "ovl"; } llvm_unreachable("Invalid variant kind"); } @@ -520,6 +522,8 @@ .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) .Case("tpoff_hi", VK_VE_TPOFF_HI32) .Case("tpoff_lo", VK_VE_TPOFF_LO32) + .Case("ovlplt", VK_RISCV_OVLPLT) + .Case("ovl", VK_RISCV_OVL) .Default(VK_Invalid); } Index: llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp =================================================================== --- llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp +++ llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp @@ -59,6 +59,7 @@ class RISCVAsmParser : public MCTargetAsmParser { SmallVector FeatureBitStack; + bool WarnOnReservedReg = true; SmallVector ParserOptionsStack; ParserOptionsSet ParserOptions; @@ -618,7 +619,9 @@ return IsValid && ((IsConstantImm && VK == RISCVMCExpr::VK_RISCV_None) || VK == RISCVMCExpr::VK_RISCV_LO || VK == RISCVMCExpr::VK_RISCV_PCREL_LO || - VK == RISCVMCExpr::VK_RISCV_TPREL_LO); + VK == RISCVMCExpr::VK_RISCV_TPREL_LO || + VK == RISCVMCExpr::VK_RISCV_OVLPLT_LO || + VK == RISCVMCExpr::VK_RISCV_OVLTOK_LO); } bool isSImm12Lsb0() const { return isBareSimmNLsb0<12>(); } @@ -645,11 +648,15 @@ if (!IsConstantImm) { IsValid = RISCVAsmParser::classifySymbolRef(getImm(), VK); return IsValid && (VK == RISCVMCExpr::VK_RISCV_HI || - VK == RISCVMCExpr::VK_RISCV_TPREL_HI); + VK == RISCVMCExpr::VK_RISCV_TPREL_HI || + VK == RISCVMCExpr::VK_RISCV_OVLPLT_HI || + VK == RISCVMCExpr::VK_RISCV_OVLTOK_HI); } else { return isUInt<20>(Imm) && (VK == RISCVMCExpr::VK_RISCV_None || VK == RISCVMCExpr::VK_RISCV_HI || - VK == RISCVMCExpr::VK_RISCV_TPREL_HI); + VK == RISCVMCExpr::VK_RISCV_TPREL_HI || + VK == RISCVMCExpr::VK_RISCV_OVLPLT_HI || + VK == RISCVMCExpr::VK_RISCV_OVLTOK_HI); } } @@ -1951,10 +1958,34 @@ return false; } + if (Option == "warnreservedreg") { + getTargetStreamer().emitDirectiveOptionWarnReservedReg(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + WarnOnReservedReg = true; + return false; + } + + if (Option == "nowarnreservedreg") { + getTargetStreamer().emitDirectiveOptionNoWarnReservedReg(); + + Parser.Lex(); + if (Parser.getTok().isNot(AsmToken::EndOfStatement)) + return Error(Parser.getTok().getLoc(), + "unexpected token, expected end of statement"); + + WarnOnReservedReg = false; + return false; + } + // Unknown option. Warning(Parser.getTok().getLoc(), - "unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax' or " - "'norelax'"); + "unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax', " + "'norelax', 'warnreservedreg' or 'nowarnreservedreg'"); Parser.eatToEndOfStatement(); return false; } @@ -2200,7 +2231,55 @@ return false; } +// Since only a RISCVGenSubtargetInfo is available here, extract register +// reservation directly from the STI bitfields. +static bool isRegisterReserved(MCRegister Reg, const MCSubtargetInfo &STI) { + switch (Reg) { + default: return false; + case RISCV::X1: return STI.getFeatureBits()[RISCV::FeatureReserveX1]; + case RISCV::X2: return STI.getFeatureBits()[RISCV::FeatureReserveX2]; + case RISCV::X3: return STI.getFeatureBits()[RISCV::FeatureReserveX3]; + case RISCV::X4: return STI.getFeatureBits()[RISCV::FeatureReserveX4]; + case RISCV::X5: return STI.getFeatureBits()[RISCV::FeatureReserveX5]; + case RISCV::X6: return STI.getFeatureBits()[RISCV::FeatureReserveX6]; + case RISCV::X7: return STI.getFeatureBits()[RISCV::FeatureReserveX7]; + case RISCV::X8: return STI.getFeatureBits()[RISCV::FeatureReserveX8]; + case RISCV::X9: return STI.getFeatureBits()[RISCV::FeatureReserveX9]; + case RISCV::X10: return STI.getFeatureBits()[RISCV::FeatureReserveX10]; + case RISCV::X11: return STI.getFeatureBits()[RISCV::FeatureReserveX11]; + case RISCV::X12: return STI.getFeatureBits()[RISCV::FeatureReserveX12]; + case RISCV::X13: return STI.getFeatureBits()[RISCV::FeatureReserveX13]; + case RISCV::X14: return STI.getFeatureBits()[RISCV::FeatureReserveX14]; + case RISCV::X15: return STI.getFeatureBits()[RISCV::FeatureReserveX15]; + case RISCV::X16: return STI.getFeatureBits()[RISCV::FeatureReserveX16]; + case RISCV::X17: return STI.getFeatureBits()[RISCV::FeatureReserveX17]; + case RISCV::X18: return STI.getFeatureBits()[RISCV::FeatureReserveX18]; + case RISCV::X19: return STI.getFeatureBits()[RISCV::FeatureReserveX19]; + case RISCV::X20: return STI.getFeatureBits()[RISCV::FeatureReserveX20]; + case RISCV::X21: return STI.getFeatureBits()[RISCV::FeatureReserveX21]; + case RISCV::X22: return STI.getFeatureBits()[RISCV::FeatureReserveX22]; + case RISCV::X23: return STI.getFeatureBits()[RISCV::FeatureReserveX23]; + case RISCV::X24: return STI.getFeatureBits()[RISCV::FeatureReserveX24]; + case RISCV::X25: return STI.getFeatureBits()[RISCV::FeatureReserveX25]; + case RISCV::X26: return STI.getFeatureBits()[RISCV::FeatureReserveX26]; + case RISCV::X27: return STI.getFeatureBits()[RISCV::FeatureReserveX27]; + case RISCV::X28: return STI.getFeatureBits()[RISCV::FeatureReserveX28]; + case RISCV::X29: return STI.getFeatureBits()[RISCV::FeatureReserveX29]; + case RISCV::X30: return STI.getFeatureBits()[RISCV::FeatureReserveX30]; + case RISCV::X31: return STI.getFeatureBits()[RISCV::FeatureReserveX31]; + } +} + void RISCVAsmParser::emitToStreamer(MCStreamer &S, const MCInst &Inst) { + // Provide a warning about defs of reserved registers. + auto &Desc = MII.get(Inst.getOpcode()); + for (unsigned i = 0; i < Desc.getNumDefs(); i++) { + if (Inst.getOperand(i).isReg() && + isRegisterReserved(Inst.getOperand(i).getReg(), getSTI()) && + WarnOnReservedReg) + Warning(Inst.getLoc(), "Instruction modifies reserved register"); + } + MCInst CInst; bool Res = compressInst(CInst, Inst, getSTI(), S.getContext()); if (Res) Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVAsmBackend.cpp @@ -93,6 +93,11 @@ {"fixup_riscv_set_6b", 2, 6, 0}, {"fixup_riscv_sub_6b", 2, 6, 0}, + + {"fixup_riscv_ovltok_hi20", 12, 20, 0}, + {"fixup_riscv_ovltok_lo12_i", 20, 12, 0}, + {"fixup_riscv_ovlplt_hi20", 12, 20, 0}, + {"fixup_riscv_ovlplt_lo12_i", 20, 12, 0}, }; static_assert((array_lengthof(Infos)) == RISCV::NumTargetFixupKinds, "Not all fixup kinds added to Infos array"); Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h @@ -157,11 +157,15 @@ MO_TPREL_ADD = 10, MO_TLS_GOT_HI = 11, MO_TLS_GD_HI = 12, + MO_OVLTOK_LO = 13, + MO_OVLTOK_HI = 14, + MO_OVLPLT_LO = 15, + MO_OVLPLT_HI = 16, // Used to differentiate between target-specific "direct" flags and "bitmask" // flags. A machine operand can only have one "direct" flag, but can have // multiple "bitmask" flags. - MO_DIRECT_FLAG_MASK = 15 + MO_DIRECT_FLAG_MASK = 31 }; } // namespace RISCVII Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFObjectWriter.cpp @@ -119,6 +119,14 @@ if (Expr->getKind() == MCExpr::Target && cast(Expr)->getKind() == RISCVMCExpr::VK_RISCV_32_PCREL) return ELF::R_RISCV_32_PCREL; + if (Expr->getKind() == MCExpr::SymbolRef && + cast(Expr)->getKind() == + MCSymbolRefExpr::VK_RISCV_OVLPLT) + return ELF::R_RISCV_OVLPLT32; + if (Expr->getKind() == MCExpr::SymbolRef && + cast(Expr)->getKind() == + MCSymbolRefExpr::VK_RISCV_OVL) + return ELF::R_RISCV_OVLTOK32; return ELF::R_RISCV_32; case FK_Data_8: return ELF::R_RISCV_64; @@ -166,6 +174,14 @@ return ELF::R_RISCV_ADD64; case RISCV::fixup_riscv_sub_64: return ELF::R_RISCV_SUB64; + case RISCV::fixup_riscv_ovltok_hi20: + return ELF::R_RISCV_OVLTOK_HI20; + case RISCV::fixup_riscv_ovltok_lo12_i: + return ELF::R_RISCV_OVLTOK_LO12_I; + case RISCV::fixup_riscv_ovlplt_hi20: + return ELF::R_RISCV_OVLPLT_HI20; + case RISCV::fixup_riscv_ovlplt_lo12_i: + return ELF::R_RISCV_OVLPLT_LO12_I; } } Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.h @@ -103,6 +103,8 @@ void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; void emitDirectiveOptionNoRelax() override; + void emitDirectiveOptionWarnReservedReg() override; + void emitDirectiveOptionNoWarnReservedReg() override; }; MCELFStreamer *createRISCVELFStreamer(MCContext &C, Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVELFStreamer.cpp @@ -76,6 +76,8 @@ void RISCVTargetELFStreamer::emitDirectiveOptionNoRVC() {} void RISCVTargetELFStreamer::emitDirectiveOptionRelax() {} void RISCVTargetELFStreamer::emitDirectiveOptionNoRelax() {} +void RISCVTargetELFStreamer::emitDirectiveOptionWarnReservedReg() {} +void RISCVTargetELFStreamer::emitDirectiveOptionNoWarnReservedReg() {} void RISCVTargetELFStreamer::emitAttribute(unsigned Attribute, unsigned Value) { setAttributeItem(Attribute, Value, /*OverwriteExisting=*/true); Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVFixupKinds.h @@ -105,6 +105,15 @@ // DWARF CFA. fixup_riscv_sub_6b, + // 20-bit fixup corresponding to %ovltok_hi(foo) for instructions like lui + fixup_riscv_ovltok_hi20, + // 12-bit fixup corresponding to %ovltok_lo(foo) for instructions like addi + fixup_riscv_ovltok_lo12_i, + // 20-bit fixup corresponding to %ovlplt_hi(foo) for instructions like lui + fixup_riscv_ovlplt_hi20, + // 12-bit fixup corresponding to %ovlplt_lo(foo) for instructions like addi + fixup_riscv_ovlplt_lo12_i, + // Used as a sentinel, must be the last fixup_riscv_invalid, NumTargetFixupKinds = fixup_riscv_invalid - FirstTargetFixupKind Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCCodeEmitter.cpp @@ -355,6 +355,18 @@ FixupKind = RISCV::fixup_riscv_call_plt; RelaxCandidate = true; break; + case RISCVMCExpr::VK_RISCV_OVLTOK_LO: + FixupKind = RISCV::fixup_riscv_ovltok_lo12_i; + break; + case RISCVMCExpr::VK_RISCV_OVLTOK_HI: + FixupKind = RISCV::fixup_riscv_ovltok_hi20; + break; + case RISCVMCExpr::VK_RISCV_OVLPLT_LO: + FixupKind = RISCV::fixup_riscv_ovlplt_lo12_i; + break; + case RISCVMCExpr::VK_RISCV_OVLPLT_HI: + FixupKind = RISCV::fixup_riscv_ovlplt_hi20; + break; } } else if (Kind == MCExpr::SymbolRef && cast(Expr)->getKind() == MCSymbolRefExpr::VK_None) { Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.h @@ -36,6 +36,10 @@ VK_RISCV_TLS_GD_HI, VK_RISCV_CALL, VK_RISCV_CALL_PLT, + VK_RISCV_OVLTOK_LO, + VK_RISCV_OVLTOK_HI, + VK_RISCV_OVLPLT_LO, + VK_RISCV_OVLPLT_HI, VK_RISCV_32_PCREL, VK_RISCV_Invalid // Must be the last item }; Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCExpr.cpp @@ -120,6 +120,10 @@ .Case("tprel_add", VK_RISCV_TPREL_ADD) .Case("tls_ie_pcrel_hi", VK_RISCV_TLS_GOT_HI) .Case("tls_gd_pcrel_hi", VK_RISCV_TLS_GD_HI) + .Case("ovltok_lo", VK_RISCV_OVLTOK_LO) + .Case("ovltok_hi", VK_RISCV_OVLTOK_HI) + .Case("ovlplt_lo", VK_RISCV_OVLPLT_LO) + .Case("ovlplt_hi", VK_RISCV_OVLPLT_HI) .Default(VK_RISCV_Invalid); } @@ -154,6 +158,14 @@ return "call_plt"; case VK_RISCV_32_PCREL: return "32_pcrel"; + case VK_RISCV_OVLTOK_LO: + return "ovltok_lo"; + case VK_RISCV_OVLTOK_HI: + return "ovltok_hi"; + case VK_RISCV_OVLPLT_LO: + return "ovlplt_lo"; + case VK_RISCV_OVLPLT_HI: + return "ovlplt_hi"; } llvm_unreachable("Invalid ELF symbol kind"); } Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h @@ -29,6 +29,8 @@ virtual void emitDirectiveOptionNoRVC(); virtual void emitDirectiveOptionRelax(); virtual void emitDirectiveOptionNoRelax(); + virtual void emitDirectiveOptionWarnReservedReg(); + virtual void emitDirectiveOptionNoWarnReservedReg(); virtual void emitAttribute(unsigned Attribute, unsigned Value); virtual void finishAttributeSection(); virtual void emitTextAttribute(unsigned Attribute, StringRef String); @@ -59,6 +61,8 @@ void emitDirectiveOptionNoRVC() override; void emitDirectiveOptionRelax() override; void emitDirectiveOptionNoRelax() override; + void emitDirectiveOptionWarnReservedReg() override; + void emitDirectiveOptionNoWarnReservedReg() override; }; } Index: llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp =================================================================== --- llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp +++ llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp @@ -36,6 +36,8 @@ void RISCVTargetStreamer::emitIntTextAttribute(unsigned Attribute, unsigned IntValue, StringRef StringValue) {} +void RISCVTargetStreamer::emitDirectiveOptionWarnReservedReg() {} +void RISCVTargetStreamer::emitDirectiveOptionNoWarnReservedReg() {} void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI) { if (STI.hasFeature(RISCV::FeatureRV32E)) @@ -147,3 +149,11 @@ StringRef StringValue) {} void RISCVTargetAsmStreamer::finishAttributeSection() {} + +void RISCVTargetAsmStreamer::emitDirectiveOptionWarnReservedReg() { + OS << "\t.option\twarnreservedreg\n"; +} + +void RISCVTargetAsmStreamer::emitDirectiveOptionNoWarnReservedReg() { + OS << "\t.option\tnowarnreservedreg\n"; +} Index: llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -49,6 +49,9 @@ bool runOnMachineFunction(MachineFunction &MF) override; + const MCExpr *lowerConstant(const Constant *CV) override; + void SetupMachineFunction(MachineFunction &MF) override; + void emitInstruction(const MachineInstr *MI) override; bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, @@ -196,6 +199,36 @@ RTS.emitTargetAttributes(*STI); } +const MCExpr *RISCVAsmPrinter::lowerConstant(const Constant *CV) { + if (auto *Fn = dyn_cast(CV)) { + if (Fn->hasFnAttribute("overlay")) { + const MCSymbolRefExpr *Expr = + MCSymbolRefExpr::create(getSymbol(cast(CV)), + MCSymbolRefExpr::VK_RISCV_OVLPLT, OutContext); + return Expr; + } + } + if (auto *GV = dyn_cast(CV)) { + if (GV->hasAttribute("overlay")) { + const MCSymbolRefExpr *Expr = + MCSymbolRefExpr::create(getSymbol(cast(CV)), + MCSymbolRefExpr::VK_RISCV_OVL, OutContext); + return Expr; + } + } + return AsmPrinter::lowerConstant(CV); +} +void RISCVAsmPrinter::SetupMachineFunction(MachineFunction &MF) { + // Set the current MCSubtargetInfo to a copy which has the correct + // feature bits for the current MachineFunction + MCSubtargetInfo &NewSTI = + OutStreamer->getContext().getSubtargetCopy(*TM.getMCSubtargetInfo()); + NewSTI.setFeatureBits(MF.getSubtarget().getFeatureBits()); + STI = &NewSTI; + + return AsmPrinter::SetupMachineFunction(MF); +} + // Force static initialization. extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVAsmPrinter() { RegisterAsmPrinter X(getTheRISCV32Target()); Index: llvm/lib/Target/RISCV/RISCVISelLowering.h =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.h +++ llvm/lib/Target/RISCV/RISCVISelLowering.h @@ -30,6 +30,7 @@ SRET_FLAG, MRET_FLAG, CALL, + CALL_OVERLAY, /// Select with condition operator - This selects between a true value and /// a false value (ops #3 and #4) based on the boolean result of comparing /// the lhs and rhs (ops #0 and #1) of a conditional expression with the Index: llvm/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -2859,6 +2859,26 @@ const GlobalValue *GV = N->getGlobal(); bool IsLocal = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV); + + // Handle addresses of globals and functions which are in overlays. + auto *F = dyn_cast(GV); + auto *G = dyn_cast(GV); + bool IsOverlayFn = F && F->hasFnAttribute("overlay"); + bool IsOverlayData = G && G->hasAttribute("overlay"); + if (IsOverlayFn || IsOverlayData) { + if (Offset != 0) + report_fatal_error("Arithmetic on overlay tokens is not supported"); + + SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, + IsOverlayFn ? RISCVII::MO_OVLPLT_HI + : RISCVII::MO_OVLTOK_HI); + SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, + IsOverlayFn ? RISCVII::MO_OVLPLT_LO + : RISCVII::MO_OVLTOK_LO); + SDValue LoadHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); + return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, LoadHi, AddrLo), 0); + } + SDValue Addr = getAddr(N, DAG, IsLocal); // In order to maximise the opportunity for common subexpression elimination, @@ -7719,6 +7739,7 @@ bool IsFixed, bool IsRet, Type *OrigTy, const RISCVTargetLowering &TLI, Optional FirstMaskArgument) { + const auto &STI = TLI.getSubtarget(); // X5 and X6 might be used for save-restore libcall. static const MCPhysReg GPRList[] = { @@ -7727,9 +7748,16 @@ RISCV::X29, RISCV::X30, RISCV::X31}; if (LocVT == MVT::i32 || LocVT == MVT::i64) { - if (unsigned Reg = State.AllocateReg(GPRList)) { - State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); - return false; + ArrayRef Regs = GPRList; + for (unsigned i = 0; i < Regs.size(); i++) { + // Skip registers that the user has reserved + if (STI.isRegisterReservedByUser(Regs[i])) + continue; + + if (unsigned Reg = State.AllocateReg(Regs[i])) { + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + return false; + } } } @@ -8035,6 +8063,15 @@ if (Caller.hasFnAttribute("interrupt")) return false; + // Overlay function can never tailcall, nor can be tail called + if (Caller.hasFnAttribute("overlay")) + return false; + if (GlobalAddressSDNode *G = dyn_cast(Callee)) { + if (auto *CalleeF = dyn_cast(G->getGlobal())) + if (CalleeF->hasFnAttribute("overlay")) + return false; + } + // Do not tail call opt if the stack is used to pass parameters. if (CCInfo.getNextStackOffset() != 0) return false; @@ -8290,6 +8327,30 @@ Glue = Chain.getValue(1); } + // If the caller is a globaladdress, and the caller or callee is marked + // 'overlay', then the target token must be placed in x30 and then a call + // must be made through the overlay system entry point preserved in x31. + bool IsOverlayCall = false; + if (auto *N = dyn_cast(Callee)) { + IsOverlayCall = MF.getFunction().hasFnAttribute("overlay"); + auto *F = dyn_cast(N->getGlobal()); + if (F && F->hasFnAttribute("overlay")) { + EVT Ty = N->getValueType(0); + IsOverlayCall = true; + SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_OVLTOK_HI); + SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_OVLTOK_LO); + SDValue LoadHi = + SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0); + Callee = + SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, LoadHi, AddrLo), 0); + } + } + if (IsOverlayCall) { + IsTailCall = false; + Chain = DAG.getCopyToReg(Chain, DL, RISCV::X30, Callee, Glue); + Glue = Chain.getValue(1); + } + // Validate that none of the argument registers have been marked as // reserved, if so report an error. Do the same for the return address if this // is not a tailcall. @@ -8300,31 +8361,36 @@ MF.getFunction(), "Return address register required, but has been reserved."}); + // The first call operand is the chain + SmallVector Ops; + Ops.push_back(Chain); + + // For a non-overlay call // If the callee is a GlobalAddress/ExternalSymbol node, turn it into a // TargetGlobalAddress/TargetExternalSymbol node so that legalize won't // split it and then direct call can be matched by PseudoCALL. - if (GlobalAddressSDNode *S = dyn_cast(Callee)) { - const GlobalValue *GV = S->getGlobal(); + if (!IsOverlayCall) { + if (GlobalAddressSDNode *S = dyn_cast(Callee)) { + const GlobalValue *GV = S->getGlobal(); - unsigned OpFlags = RISCVII::MO_CALL; - if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) - OpFlags = RISCVII::MO_PLT; + unsigned OpFlags = RISCVII::MO_CALL; + if (!getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV)) + OpFlags = RISCVII::MO_PLT; - Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); - } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { - unsigned OpFlags = RISCVII::MO_CALL; + Callee = DAG.getTargetGlobalAddress(GV, DL, PtrVT, 0, OpFlags); + } else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) { + unsigned OpFlags = RISCVII::MO_CALL; - if (!getTargetMachine().shouldAssumeDSOLocal(*MF.getFunction().getParent(), - nullptr)) - OpFlags = RISCVII::MO_PLT; + if (!getTargetMachine().shouldAssumeDSOLocal(*MF.getFunction().getParent(), + nullptr)) + OpFlags = RISCVII::MO_PLT; - Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); - } + Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, OpFlags); + } - // The first call operand is the chain and the second is the target address. - SmallVector Ops; - Ops.push_back(Chain); - Ops.push_back(Callee); + // The second operand for a non-overlay call is the target address + Ops.push_back(Callee); + } // Add argument registers to the end of the list so that they are // known live into the call. @@ -8351,7 +8417,11 @@ return DAG.getNode(RISCVISD::TAIL, DL, NodeTys, Ops); } - Chain = DAG.getNode(RISCVISD::CALL, DL, NodeTys, Ops); + if (!IsOverlayCall) + Chain = DAG.getNode(RISCVISD::CALL, DL, NodeTys, Ops); + else + Chain = DAG.getNode(RISCVISD::CALL_OVERLAY, DL, NodeTys, Ops); + DAG.addNoMergeSiteInfo(Chain.getNode(), CLI.NoMerge); Glue = Chain.getValue(1); @@ -8546,6 +8616,7 @@ NODE_NAME_CASE(SRET_FLAG) NODE_NAME_CASE(MRET_FLAG) NODE_NAME_CASE(CALL) + NODE_NAME_CASE(CALL_OVERLAY) NODE_NAME_CASE(SELECT_CC) NODE_NAME_CASE(BR_CC) NODE_NAME_CASE(BuildPairF64) Index: llvm/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -22,6 +22,7 @@ // Target-dependent type requirements. def SDT_RISCVCall : SDTypeProfile<0, -1, [SDTCisVT<0, XLenVT>]>; +def SDT_RISCVCallOverlay : SDTypeProfile<0, -1, []>; def SDT_RISCVSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>, SDTCisVT<3, OtherVT>, SDTCisSameAs<0, 4>, @@ -55,6 +56,9 @@ def riscv_call : SDNode<"RISCVISD::CALL", SDT_RISCVCall, [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, SDNPVariadic]>; +def riscv_call_overlay : SDNode<"RISCVISD::CALL_OVERLAY", SDT_RISCVCallOverlay, + [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue, + SDNPVariadic]>; def riscv_ret_flag : SDNode<"RISCVISD::RET_FLAG", SDTNone, [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>; def riscv_uret_flag : SDNode<"RISCVISD::URET_FLAG", SDTNone, @@ -1059,6 +1063,11 @@ [(riscv_call GPRJALR:$rs1)]>, PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>; +let isCall = 1, Defs = [X1], Uses = [X30, X31] in +def PseudoCallOverlay : Pseudo<(outs), (ins), + [(riscv_call_overlay)]>, + PseudoInstExpansion<(JALR X1, X31, 0)>; + let isBarrier = 1, isReturn = 1, isTerminator = 1 in def PseudoRET : Pseudo<(outs), (ins), [(riscv_ret_flag)]>, PseudoInstExpansion<(JALR X0, X1, 0)>; Index: llvm/lib/Target/RISCV/RISCVMCInstLower.cpp =================================================================== --- llvm/lib/Target/RISCV/RISCVMCInstLower.cpp +++ llvm/lib/Target/RISCV/RISCVMCInstLower.cpp @@ -73,6 +73,18 @@ case RISCVII::MO_TLS_GD_HI: Kind = RISCVMCExpr::VK_RISCV_TLS_GD_HI; break; + case RISCVII::MO_OVLTOK_LO: + Kind = RISCVMCExpr::VK_RISCV_OVLTOK_LO; + break; + case RISCVII::MO_OVLTOK_HI: + Kind = RISCVMCExpr::VK_RISCV_OVLTOK_HI; + break; + case RISCVII::MO_OVLPLT_LO: + Kind = RISCVMCExpr::VK_RISCV_OVLPLT_LO; + break; + case RISCVII::MO_OVLPLT_HI: + Kind = RISCVMCExpr::VK_RISCV_OVLPLT_HI; + break; } const MCExpr *ME = Index: llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2529,6 +2529,10 @@ // of the calling conventions is compatible with C calling convention // this call must be unreachable, as the call is undefined. if ((CalleeF->getCallingConv() != Call.getCallingConv() && + !(CalleeF->getCallingConv() == llvm::CallingConv::C && + Call.getFunction()->hasFnAttribute("overlay")) && + !(Call.getCallingConv() == llvm::CallingConv::C && + CalleeF->hasFnAttribute("overlay")) && !(CalleeF->getCallingConv() == llvm::CallingConv::C && TargetLibraryInfoImpl::isCallingConvCCompatible(&Call)) && !(Call.getCallingConv() == llvm::CallingConv::C && Index: llvm/test/CodeGen/RISCV/overlay-calls.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/overlay-calls.ll @@ -0,0 +1,204 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 \ +; RUN: -mattr=+reserve-x28,+reserve-x29,+reserve-x30,+reserve-x31 \ +; RUN: -verify-machineinstrs < %s \ +; RUN: | FileCheck %s + +; Test for overlay system function call instructions/relocations + +@global_fnptr_to_overlay = global void ()* @overlay_callee, align 4 +@global_fnptr_to_resident = global void ()* @resident_callee, align 4 + +declare void @overlay_callee() #0 +declare void @resident_callee() #1 + +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #2 + +define void @overlay_caller1() #0 { +; CHECK-LABEL: overlay_caller1: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %ovltok_hi(overlay_callee) +; CHECK-NEXT: addi t5, a0, %ovltok_lo(overlay_callee) +; CHECK-NEXT: jalr t6 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @overlay_callee() + ret void +} + +define void @overlay_caller2() #0 { +; CHECK-LABEL: overlay_caller2: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %hi(resident_callee) +; CHECK-NEXT: addi t5, a0, %lo(resident_callee) +; CHECK-NEXT: jalr t6 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @resident_callee() + ret void +} + +define void ()* @overlay_caller3() #0 { +; CHECK-LABEL: overlay_caller3: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a0, %ovlplt_hi(overlay_callee) +; CHECK-NEXT: addi a0, a0, %ovlplt_lo(overlay_callee) +; CHECK-NEXT: ret + ret void ()* @overlay_callee +} + +define void ()* @overlay_caller4() #0 { +; CHECK-LABEL: overlay_caller4: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a0, %hi(resident_callee) +; CHECK-NEXT: addi a0, a0, %lo(resident_callee) +; CHECK-NEXT: ret + ret void ()* @resident_callee +} + +define void @overlay_caller5() #0 { +; CHECK-LABEL: overlay_caller5: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %hi(global_fnptr_to_overlay) +; CHECK-NEXT: lw a0, %lo(global_fnptr_to_overlay)(a0) +; CHECK-NEXT: jalr a0 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = load void ()*, void ()** @global_fnptr_to_overlay, align 4 + call void %1() + ret void +} + +define void @overlay_caller6() #0 { +; CHECK-LABEL: overlay_caller6: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %hi(global_fnptr_to_resident) +; CHECK-NEXT: lw a0, %lo(global_fnptr_to_resident)(a0) +; CHECK-NEXT: jalr a0 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = load void ()*, void ()** @global_fnptr_to_resident, align 4 + call void %1() + ret void +} + +; Check that a call to an external function like memcpy works correctly +define void @overlay_caller_memcpy(i8* %a, i8* %b, i32 %c) #0 { +; CHECK-LABEL: overlay_caller_memcpy: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: call memcpy@plt +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 %c, i1 false) + ret void +} + +define void @resident_caller1() #1 { +; CHECK-LABEL: resident_caller1: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %ovltok_hi(overlay_callee) +; CHECK-NEXT: addi t5, a0, %ovltok_lo(overlay_callee) +; CHECK-NEXT: jalr t6 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @overlay_callee() + ret void +} + +define void @resident_caller2() #1 { +; CHECK-LABEL: resident_caller2: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: call resident_callee@plt +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @resident_callee() + ret void +} + +define void ()* @resident_caller3() #1 { +; CHECK-LABEL: resident_caller3: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a0, %ovlplt_hi(overlay_callee) +; CHECK-NEXT: addi a0, a0, %ovlplt_lo(overlay_callee) +; CHECK-NEXT: ret + ret void ()* @overlay_callee +} + +define void ()* @resident_caller4() #1 { +; CHECK-LABEL: resident_caller4: +; CHECK: # %bb.0: +; CHECK-NEXT: lui a0, %hi(resident_callee) +; CHECK-NEXT: addi a0, a0, %lo(resident_callee) +; CHECK-NEXT: ret + ret void ()* @resident_callee +} + +define void @resident_caller5() #1 { +; CHECK-LABEL: resident_caller5: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %hi(global_fnptr_to_overlay) +; CHECK-NEXT: lw a0, %lo(global_fnptr_to_overlay)(a0) +; CHECK-NEXT: jalr a0 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = load void ()*, void ()** @global_fnptr_to_overlay, align 4 + call void %1() + ret void +} + +define void @resident_caller6() #1 { +; CHECK-LABEL: resident_caller6: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: lui a0, %hi(global_fnptr_to_resident) +; CHECK-NEXT: lw a0, %lo(global_fnptr_to_resident)(a0) +; CHECK-NEXT: jalr a0 +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + %1 = load void ()*, void ()** @global_fnptr_to_resident, align 4 + call void %1() + ret void +} + +define void @resident_caller_memcpy(i8* %a, i8* %b, i32 %c) #1 { +; CHECK-LABEL: resident_caller_memcpy: +; CHECK: # %bb.0: +; CHECK-NEXT: addi sp, sp, -16 +; CHECK-NEXT: sw ra, 12(sp) # 4-byte Folded Spill +; CHECK-NEXT: call memcpy@plt +; CHECK-NEXT: lw ra, 12(sp) # 4-byte Folded Reload +; CHECK-NEXT: addi sp, sp, 16 +; CHECK-NEXT: ret + call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 %c, i1 false) + ret void +} + +attributes #0 = { noinline nounwind "overlay" } +attributes #1 = { noinline nounwind } +attributes #2 = { argmemonly nounwind willreturn } Index: llvm/test/CodeGen/RISCV/overlay-sections.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/RISCV/overlay-sections.ll @@ -0,0 +1,20 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=riscv32 \ +; RUN: -mattr=+reserve-x28,+reserve-x29,+reserve-x30,+reserve-x31 \ +; RUN: -verify-machineinstrs < %s \ +; RUN: | FileCheck %s + +; Test that overlay functions are placed into a section with the correct +; prefix + +define i32 @overlay_fn() "overlay" { +; CHECK: .section .ovlinput.overlay_fn +; CHECK-LABEL: overlay_fn: + ret i32 0 +} + +define i32 @resident_fn() { +; CHECK: .text +; CHECK-LABEL: resident_fn: + ret i32 0 +} Index: llvm/test/MC/RISCV/option-invalid.s =================================================================== --- llvm/test/MC/RISCV/option-invalid.s +++ llvm/test/MC/RISCV/option-invalid.s @@ -13,7 +13,7 @@ # CHECK: error: unexpected token, expected end of statement .option rvc foo -# CHECK: warning: unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax' or 'norelax' +# CHECK: warning: unknown option, expected 'push', 'pop', 'rvc', 'norvc', 'relax', 'norelax', 'warnreservedreg' or 'nowarnreservedreg' .option bar # CHECK: error: .option pop with no .option push Index: llvm/test/MC/RISCV/overlay.s =================================================================== --- /dev/null +++ llvm/test/MC/RISCV/overlay.s @@ -0,0 +1,32 @@ +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-objdump -d - | FileCheck --check-prefix=INSTR %s +# RUN: llvm-mc -filetype=obj -triple riscv32 < %s \ +# RUN: | llvm-readobj -r - | FileCheck -check-prefix=RELOC %s +# RUN: llvm-mc -triple riscv32 < %s -show-encoding \ +# RUN: | FileCheck -check-prefix=FIXUP %s + +lui a4, %ovltok_hi(foo) +# RELOC: R_RISCV_OVLTOK_HI20 foo 0x0 +# INSTR: lui a4, 0 +# FIXUP: fixup A - offset: 0, value: %ovltok_hi(foo), kind: fixup_riscv_ovltok_hi20 + +addi a4, a5, %ovltok_lo(foo) +# RELOC: R_RISCV_OVLTOK_LO12_I foo 0x0 +# INSTR: mv a4, a5 +# FIXUP: fixup A - offset: 0, value: %ovltok_lo(foo), kind: fixup_riscv_ovltok_lo12_i + +lui a4, %ovlplt_hi(foo) +# RELOC: R_RISCV_OVLPLT_HI20 foo 0x0 +# INSTR: lui a4, 0 +# FIXUP: fixup A - offset: 0, value: %ovlplt_hi(foo), kind: fixup_riscv_ovlplt_hi20 + +addi a4, a5, %ovlplt_lo(foo) +# RELOC: R_RISCV_OVLPLT_LO12_I foo 0x0 +# INSTR: mv a4, a5 +# FIXUP: fixup A - offset: 0, value: %ovlplt_lo(foo), kind: fixup_riscv_ovlplt_lo12_i + +.word foo@ovl +# RELOC: R_RISCV_OVLTOK32 foo 0x0 + +.word foo@ovlplt +# RELOC: R_RISCV_OVLPLT32 foo 0x0 Index: llvm/test/Transforms/Inline/RISCV/lit.local.cfg =================================================================== --- /dev/null +++ llvm/test/Transforms/Inline/RISCV/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'RISCV' in config.root.targets: + config.unsupported = True Index: llvm/test/Transforms/Inline/RISCV/riscv-overlay-callee.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Inline/RISCV/riscv-overlay-callee.ll @@ -0,0 +1,16 @@ +; RUN: opt -inline -S %s | FileCheck %s +; RUN: opt -passes='cgscc(inline)' -S %s | FileCheck %s + +define void @f() { +; CHECK-LABEL: @f +; CHECK: call +entry: + tail call void @g() + unreachable +} + +define void @g() "overlay" { +; CHECK-LABEL: @g +entry: + unreachable +} Index: llvm/test/Transforms/Inline/RISCV/riscv-overlay-caller.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/Inline/RISCV/riscv-overlay-caller.ll @@ -0,0 +1,16 @@ +; RUN: opt -inline -S %s | FileCheck %s +; RUN: opt -passes='cgscc(inline)' -S %s | FileCheck %s + +define void @f() "overlay" { +; CHECK-LABEL: @f +; CHECK: call +entry: + tail call void @g() + unreachable +} + +define void @g() { +; CHECK-LABEL: @g +entry: + unreachable +}