[llvm] [RISCV][Zicfilp] Enable Zicfilp CFI compiler behaviors by looking at module flags (PR #152121)

Ming-Yi Lai via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 8 02:57:51 PDT 2025


https://github.com/mylai-mtk updated https://github.com/llvm/llvm-project/pull/152121

>From 614f475c4067f15df01186f782688d6ab8607d5a Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Tue, 5 Aug 2025 17:31:54 +0800
Subject: [PATCH 01/10] [RISCV][Zicfilp] Codegen LPAD insns by looking at
 module flags

Expected Behavior:

Stop codegening LPAD insns by testing if the target has the Zicfilp extension
and instead, codegen LPAD insns if the LLVM module has all of these flags:

+ `cf-protection-branch`: Needs to be a non-zero integer (which means `true`)
+ `cf-branch-label-scheme`: Needs to be `unlabeled`

Context:

In clang, Zicfilp-based control flow integrity (the `unlabeled` scheme) can now
be enabled by giving the `-fcf-protection=branch
-mcf-branch-label-scheme=unlabeled` options. With these options, the clang
frontend adds the above-mentioned flags to LLVM modules. Here we want to align
LPAD insn codegen to be enabled by the semantics of those LLVM module flags,
instead of relying on the inaccurate indicator of whether the Zicfilp extension
is available, so the toolchain's behavior is more streamlined and expected.

Also, since LPAD insns can be executed regardless of whether Zicfilp is
available in target or not (due to LPAD insn being encoded as a standard hint
insn), clang accepts the above-mentioned CLI options even if Zicfilp is not
enabled and expects backend to still generate LPAD insns. This patch enables
LPAD insn generation in such cases.
---
 llvm/include/llvm/Support/RISCVISAUtils.h     | 19 +++++++++++++++++
 .../RISCV/RISCVIndirectBranchTracking.cpp     | 21 ++++++++++++++++++-
 llvm/test/CodeGen/RISCV/lpad.ll               |  5 +++++
 3 files changed, 44 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/Support/RISCVISAUtils.h b/llvm/include/llvm/Support/RISCVISAUtils.h
index 165bb08d66431..e2dd833de74fd 100644
--- a/llvm/include/llvm/Support/RISCVISAUtils.h
+++ b/llvm/include/llvm/Support/RISCVISAUtils.h
@@ -14,7 +14,9 @@
 #define LLVM_SUPPORT_RISCVISAUTILS_H
 
 #include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Compiler.h"
+#include <cassert>
 #include <map>
 #include <string>
 
@@ -43,6 +45,23 @@ struct ExtensionComparator {
 typedef std::map<std::string, ExtensionVersion, ExtensionComparator>
     OrderedExtensionMap;
 
+enum class ZicfilpLabelSchemeKind {
+  Invalid,
+  Unlabeled,
+  FuncSig,
+};
+
+// See clang::getCFBranchLabelSchemeFlagVal() for possible CFBranchLabelScheme
+inline ZicfilpLabelSchemeKind
+getZicfilpLabelScheme(const StringRef CFBranchLabelScheme) {
+  const auto Ret = StringSwitch<ZicfilpLabelSchemeKind>(CFBranchLabelScheme)
+                       .Case("unlabeled", ZicfilpLabelSchemeKind::Unlabeled)
+                       .Case("func-sig", ZicfilpLabelSchemeKind::FuncSig)
+                       .Default(ZicfilpLabelSchemeKind::Invalid);
+  assert(Ret != ZicfilpLabelSchemeKind::Invalid);
+  return Ret;
+}
+
 } // namespace RISCVISAUtils
 
 } // namespace llvm
diff --git a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
index 43621b8f0f33d..554f7d5494731 100644
--- a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
+++ b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
@@ -19,11 +19,14 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/RISCVISAUtils.h"
 
 #define DEBUG_TYPE "riscv-indrect-branch-tracking"
 #define PASS_NAME "RISC-V Indirect Branch Tracking"
 
 using namespace llvm;
+using namespace llvm::RISCVISAUtils;
 
 cl::opt<uint32_t> PreferredLandingPadLabel(
     "riscv-landing-pad-label", cl::ReallyHidden,
@@ -64,9 +67,25 @@ static void emitLpad(MachineBasicBlock &MBB, const RISCVInstrInfo *TII,
 bool RISCVIndirectBranchTracking::runOnMachineFunction(MachineFunction &MF) {
   const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
   const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
-  if (!Subtarget.hasStdExtZicfilp())
+
+  const Module *const M = MF.getFunction().getParent();
+  if (!M)
+    return false;
+  if (const Metadata *const Flag = M->getModuleFlag("cf-protection-branch");
+      !Flag || mdconst::extract<ConstantInt>(Flag)->isZero())
     return false;
 
+  StringRef CFBranchLabelScheme;
+  if (const Metadata *const MD = M->getModuleFlag("cf-branch-label-scheme"))
+    CFBranchLabelScheme = cast<MDString>(MD)->getString();
+  else
+    report_fatal_error("missing cf-branch-label-scheme module flag");
+
+  const ZicfilpLabelSchemeKind Scheme =
+      getZicfilpLabelScheme(CFBranchLabelScheme);
+  if (Scheme != ZicfilpLabelSchemeKind::Unlabeled)
+    report_fatal_error("unsupported cf-branch-label-scheme module flag");
+
   uint32_t FixedLabel = 0;
   if (PreferredLandingPadLabel.getNumOccurrences() > 0) {
     if (!isUInt<20>(PreferredLandingPadLabel))
diff --git a/llvm/test/CodeGen/RISCV/lpad.ll b/llvm/test/CodeGen/RISCV/lpad.ll
index 93eda6f10eedb..f69b4dad068b5 100644
--- a/llvm/test/CodeGen/RISCV/lpad.ll
+++ b/llvm/test/CodeGen/RISCV/lpad.ll
@@ -289,3 +289,8 @@ define void @interrupt() "interrupt"="machine" {
 ; FIXED-ONE-NEXT:    mret
   ret void
 }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}

>From 1f761cd55196764f8e7c35afa445e19c18ba4d84 Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Wed, 6 Aug 2025 17:43:20 +0800
Subject: [PATCH 02/10] fixup: Change SelectionDAG patterns to depend on
 Zicfilp CFI feature adoption instead of Zicfilp extension availability

---
 llvm/include/llvm/Support/RISCVISAUtils.h     | 19 ----------
 llvm/lib/Target/RISCV/RISCVFeatures.td        |  4 +-
 llvm/lib/Target/RISCV/RISCVInstrInfo.td       | 16 ++++----
 llvm/lib/Target/RISCV/RISCVSubtarget.cpp      |  2 +
 llvm/lib/Target/RISCV/RISCVSubtarget.h        | 20 +++++++++-
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp  | 38 +++++++++++++++++--
 .../Target/RISCV/RISCVInstrInfoTest.cpp       |  3 +-
 7 files changed, 68 insertions(+), 34 deletions(-)

diff --git a/llvm/include/llvm/Support/RISCVISAUtils.h b/llvm/include/llvm/Support/RISCVISAUtils.h
index e2dd833de74fd..165bb08d66431 100644
--- a/llvm/include/llvm/Support/RISCVISAUtils.h
+++ b/llvm/include/llvm/Support/RISCVISAUtils.h
@@ -14,9 +14,7 @@
 #define LLVM_SUPPORT_RISCVISAUTILS_H
 
 #include "llvm/ADT/StringRef.h"
-#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Support/Compiler.h"
-#include <cassert>
 #include <map>
 #include <string>
 
@@ -45,23 +43,6 @@ struct ExtensionComparator {
 typedef std::map<std::string, ExtensionVersion, ExtensionComparator>
     OrderedExtensionMap;
 
-enum class ZicfilpLabelSchemeKind {
-  Invalid,
-  Unlabeled,
-  FuncSig,
-};
-
-// See clang::getCFBranchLabelSchemeFlagVal() for possible CFBranchLabelScheme
-inline ZicfilpLabelSchemeKind
-getZicfilpLabelScheme(const StringRef CFBranchLabelScheme) {
-  const auto Ret = StringSwitch<ZicfilpLabelSchemeKind>(CFBranchLabelScheme)
-                       .Case("unlabeled", ZicfilpLabelSchemeKind::Unlabeled)
-                       .Case("func-sig", ZicfilpLabelSchemeKind::FuncSig)
-                       .Default(ZicfilpLabelSchemeKind::Invalid);
-  assert(Ret != ZicfilpLabelSchemeKind::Invalid);
-  return Ret;
-}
-
 } // namespace RISCVISAUtils
 
 } // namespace llvm
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 171940e149815..eb0749163cc0e 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -170,8 +170,8 @@ def FeatureStdExtZicfilp
 def HasStdExtZicfilp : Predicate<"Subtarget->hasStdExtZicfilp()">,
                        AssemblerPredicate<(all_of FeatureStdExtZicfilp),
                                           "'Zicfilp' (Landing pad)">;
-def NoStdExtZicfilp : Predicate<"!Subtarget->hasStdExtZicfilp()">,
-                      AssemblerPredicate<(all_of (not FeatureStdExtZicfilp))>;
+def HasZicfilpCFI : Predicate<"Subtarget->hasZicfilpCFI()">;
+def HasNoZicfilpCFI : Predicate<"!Subtarget->hasZicfilpCFI()">;
 
 def FeatureStdExtZicfiss
     : RISCVExperimentalExtension<1, 0, "Shadow stack",
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 8bd383033f11c..610edf126f0c5 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1746,12 +1746,12 @@ let isBarrier = 1, isBranch = 1, isTerminator = 1 in
 def PseudoBR : Pseudo<(outs), (ins simm21_lsb0_jal:$imm20), [(br bb:$imm20)]>,
                PseudoInstExpansion<(JAL X0, simm21_lsb0_jal:$imm20)>;
 
-let Predicates = [NoStdExtZicfilp],
+let Predicates = [HasNoZicfilpCFI],
     isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in
 def PseudoBRIND : Pseudo<(outs), (ins GPRJALR:$rs1, simm12:$imm12), []>,
                   PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;
 
-let Predicates = [HasStdExtZicfilp],
+let Predicates = [HasZicfilpCFI],
     isBarrier = 1, isBranch = 1, isIndirectBranch = 1, isTerminator = 1 in {
 def PseudoBRINDNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1, simm12:$imm12), []>,
                        PseudoInstExpansion<(JALR X0, GPR:$rs1, simm12:$imm12)>;
@@ -1761,7 +1761,7 @@ def PseudoBRINDX7 : Pseudo<(outs), (ins GPRX7:$rs1, simm12:$imm12), []>,
 
 // For Zicfilp, need to avoid using X7/T2 for indirect branches which need
 // landing pad.
-let Predicates = [HasStdExtZicfilp] in {
+let Predicates = [HasZicfilpCFI] in {
 def : Pat<(brind GPRJALRNonX7:$rs1), (PseudoBRINDNonX7 GPRJALRNonX7:$rs1, 0)>;
 def : Pat<(brind (add GPRJALRNonX7:$rs1, simm12:$imm12)),
           (PseudoBRINDNonX7 GPRJALRNonX7:$rs1, simm12:$imm12)>;
@@ -1771,7 +1771,7 @@ def : Pat<(riscv_sw_guarded_brind (add GPRX7:$rs1, simm12:$imm12)),
           (PseudoBRINDX7 GPRX7:$rs1, simm12:$imm12)>;
 }
 
-let Predicates = [NoStdExtZicfilp] in {
+let Predicates = [HasNoZicfilpCFI] in {
 def : Pat<(brind GPRJALR:$rs1), (PseudoBRIND GPRJALR:$rs1, 0)>;
 def : Pat<(brind (add GPRJALR:$rs1, simm12:$imm12)),
           (PseudoBRIND GPRJALR:$rs1, simm12:$imm12)>;
@@ -1808,11 +1808,11 @@ let Predicates = [HasStdExtSmrnmi] in
 def : Pat<(riscv_mnret_glue), (MNRET)>;
 
 let isCall = 1, Defs = [X1] in {
-let Predicates = [NoStdExtZicfilp] in
+let Predicates = [HasNoZicfilpCFI] in
 def PseudoCALLIndirect : Pseudo<(outs), (ins GPRJALR:$rs1),
                                 [(riscv_call GPRJALR:$rs1)]>,
                          PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
-let Predicates = [HasStdExtZicfilp] in {
+let Predicates = [HasZicfilpCFI] in {
 def PseudoCALLIndirectNonX7 : Pseudo<(outs), (ins GPRJALRNonX7:$rs1),
                                      [(riscv_call GPRJALRNonX7:$rs1)]>,
                               PseudoInstExpansion<(JALR X1, GPR:$rs1, 0)>;
@@ -1837,11 +1837,11 @@ def PseudoTAIL : Pseudo<(outs), (ins call_symbol:$dst), [],
                  Sched<[WriteIALU, WriteJalr, ReadJalr]>;
 
 let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [X2] in {
-let Predicates = [NoStdExtZicfilp] in
+let Predicates = [HasNoZicfilpCFI] in
 def PseudoTAILIndirect : Pseudo<(outs), (ins GPRTC:$rs1),
                                 [(riscv_tail GPRTC:$rs1)]>,
                          PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>;
-let Predicates = [HasStdExtZicfilp] in {
+let Predicates = [HasZicfilpCFI] in {
 def PseudoTAILIndirectNonX7 : Pseudo<(outs), (ins GPRTCNonX7:$rs1),
                                      [(riscv_tail GPRTCNonX7:$rs1)]>,
                               PseudoInstExpansion<(JALR X0, GPR:$rs1, 0)>;
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
index e35ffaf2b3935..6098f3c10296f 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.cpp
@@ -99,9 +99,11 @@ RISCVSubtarget::RISCVSubtarget(const Triple &TT, StringRef CPU,
                                StringRef TuneCPU, StringRef FS,
                                StringRef ABIName, unsigned RVVVectorBitsMin,
                                unsigned RVVVectorBitsMax,
+                               RISCVSubtarget::ZicfilpLabelSchemeKind Zicfilp,
                                const TargetMachine &TM)
     : RISCVGenSubtargetInfo(TT, CPU, TuneCPU, FS),
       RVVVectorBitsMin(RVVVectorBitsMin), RVVVectorBitsMax(RVVVectorBitsMax),
+      ZicfilpLabelScheme(Zicfilp),
       FrameLowering(
           initializeSubtargetDependencies(TT, CPU, TuneCPU, FS, ABIName)),
       InstrInfo(*this), RegInfo(getHwMode()), TLInfo(TM, *this) {
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index fd57e02c25d05..424087b8ca83b 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -91,6 +91,14 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
     NLog2N,
   };
   // clang-format on
+
+  enum class ZicfilpLabelSchemeKind {
+    Disabled,
+    Unknown,
+    Unlabeled,
+    FuncSig,
+  };
+
 private:
   virtual void anchor();
 
@@ -107,6 +115,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
   unsigned RVVVectorBitsMax;
   uint8_t MaxInterleaveFactor = 2;
   RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
+  const ZicfilpLabelSchemeKind ZicfilpLabelScheme;
   std::bitset<RISCV::NUM_TARGET_REGS> UserReservedRegister;
   const RISCVTuneInfoTable::RISCVTuneInfo *TuneInfo;
 
@@ -127,7 +136,9 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
   // Initializes the data members to match that of the specified triple.
   RISCVSubtarget(const Triple &TT, StringRef CPU, StringRef TuneCPU,
                  StringRef FS, StringRef ABIName, unsigned RVVVectorBitsMin,
-                 unsigned RVVVectorLMULMax, const TargetMachine &TM);
+                 unsigned RVVVectorLMULMax,
+                 ZicfilpLabelSchemeKind ZicfilpLabelScheme,
+                 const TargetMachine &TM);
 
   ~RISCVSubtarget() override;
 
@@ -186,6 +197,13 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
     return HasStdExtZfhmin || HasStdExtZfbfmin;
   }
 
+  ZicfilpLabelSchemeKind getZicfilpLabelScheme() const {
+    return ZicfilpLabelScheme;
+  }
+  bool hasZicfilpCFI() const {
+    return getZicfilpLabelScheme() != ZicfilpLabelSchemeKind::Disabled;
+  }
+
   bool hasConditionalMoveFusion() const {
     // Do we support fusing a branch+mv or branch+c.mv as a conditional move.
     return (hasConditionalCompressedMoveFusion() && hasStdExtZca()) ||
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 3f2a83f8ce98c..fee8a2598be5b 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -17,6 +17,9 @@
 #include "RISCVTargetObjectFile.h"
 #include "RISCVTargetTransformInfo.h"
 #include "TargetInfo/RISCVTargetInfo.h"
+#include "llvm/ADT/STLForwardCompat.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/CodeGen/GlobalISel/CSEInfo.h"
 #include "llvm/CodeGen/GlobalISel/IRTranslator.h"
@@ -31,6 +34,9 @@
 #include "llvm/CodeGen/RegAllocRegistry.h"
 #include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
 #include "llvm/CodeGen/TargetPassConfig.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Metadata.h"
+#include "llvm/IR/Module.h"
 #include "llvm/InitializePasses.h"
 #include "llvm/MC/TargetRegistry.h"
 #include "llvm/Passes/PassBuilder.h"
@@ -40,6 +46,7 @@
 #include "llvm/Transforms/Scalar.h"
 #include "llvm/Transforms/Vectorize/EVLIndVarSimplify.h"
 #include "llvm/Transforms/Vectorize/LoopIdiomVectorize.h"
+#include <cassert>
 #include <optional>
 using namespace llvm;
 
@@ -246,9 +253,33 @@ RISCVTargetMachine::getSubtargetImpl(const Function &F) const {
   RVVBitsMax =
       llvm::bit_floor((RVVBitsMax < 64 || RVVBitsMax > 65536) ? 0 : RVVBitsMax);
 
+  using ZicfilpLabelSchemeKind = RISCVSubtarget::ZicfilpLabelSchemeKind;
+  ZicfilpLabelSchemeKind ZicfilpLabelScheme = ZicfilpLabelSchemeKind::Disabled;
+  if (const Module *const M = F.getParent()) {
+    if (const Metadata *const Flag = M->getModuleFlag("cf-protection-branch");
+        Flag && !mdconst::extract<ConstantInt>(Flag)->isZero()) {
+      StringRef CFBranchLabelScheme;
+      if (const Metadata *const MD = M->getModuleFlag("cf-branch-label-scheme"))
+        CFBranchLabelScheme = cast<MDString>(MD)->getString();
+      else
+        report_fatal_error("missing cf-branch-label-scheme module flag");
+
+      // See clang::getCFBranchLabelSchemeFlagVal() for possible
+      // CFBranchLabelScheme
+      ZicfilpLabelScheme =
+          StringSwitch<ZicfilpLabelSchemeKind>(CFBranchLabelScheme)
+              .Case("unlabeled", ZicfilpLabelSchemeKind::Unlabeled)
+              .Case("func-sig", ZicfilpLabelSchemeKind::FuncSig)
+              .Default(ZicfilpLabelSchemeKind::Unknown);
+      assert(ZicfilpLabelScheme != ZicfilpLabelSchemeKind::Unknown);
+    }
+  }
+
   SmallString<512> Key;
   raw_svector_ostream(Key) << "RVVMin" << RVVBitsMin << "RVVMax" << RVVBitsMax
-                           << CPU << TuneCPU << FS;
+                           << "ZicfilpLabelSchemeKind"
+                           << to_underlying(ZicfilpLabelScheme) << CPU
+                           << TuneCPU << FS;
   auto &I = SubtargetMap[Key];
   if (!I) {
     // This needs to be done before we create a new subtarget since any
@@ -265,8 +296,9 @@ RISCVTargetMachine::getSubtargetImpl(const Function &F) const {
       }
       ABIName = ModuleTargetABI->getString();
     }
-    I = std::make_unique<RISCVSubtarget>(
-        TargetTriple, CPU, TuneCPU, FS, ABIName, RVVBitsMin, RVVBitsMax, *this);
+    I = std::make_unique<RISCVSubtarget>(TargetTriple, CPU, TuneCPU, FS,
+                                         ABIName, RVVBitsMin, RVVBitsMax,
+                                         ZicfilpLabelScheme, *this);
   }
   return I.get();
 }
diff --git a/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp b/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
index 2744dbc0907bf..3b6a7a143f351 100644
--- a/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
+++ b/llvm/unittests/Target/RISCV/RISCVInstrInfoTest.cpp
@@ -61,7 +61,8 @@ class RISCVInstrInfoTest : public testing::TestWithParam<const char *> {
     ST = std::make_unique<RISCVSubtarget>(
         TM->getTargetTriple(), TM->getTargetCPU(), TM->getTargetCPU(),
         TM->getTargetFeatureString(),
-        TM->getTargetTriple().isArch64Bit() ? "lp64" : "ilp32", 0, 0, *TM);
+        TM->getTargetTriple().isArch64Bit() ? "lp64" : "ilp32", 0, 0,
+        RISCVSubtarget::ZicfilpLabelSchemeKind::Disabled, *TM);
 
     MF = std::make_unique<MachineFunction>(*F, *TM, *ST, MMI->getContext(), 42);
   }

>From 968e25057229f1c6f1f4c9b7a68945e4bfa8133e Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Wed, 6 Aug 2025 16:41:18 +0800
Subject: [PATCH 03/10] fixup: Codegen software-guarded long calls based on
 Zicfilp CFI feature adoption instead of Zicfilp extension availability

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |   9 +-
 llvm/test/CodeGen/RISCV/calls.ll              | 186 --------
 llvm/test/CodeGen/RISCV/tail-calls.ll         | 270 -----------
 .../CodeGen/RISCV/zicfilp-unlabeled-calls.ll  | 253 ++++++++++
 .../RISCV/zicfilp-unlabeled-tail-calls.ll     | 434 ++++++++++++++++++
 5 files changed, 691 insertions(+), 461 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/zicfilp-unlabeled-calls.ll
 create mode 100644 llvm/test/CodeGen/RISCV/zicfilp-unlabeled-tail-calls.ll

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index e09e6fb5b26ee..86d51b8d7d172 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -22953,11 +22953,10 @@ SDValue RISCVTargetLowering::LowerCall(CallLoweringInfo &CLI,
   // Use software guarded branch for large code model non-indirect calls
   // Tail call to external symbol will have a null CLI.CB and we need another
   // way to determine the callsite type
-  bool NeedSWGuarded = false;
-  if (getTargetMachine().getCodeModel() == CodeModel::Large &&
-      Subtarget.hasStdExtZicfilp() &&
-      ((CLI.CB && !CLI.CB->isIndirectCall()) || CalleeIsLargeExternalSymbol))
-    NeedSWGuarded = true;
+  const bool NeedSWGuarded =
+      getTargetMachine().getCodeModel() == CodeModel::Large &&
+      Subtarget.hasZicfilpCFI() &&
+      ((CLI.CB && !CLI.CB->isIndirectCall()) || CalleeIsLargeExternalSymbol);
 
   if (IsTailCall) {
     MF.getFrameInfo().setHasTailCall();
diff --git a/llvm/test/CodeGen/RISCV/calls.ll b/llvm/test/CodeGen/RISCV/calls.ll
index f30c453d7f6bc..1a3e77b8b8ea1 100644
--- a/llvm/test/CodeGen/RISCV/calls.ll
+++ b/llvm/test/CodeGen/RISCV/calls.ll
@@ -11,8 +11,6 @@
 ; RUN:   | FileCheck -check-prefix=RV64I-MEDIUM %s
 ; RUN: llc -code-model=large -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV64I-LARGE %s
-; RUN: llc -code-model=large -mtriple=riscv64 -mattr=experimental-zicfilp -verify-machineinstrs < %s \
-; RUN:   | FileCheck -check-prefix=RV64I-LARGE-ZICFILP %s
 
 declare i32 @external_function(i32)
 
@@ -64,19 +62,6 @@ define i32 @test_call_external(i32 %a) nounwind {
 ; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_external:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi0:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI0_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi0)(a1)
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 @external_function(i32 %a)
   ret i32 %1
 }
@@ -131,19 +116,6 @@ define i32 @test_call_dso_local(i32 %a) nounwind {
 ; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_dso_local:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi1:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI1_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi1)(a1)
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 @dso_local_function(i32 %a)
   ret i32 %1
 }
@@ -173,12 +145,6 @@ define i32 @defined_function(i32 %a) nounwind {
 ; RV64I-LARGE:       # %bb.0:
 ; RV64I-LARGE-NEXT:    addiw a0, a0, 1
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: defined_function:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addiw a0, a0, 1
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = add i32 %a, 1
   ret i32 %1
 }
@@ -231,19 +197,6 @@ define i32 @test_call_defined(i32 %a) nounwind {
 ; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_defined:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi2:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI3_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi2)(a1)
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 @defined_function(i32 %a)
   ret i32 %1
 }
@@ -303,18 +256,6 @@ define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
 ; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_indirect:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    mv a2, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, a1
-; RV64I-LARGE-ZICFILP-NEXT:    jalr a2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 %a(i32 %b)
   ret i32 %1
 }
@@ -406,24 +347,6 @@ define i32 @test_call_indirect_no_t0(ptr %a, i32 %b, i32 %c, i32 %d, i32 %e, i32
 ; RV64I-LARGE-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_indirect_no_t0:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    mv t1, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, a1
-; RV64I-LARGE-ZICFILP-NEXT:    mv a1, a2
-; RV64I-LARGE-ZICFILP-NEXT:    mv a2, a3
-; RV64I-LARGE-ZICFILP-NEXT:    mv a3, a4
-; RV64I-LARGE-ZICFILP-NEXT:    mv a4, a5
-; RV64I-LARGE-ZICFILP-NEXT:    mv a5, a6
-; RV64I-LARGE-ZICFILP-NEXT:    mv a6, a7
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t1
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 %a(i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
   ret i32 %1
 }
@@ -456,12 +379,6 @@ define fastcc i32 @fastcc_function(i32 %a, i32 %b) nounwind {
 ; RV64I-LARGE:       # %bb.0:
 ; RV64I-LARGE-NEXT:    addw a0, a0, a1
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: fastcc_function:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addw a0, a0, a1
-; RV64I-LARGE-ZICFILP-NEXT:    ret
  %1 = add i32 %a, %b
  ret i32 %1
 }
@@ -535,24 +452,6 @@ define i32 @test_call_fastcc(i32 %a, i32 %b) nounwind {
 ; RV64I-LARGE-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 16
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_fastcc:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    mv s0, a0
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi3:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi3)(a0)
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, s0
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, s0
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call fastcc i32 @fastcc_function(i32 %a, i32 %b)
   ret i32 %a
 }
@@ -673,33 +572,6 @@ define i32 @test_call_external_many_args(i32 %a) nounwind {
 ; RV64I-LARGE-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 32
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_external_many_args:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -32
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    mv s0, a0
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi4:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi4)(a0)
-; RV64I-LARGE-ZICFILP-NEXT:    sd s0, 0(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    sd s0, 8(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a1, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a2, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a3, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a4, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a5, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a6, s0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a7, s0
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    mv a0, s0
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 32
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 @external_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
                                     i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
   ret i32 %a
@@ -735,13 +607,6 @@ define i32 @defined_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 %
 ; RV64I-LARGE-NEXT:    lw a0, 8(sp)
 ; RV64I-LARGE-NEXT:    addiw a0, a0, 1
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: defined_many_args:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    lw a0, 8(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    addiw a0, a0, 1
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %added = add i32 %j, 1
   ret i32 %added
 }
@@ -839,28 +704,6 @@ define i32 @test_call_defined_many_args(i32 %a) nounwind {
 ; RV64I-LARGE-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
 ; RV64I-LARGE-NEXT:    addi sp, sp, 32
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: test_call_defined_many_args:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -32
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi5:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI10_0)
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi5)(a1)
-; RV64I-LARGE-ZICFILP-NEXT:    sd a0, 0(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    sd a0, 8(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    mv a1, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a2, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a3, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a4, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a5, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a6, a0
-; RV64I-LARGE-ZICFILP-NEXT:    mv a7, a0
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 32
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   %1 = call i32 @defined_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
                                    i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
   ret i32 %1
@@ -994,35 +837,6 @@ define fastcc void @fastcc_call_nonfastcc(){
 ; RV64I-LARGE-NEXT:    addi sp, sp, 32
 ; RV64I-LARGE-NEXT:    .cfi_def_cfa_offset 0
 ; RV64I-LARGE-NEXT:    ret
-;
-; RV64I-LARGE-ZICFILP-LABEL: fastcc_call_nonfastcc:
-; RV64I-LARGE-ZICFILP:       # %bb.0:
-; RV64I-LARGE-ZICFILP-NEXT:    lpad 0
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, -32
-; RV64I-LARGE-ZICFILP-NEXT:    .cfi_def_cfa_offset 32
-; RV64I-LARGE-ZICFILP-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
-; RV64I-LARGE-ZICFILP-NEXT:    .cfi_offset ra, -8
-; RV64I-LARGE-ZICFILP-NEXT:    li t0, 10
-; RV64I-LARGE-ZICFILP-NEXT:    li t1, 9
-; RV64I-LARGE-ZICFILP-NEXT:  .Lpcrel_hi6:
-; RV64I-LARGE-ZICFILP-NEXT:    auipc a5, %pcrel_hi(.LCPI11_0)
-; RV64I-LARGE-ZICFILP-NEXT:    li a0, 1
-; RV64I-LARGE-ZICFILP-NEXT:    li a1, 2
-; RV64I-LARGE-ZICFILP-NEXT:    li a2, 3
-; RV64I-LARGE-ZICFILP-NEXT:    li a3, 4
-; RV64I-LARGE-ZICFILP-NEXT:    li a4, 5
-; RV64I-LARGE-ZICFILP-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi6)(a5)
-; RV64I-LARGE-ZICFILP-NEXT:    li a5, 6
-; RV64I-LARGE-ZICFILP-NEXT:    li a6, 7
-; RV64I-LARGE-ZICFILP-NEXT:    li a7, 8
-; RV64I-LARGE-ZICFILP-NEXT:    sd t1, 0(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    sd t0, 8(sp)
-; RV64I-LARGE-ZICFILP-NEXT:    jalr t2
-; RV64I-LARGE-ZICFILP-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
-; RV64I-LARGE-ZICFILP-NEXT:    .cfi_restore ra
-; RV64I-LARGE-ZICFILP-NEXT:    addi sp, sp, 32
-; RV64I-LARGE-ZICFILP-NEXT:    .cfi_def_cfa_offset 0
-; RV64I-LARGE-ZICFILP-NEXT:    ret
   call void @external_many_args(i32 1, i32 2,i32 3,i32 4,i32 5,i32 6,i32 7,i32 8,i32 9,i32 10)
   ret void
 }
diff --git a/llvm/test/CodeGen/RISCV/tail-calls.ll b/llvm/test/CodeGen/RISCV/tail-calls.ll
index 366b37ac5d472..4d164c84e9d3f 100644
--- a/llvm/test/CodeGen/RISCV/tail-calls.ll
+++ b/llvm/test/CodeGen/RISCV/tail-calls.ll
@@ -1,8 +1,5 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 ; RUN: llc -mtriple riscv32-unknown-linux-gnu -o - %s | FileCheck %s
-; RUN: llc -mtriple riscv32-unknown-linux-gnu -mattr=experimental-zicfilp \
-; RUN:   -code-model=large -o - %s \
-; RUN:   | FileCheck %s -check-prefix=CHECK-LARGE-ZICFILP
 ; RUN: llc -mtriple riscv32-unknown-elf       -o - %s | FileCheck %s
 
 ; Perform tail call optimization for global address.
@@ -11,14 +8,6 @@ define i32 @caller_tail(i32 %i) nounwind {
 ; CHECK-LABEL: caller_tail:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    tail callee_tail
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_tail:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi0:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI0_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi0)(a1)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
 entry:
   %r = tail call i32 @callee_tail(i32 %i)
   ret i32 %r
@@ -37,21 +26,6 @@ define void @caller_extern(ptr %src) optsize {
 ; CHECK-NEXT:    mv a0, a1
 ; CHECK-NEXT:    mv a1, a3
 ; CHECK-NEXT:    tail memcpy
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_extern:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi1:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI1_0)
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi2:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a2, %pcrel_hi(.LCPI1_1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw a1, %pcrel_lo(.Lpcrel_hi1)(a1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi2)(a2)
-; CHECK-LARGE-ZICFILP-NEXT:    li a2, 7
-; CHECK-LARGE-ZICFILP-NEXT:    mv a3, a0
-; CHECK-LARGE-ZICFILP-NEXT:    mv a0, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a1, a3
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
 entry:
   tail call void @llvm.memcpy.p0.p0.i32(ptr @dest, ptr %src, i32 7, i1 false)
   ret void
@@ -69,21 +43,6 @@ define void @caller_extern_pgso(ptr %src) !prof !14 {
 ; CHECK-NEXT:    mv a0, a1
 ; CHECK-NEXT:    mv a1, a3
 ; CHECK-NEXT:    tail memcpy
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_extern_pgso:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi3:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI2_0)
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi4:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a2, %pcrel_hi(.LCPI2_1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw a1, %pcrel_lo(.Lpcrel_hi3)(a1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi4)(a2)
-; CHECK-LARGE-ZICFILP-NEXT:    li a2, 7
-; CHECK-LARGE-ZICFILP-NEXT:    mv a3, a0
-; CHECK-LARGE-ZICFILP-NEXT:    mv a0, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a1, a3
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
 entry:
   tail call void @llvm.memcpy.p0.p0.i32(ptr @dest_pgso, ptr %src, i32 7, i1 false)
   ret void
@@ -104,21 +63,6 @@ define void @caller_indirect_tail(i32 %a) nounwind {
 ; CHECK-NEXT:    lui t1, %hi(callee_indirect1)
 ; CHECK-NEXT:    addi t1, t1, %lo(callee_indirect1)
 ; CHECK-NEXT:    jr t1
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_tail:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    beqz a0, .LBB3_2
-; CHECK-LARGE-ZICFILP-NEXT:  # %bb.1: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi6:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t1, %pcrel_lo(.Lpcrel_hi6)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t1
-; CHECK-LARGE-ZICFILP-NEXT:  .LBB3_2:
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi5:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI3_1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t1, %pcrel_lo(.Lpcrel_hi5)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t1
 entry:
   %tobool = icmp eq i32 %a, 0
   %callee = select i1 %tobool, ptr @callee_indirect1, ptr @callee_indirect2
@@ -140,19 +84,6 @@ define i32 @caller_indirect_no_t0(ptr %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5
 ; CHECK-NEXT:    mv a5, a6
 ; CHECK-NEXT:    mv a6, a7
 ; CHECK-NEXT:    jr t1
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_no_t0:
-; CHECK-LARGE-ZICFILP:       # %bb.0:
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    mv t1, a0
-; CHECK-LARGE-ZICFILP-NEXT:    mv a0, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a1, a2
-; CHECK-LARGE-ZICFILP-NEXT:    mv a2, a3
-; CHECK-LARGE-ZICFILP-NEXT:    mv a3, a4
-; CHECK-LARGE-ZICFILP-NEXT:    mv a4, a5
-; CHECK-LARGE-ZICFILP-NEXT:    mv a5, a6
-; CHECK-LARGE-ZICFILP-NEXT:    mv a6, a7
-; CHECK-LARGE-ZICFILP-NEXT:    jr t1
   %9 = tail call i32 %0(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7)
   ret i32 %9
 }
@@ -175,26 +106,6 @@ define void @caller_varargs(i32 %a, i32 %b) nounwind {
 ; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 16
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_varargs:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi7:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a2, %pcrel_hi(.LCPI5_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi7)(a2)
-; CHECK-LARGE-ZICFILP-NEXT:    sw a0, 0(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    mv a2, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a3, a0
-; CHECK-LARGE-ZICFILP-NEXT:    mv a4, a0
-; CHECK-LARGE-ZICFILP-NEXT:    mv a5, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a6, a1
-; CHECK-LARGE-ZICFILP-NEXT:    mv a7, a0
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a, i32 %a, i32 %b, i32 %b, i32 %a, i32 %a)
   ret void
@@ -223,31 +134,6 @@ define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g
 ; CHECK-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 32
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_args:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -32
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    lw t0, 32(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t1, 36(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t3, 40(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t4, 44(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, 48(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t5, 52(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t2, 16(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t5, 20(sp)
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi8:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc t2, %pcrel_hi(.LCPI6_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi8)(t2)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t0, 0(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t1, 4(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t3, 8(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw t4, 12(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 32
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n)
   ret i32 %r
@@ -270,25 +156,6 @@ define void @caller_indirect_args() nounwind {
 ; CHECK-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 32
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_indirect_args:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -32
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    lui a1, 262128
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi9:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi9)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    mv a0, sp
-; CHECK-LARGE-ZICFILP-NEXT:    sw zero, 0(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw zero, 4(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw zero, 8(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw a1, 12(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 32
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   %call = tail call i32 @callee_indirect_args(fp128 0xL00000000000000003FFF000000000000)
   ret void
@@ -300,14 +167,6 @@ define void @caller_weak() nounwind {
 ; CHECK-LABEL: caller_weak:
 ; CHECK:       # %bb.0: # %entry
 ; CHECK-NEXT:    tail callee_weak
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_weak:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi10:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi10)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
 entry:
   tail call void @callee_weak()
   ret void
@@ -356,48 +215,6 @@ define void @caller_irq() nounwind "interrupt"="machine" {
 ; CHECK-NEXT:    lw t6, 0(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 64
 ; CHECK-NEXT:    mret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_irq:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -64
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 60(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t0, 56(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t1, 52(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t2, 48(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a0, 44(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a1, 40(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a2, 36(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a3, 32(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a4, 28(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a5, 24(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a6, 20(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw a7, 16(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t3, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t4, 8(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t5, 4(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    sw t6, 0(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi11:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI9_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi11)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 60(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t0, 56(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t1, 52(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, 48(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a0, 44(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a1, 40(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a2, 36(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a3, 32(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a4, 28(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a5, 24(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a6, 20(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw a7, 16(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t3, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t4, 8(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t5, 4(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    lw t6, 0(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 64
-; CHECK-LARGE-ZICFILP-NEXT:    mret
 entry:
   tail call void @callee_irq()
   ret void
@@ -419,22 +236,6 @@ define i32 @caller_byval() nounwind {
 ; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 16
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_byval:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:    lw a0, 8(sp)
-; CHECK-LARGE-ZICFILP-NEXT:    sw a0, 4(sp)
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi12:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI10_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi12)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    addi a0, sp, 4
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   %a = alloca ptr
   %r = tail call i32 @callee_byval(ptr byval(ptr) %a)
@@ -457,22 +258,6 @@ define void @caller_nostruct() nounwind {
 ; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 16
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_nostruct:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi13:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI11_0)
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi14:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI11_1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi13)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi14)(a1)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   tail call void @callee_struct(ptr sret(%struct.A) @a)
   ret void
@@ -489,19 +274,6 @@ define void @caller_struct(ptr sret(%struct.A) %a) nounwind {
 ; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 16
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: caller_struct:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi15:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI12_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi15)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   tail call void @callee_nostruct()
   ret void
@@ -517,19 +289,6 @@ define i32 @disable_tail_calls(i32 %i) nounwind "disable-tail-calls"="true" {
 ; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
 ; CHECK-NEXT:    addi sp, sp, 16
 ; CHECK-NEXT:    ret
-;
-; CHECK-LARGE-ZICFILP-LABEL: disable_tail_calls:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, -16
-; CHECK-LARGE-ZICFILP-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi16:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a1, %pcrel_hi(.LCPI13_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi16)(a1)
-; CHECK-LARGE-ZICFILP-NEXT:    jalr t2
-; CHECK-LARGE-ZICFILP-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
-; CHECK-LARGE-ZICFILP-NEXT:    addi sp, sp, 16
-; CHECK-LARGE-ZICFILP-NEXT:    ret
 entry:
   %rv = tail call i32 @callee_tail(i32 %i)
   ret i32 %rv
@@ -556,35 +315,6 @@ define i32 @duplicate_returns(i32 %a, i32 %b) nounwind {
 ; CHECK-NEXT:    tail test1
 ; CHECK-NEXT:  .LBB14_6: # %if.else8
 ; CHECK-NEXT:    tail test3
-;
-; CHECK-LARGE-ZICFILP-LABEL: duplicate_returns:
-; CHECK-LARGE-ZICFILP:       # %bb.0: # %entry
-; CHECK-LARGE-ZICFILP-NEXT:    lpad 0
-; CHECK-LARGE-ZICFILP-NEXT:    beqz a0, .LBB14_4
-; CHECK-LARGE-ZICFILP-NEXT:  # %bb.1: # %if.else
-; CHECK-LARGE-ZICFILP-NEXT:    beqz a1, .LBB14_5
-; CHECK-LARGE-ZICFILP-NEXT:  # %bb.2: # %if.else4
-; CHECK-LARGE-ZICFILP-NEXT:    bge a1, a0, .LBB14_6
-; CHECK-LARGE-ZICFILP-NEXT:  # %bb.3: # %if.then6
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi19:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI14_1)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi19)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
-; CHECK-LARGE-ZICFILP-NEXT:  .LBB14_4: # %if.then
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi17:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI14_3)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi17)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
-; CHECK-LARGE-ZICFILP-NEXT:  .LBB14_5: # %if.then2
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi18:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI14_2)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi18)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
-; CHECK-LARGE-ZICFILP-NEXT:  .LBB14_6: # %if.else8
-; CHECK-LARGE-ZICFILP-NEXT:  .Lpcrel_hi20:
-; CHECK-LARGE-ZICFILP-NEXT:    auipc a0, %pcrel_hi(.LCPI14_0)
-; CHECK-LARGE-ZICFILP-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi20)(a0)
-; CHECK-LARGE-ZICFILP-NEXT:    jr t2
 entry:
   %cmp = icmp eq i32 %a, 0
   br i1 %cmp, label %if.then, label %if.else
diff --git a/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-calls.ll b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-calls.ll
new file mode 100644
index 0000000000000..0cd8dff8cd02b
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-calls.ll
@@ -0,0 +1,253 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -code-model=large -mtriple=riscv64 -verify-machineinstrs < %s \
+; RUN:   | FileCheck %s
+
+declare i32 @external_function(i32)
+
+define i32 @test_call_external(i32 %a) nounwind {
+; CHECK-LABEL: test_call_external:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi0:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI0_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi0)(a1)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call i32 @external_function(i32 %a)
+  ret i32 %1
+}
+
+declare dso_local i32 @dso_local_function(i32)
+
+define i32 @test_call_dso_local(i32 %a) nounwind {
+; CHECK-LABEL: test_call_dso_local:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi1:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI1_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi1)(a1)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call i32 @dso_local_function(i32 %a)
+  ret i32 %1
+}
+
+define i32 @defined_function(i32 %a) nounwind {
+; CHECK-LABEL: defined_function:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addiw a0, a0, 1
+; CHECK-NEXT:    ret
+  %1 = add i32 %a, 1
+  ret i32 %1
+}
+
+define i32 @test_call_defined(i32 %a) nounwind {
+; CHECK-LABEL: test_call_defined:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi2:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI3_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi2)(a1)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call i32 @defined_function(i32 %a)
+  ret i32 %1
+}
+
+define i32 @test_call_indirect(ptr %a, i32 %b) nounwind {
+; CHECK-LABEL: test_call_indirect:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    jalr a2
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call i32 %a(i32 %b)
+  ret i32 %1
+}
+
+; Make sure we don't use t0 as the source for jalr as that is a hint to pop the
+; return address stack on some microarchitectures.
+define i32 @test_call_indirect_no_t0(ptr %a, i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h) nounwind {
+; CHECK-LABEL: test_call_indirect_no_t0:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    mv t1, a0
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:    mv a3, a4
+; CHECK-NEXT:    mv a4, a5
+; CHECK-NEXT:    mv a5, a6
+; CHECK-NEXT:    mv a6, a7
+; CHECK-NEXT:    jalr t1
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call i32 %a(i32 %b, i32 %c, i32 %d, i32 %e, i32 %f, i32 %g, i32 %h)
+  ret i32 %1
+}
+
+; Ensure that calls to fastcc functions aren't rejected. Such calls may be
+; introduced when compiling with optimisation.
+
+define fastcc i32 @fastcc_function(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: fastcc_function:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addw a0, a0, a1
+; CHECK-NEXT:    ret
+ %1 = add i32 %a, %b
+ ret i32 %1
+}
+
+define i32 @test_call_fastcc(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: test_call_fastcc:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    sd s0, 0(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    mv s0, a0
+; CHECK-NEXT:  .Lpcrel_hi3:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi3)(a0)
+; CHECK-NEXT:    mv a0, s0
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    mv a0, s0
+; CHECK-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    ld s0, 0(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+  %1 = call fastcc i32 @fastcc_function(i32 %a, i32 %b)
+  ret i32 %a
+}
+
+declare i32 @external_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) nounwind
+
+define i32 @test_call_external_many_args(i32 %a) nounwind {
+; CHECK-LABEL: test_call_external_many_args:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    sd s0, 16(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    mv s0, a0
+; CHECK-NEXT:  .Lpcrel_hi4:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi4)(a0)
+; CHECK-NEXT:    sd s0, 0(sp)
+; CHECK-NEXT:    sd s0, 8(sp)
+; CHECK-NEXT:    mv a0, s0
+; CHECK-NEXT:    mv a1, s0
+; CHECK-NEXT:    mv a2, s0
+; CHECK-NEXT:    mv a3, s0
+; CHECK-NEXT:    mv a4, s0
+; CHECK-NEXT:    mv a5, s0
+; CHECK-NEXT:    mv a6, s0
+; CHECK-NEXT:    mv a7, s0
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    mv a0, s0
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    ld s0, 16(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    ret
+  %1 = call i32 @external_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
+                                    i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
+  ret i32 %a
+}
+
+define i32 @defined_many_args(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32 %j) nounwind {
+; CHECK-LABEL: defined_many_args:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    lw a0, 8(sp)
+; CHECK-NEXT:    addiw a0, a0, 1
+; CHECK-NEXT:    ret
+  %added = add i32 %j, 1
+  ret i32 %added
+}
+
+define i32 @test_call_defined_many_args(i32 %a) nounwind {
+; CHECK-LABEL: test_call_defined_many_args:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi5:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI10_0)
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi5)(a1)
+; CHECK-NEXT:    sd a0, 0(sp)
+; CHECK-NEXT:    sd a0, 8(sp)
+; CHECK-NEXT:    mv a1, a0
+; CHECK-NEXT:    mv a2, a0
+; CHECK-NEXT:    mv a3, a0
+; CHECK-NEXT:    mv a4, a0
+; CHECK-NEXT:    mv a5, a0
+; CHECK-NEXT:    mv a6, a0
+; CHECK-NEXT:    mv a7, a0
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    ret
+  %1 = call i32 @defined_many_args(i32 %a, i32 %a, i32 %a, i32 %a, i32 %a,
+                                   i32 %a, i32 %a, i32 %a, i32 %a, i32 %a)
+  ret i32 %1
+}
+
+define fastcc void @fastcc_call_nonfastcc(){
+; CHECK-LABEL: fastcc_call_nonfastcc:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    .cfi_def_cfa_offset 32
+; CHECK-NEXT:    sd ra, 24(sp) # 8-byte Folded Spill
+; CHECK-NEXT:    .cfi_offset ra, -8
+; CHECK-NEXT:    li t0, 10
+; CHECK-NEXT:    li t1, 9
+; CHECK-NEXT:  .Lpcrel_hi6:
+; CHECK-NEXT:    auipc a5, %pcrel_hi(.LCPI11_0)
+; CHECK-NEXT:    li a0, 1
+; CHECK-NEXT:    li a1, 2
+; CHECK-NEXT:    li a2, 3
+; CHECK-NEXT:    li a3, 4
+; CHECK-NEXT:    li a4, 5
+; CHECK-NEXT:    ld t2, %pcrel_lo(.Lpcrel_hi6)(a5)
+; CHECK-NEXT:    li a5, 6
+; CHECK-NEXT:    li a6, 7
+; CHECK-NEXT:    li a7, 8
+; CHECK-NEXT:    sd t1, 0(sp)
+; CHECK-NEXT:    sd t0, 8(sp)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    ld ra, 24(sp) # 8-byte Folded Reload
+; CHECK-NEXT:    .cfi_restore ra
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    .cfi_def_cfa_offset 0
+; CHECK-NEXT:    ret
+  call void @external_many_args(i32 1, i32 2,i32 3,i32 4,i32 5,i32 6,i32 7,i32 8,i32 9,i32 10)
+  ret void
+}
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
diff --git a/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-tail-calls.ll b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-tail-calls.ll
new file mode 100644
index 0000000000000..8cfc83bb11a4c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-tail-calls.ll
@@ -0,0 +1,434 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple riscv32-unknown-linux-gnu -code-model=large -o - %s | FileCheck %s
+
+; Perform tail call optimization for global address.
+declare i32 @callee_tail(i32 %i)
+define i32 @caller_tail(i32 %i) nounwind {
+; CHECK-LABEL: caller_tail:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:  .Lpcrel_hi0:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI0_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi0)(a1)
+; CHECK-NEXT:    jr t2
+entry:
+  %r = tail call i32 @callee_tail(i32 %i)
+  ret i32 %r
+}
+
+; Perform tail call optimization for external symbol.
+ at dest = global [2 x i8] zeroinitializer
+declare void @llvm.memcpy.p0.p0.i32(ptr, ptr, i32, i1)
+define void @caller_extern(ptr %src) optsize {
+; CHECK-LABEL: caller_extern:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:  .Lpcrel_hi1:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI1_0)
+; CHECK-NEXT:  .Lpcrel_hi2:
+; CHECK-NEXT:    auipc a2, %pcrel_hi(.LCPI1_1)
+; CHECK-NEXT:    lw a1, %pcrel_lo(.Lpcrel_hi1)(a1)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi2)(a2)
+; CHECK-NEXT:    li a2, 7
+; CHECK-NEXT:    mv a3, a0
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    mv a1, a3
+; CHECK-NEXT:    jr t2
+entry:
+  tail call void @llvm.memcpy.p0.p0.i32(ptr @dest, ptr %src, i32 7, i1 false)
+  ret void
+}
+
+; Perform tail call optimization for external symbol.
+ at dest_pgso = global [2 x i8] zeroinitializer
+define void @caller_extern_pgso(ptr %src) !prof !14 {
+; CHECK-LABEL: caller_extern_pgso:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:  .Lpcrel_hi3:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI2_0)
+; CHECK-NEXT:  .Lpcrel_hi4:
+; CHECK-NEXT:    auipc a2, %pcrel_hi(.LCPI2_1)
+; CHECK-NEXT:    lw a1, %pcrel_lo(.Lpcrel_hi3)(a1)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi4)(a2)
+; CHECK-NEXT:    li a2, 7
+; CHECK-NEXT:    mv a3, a0
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    mv a1, a3
+; CHECK-NEXT:    jr t2
+entry:
+  tail call void @llvm.memcpy.p0.p0.i32(ptr @dest_pgso, ptr %src, i32 7, i1 false)
+  ret void
+}
+
+; Perform indirect tail call optimization (for function pointer call).
+declare void @callee_indirect1()
+declare void @callee_indirect2()
+define void @caller_indirect_tail(i32 %a) nounwind {
+; CHECK-LABEL: caller_indirect_tail:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    beqz a0, .LBB3_2
+; CHECK-NEXT:  # %bb.1: # %entry
+; CHECK-NEXT:  .Lpcrel_hi6:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI3_0)
+; CHECK-NEXT:    lw t1, %pcrel_lo(.Lpcrel_hi6)(a0)
+; CHECK-NEXT:    jr t1
+; CHECK-NEXT:  .LBB3_2:
+; CHECK-NEXT:  .Lpcrel_hi5:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI3_1)
+; CHECK-NEXT:    lw t1, %pcrel_lo(.Lpcrel_hi5)(a0)
+; CHECK-NEXT:    jr t1
+entry:
+  %tobool = icmp eq i32 %a, 0
+  %callee = select i1 %tobool, ptr @callee_indirect1, ptr @callee_indirect2
+  tail call void %callee()
+  ret void
+}
+
+; Make sure we don't use t0 as the source for jr as that is a hint to pop the
+; return address stack on some microarchitectures.
+define i32 @caller_indirect_no_t0(ptr %0, i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7) {
+; CHECK-LABEL: caller_indirect_no_t0:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    mv t1, a0
+; CHECK-NEXT:    mv a0, a1
+; CHECK-NEXT:    mv a1, a2
+; CHECK-NEXT:    mv a2, a3
+; CHECK-NEXT:    mv a3, a4
+; CHECK-NEXT:    mv a4, a5
+; CHECK-NEXT:    mv a5, a6
+; CHECK-NEXT:    mv a6, a7
+; CHECK-NEXT:    jr t1
+  %9 = tail call i32 %0(i32 %1, i32 %2, i32 %3, i32 %4, i32 %5, i32 %6, i32 %7)
+  ret i32 %9
+}
+
+; Do not tail call optimize functions with varargs passed by stack.
+declare i32 @callee_varargs(i32, ...)
+define void @caller_varargs(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: caller_varargs:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi7:
+; CHECK-NEXT:    auipc a2, %pcrel_hi(.LCPI5_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi7)(a2)
+; CHECK-NEXT:    sw a0, 0(sp)
+; CHECK-NEXT:    mv a2, a1
+; CHECK-NEXT:    mv a3, a0
+; CHECK-NEXT:    mv a4, a0
+; CHECK-NEXT:    mv a5, a1
+; CHECK-NEXT:    mv a6, a1
+; CHECK-NEXT:    mv a7, a0
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+entry:
+  %call = tail call i32 (i32, ...) @callee_varargs(i32 %a, i32 %b, i32 %b, i32 %a, i32 %a, i32 %b, i32 %b, i32 %a, i32 %a)
+  ret void
+}
+
+; Do not tail call optimize if stack is used to pass parameters.
+declare i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n)
+define i32 @caller_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n) nounwind {
+; CHECK-LABEL: caller_args:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    lw t0, 32(sp)
+; CHECK-NEXT:    lw t1, 36(sp)
+; CHECK-NEXT:    lw t3, 40(sp)
+; CHECK-NEXT:    lw t4, 44(sp)
+; CHECK-NEXT:    lw t2, 48(sp)
+; CHECK-NEXT:    lw t5, 52(sp)
+; CHECK-NEXT:    sw t2, 16(sp)
+; CHECK-NEXT:    sw t5, 20(sp)
+; CHECK-NEXT:  .Lpcrel_hi8:
+; CHECK-NEXT:    auipc t2, %pcrel_hi(.LCPI6_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi8)(t2)
+; CHECK-NEXT:    sw t0, 0(sp)
+; CHECK-NEXT:    sw t1, 4(sp)
+; CHECK-NEXT:    sw t3, 8(sp)
+; CHECK-NEXT:    sw t4, 12(sp)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    ret
+entry:
+  %r = tail call i32 @callee_args(i32 %a, i32 %b, i32 %c, i32 %dd, i32 %e, i32 %ff, i32 %g, i32 %h, i32 %i, i32 %j, i32 %k, i32 %l, i32 %m, i32 %n)
+  ret i32 %r
+}
+
+; Do not tail call optimize if parameters need to be passed indirectly.
+declare i32 @callee_indirect_args(fp128 %a)
+define void @caller_indirect_args() nounwind {
+; CHECK-LABEL: caller_indirect_args:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -32
+; CHECK-NEXT:    sw ra, 28(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    lui a1, 262128
+; CHECK-NEXT:  .Lpcrel_hi9:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI7_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi9)(a0)
+; CHECK-NEXT:    mv a0, sp
+; CHECK-NEXT:    sw zero, 0(sp)
+; CHECK-NEXT:    sw zero, 4(sp)
+; CHECK-NEXT:    sw zero, 8(sp)
+; CHECK-NEXT:    sw a1, 12(sp)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 28(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 32
+; CHECK-NEXT:    ret
+entry:
+  %call = tail call i32 @callee_indirect_args(fp128 0xL00000000000000003FFF000000000000)
+  ret void
+}
+
+; Perform tail call optimization for external weak symbol.
+declare extern_weak void @callee_weak()
+define void @caller_weak() nounwind {
+; CHECK-LABEL: caller_weak:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:  .Lpcrel_hi10:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI8_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi10)(a0)
+; CHECK-NEXT:    jr t2
+entry:
+  tail call void @callee_weak()
+  ret void
+}
+
+; Exception-handling functions need a special set of instructions to indicate a
+; return to the hardware. Tail-calling another function would probably break
+; this.
+declare void @callee_irq()
+define void @caller_irq() nounwind "interrupt"="machine" {
+; CHECK-LABEL: caller_irq:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    addi sp, sp, -64
+; CHECK-NEXT:    sw ra, 60(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t0, 56(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t1, 52(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t2, 48(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a0, 44(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a1, 40(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a2, 36(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a3, 32(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a4, 28(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a5, 24(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a6, 20(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw a7, 16(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t3, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t4, 8(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t5, 4(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    sw t6, 0(sp) # 4-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi11:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI9_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi11)(a0)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 60(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t0, 56(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t1, 52(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t2, 48(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a0, 44(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a1, 40(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a2, 36(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a3, 32(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a4, 28(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a5, 24(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a6, 20(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw a7, 16(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t3, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t4, 8(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t5, 4(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    lw t6, 0(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 64
+; CHECK-NEXT:    mret
+entry:
+  tail call void @callee_irq()
+  ret void
+}
+
+; Byval parameters hand the function a pointer directly into the stack area
+; we want to reuse during a tail call. Do not tail call optimize functions with
+; byval parameters.
+declare i32 @callee_byval(ptr byval(ptr) %a)
+define i32 @caller_byval() nounwind {
+; CHECK-LABEL: caller_byval:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:    lw a0, 8(sp)
+; CHECK-NEXT:    sw a0, 4(sp)
+; CHECK-NEXT:  .Lpcrel_hi12:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI10_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi12)(a0)
+; CHECK-NEXT:    addi a0, sp, 4
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+entry:
+  %a = alloca ptr
+  %r = tail call i32 @callee_byval(ptr byval(ptr) %a)
+  ret i32 %r
+}
+
+; Do not tail call optimize if callee uses structret semantics.
+%struct.A = type { i32 }
+ at a = global %struct.A zeroinitializer
+
+declare void @callee_struct(ptr sret(%struct.A) %a)
+define void @caller_nostruct() nounwind {
+; CHECK-LABEL: caller_nostruct:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi13:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI11_0)
+; CHECK-NEXT:  .Lpcrel_hi14:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI11_1)
+; CHECK-NEXT:    lw a0, %pcrel_lo(.Lpcrel_hi13)(a0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi14)(a1)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+entry:
+  tail call void @callee_struct(ptr sret(%struct.A) @a)
+  ret void
+}
+
+; Do not tail call optimize if caller uses structret semantics.
+declare void @callee_nostruct()
+define void @caller_struct(ptr sret(%struct.A) %a) nounwind {
+; CHECK-LABEL: caller_struct:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi15:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI12_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi15)(a0)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+entry:
+  tail call void @callee_nostruct()
+  ret void
+}
+
+; Do not tail call optimize if disabled.
+define i32 @disable_tail_calls(i32 %i) nounwind "disable-tail-calls"="true" {
+; CHECK-LABEL: disable_tail_calls:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    addi sp, sp, -16
+; CHECK-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
+; CHECK-NEXT:  .Lpcrel_hi16:
+; CHECK-NEXT:    auipc a1, %pcrel_hi(.LCPI13_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi16)(a1)
+; CHECK-NEXT:    jalr t2
+; CHECK-NEXT:    lw ra, 12(sp) # 4-byte Folded Reload
+; CHECK-NEXT:    addi sp, sp, 16
+; CHECK-NEXT:    ret
+entry:
+  %rv = tail call i32 @callee_tail(i32 %i)
+  ret i32 %rv
+}
+
+; Duplicate returns to enable tail call optimizations.
+declare i32 @test()
+declare i32 @test1()
+declare i32 @test2()
+declare i32 @test3()
+define i32 @duplicate_returns(i32 %a, i32 %b) nounwind {
+; CHECK-LABEL: duplicate_returns:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    auipc zero, 0
+; CHECK-NEXT:    beqz a0, .LBB14_4
+; CHECK-NEXT:  # %bb.1: # %if.else
+; CHECK-NEXT:    beqz a1, .LBB14_5
+; CHECK-NEXT:  # %bb.2: # %if.else4
+; CHECK-NEXT:    bge a1, a0, .LBB14_6
+; CHECK-NEXT:  # %bb.3: # %if.then6
+; CHECK-NEXT:  .Lpcrel_hi19:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI14_1)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi19)(a0)
+; CHECK-NEXT:    jr t2
+; CHECK-NEXT:  .LBB14_4: # %if.then
+; CHECK-NEXT:  .Lpcrel_hi17:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI14_3)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi17)(a0)
+; CHECK-NEXT:    jr t2
+; CHECK-NEXT:  .LBB14_5: # %if.then2
+; CHECK-NEXT:  .Lpcrel_hi18:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI14_2)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi18)(a0)
+; CHECK-NEXT:    jr t2
+; CHECK-NEXT:  .LBB14_6: # %if.else8
+; CHECK-NEXT:  .Lpcrel_hi20:
+; CHECK-NEXT:    auipc a0, %pcrel_hi(.LCPI14_0)
+; CHECK-NEXT:    lw t2, %pcrel_lo(.Lpcrel_hi20)(a0)
+; CHECK-NEXT:    jr t2
+entry:
+  %cmp = icmp eq i32 %a, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %call = tail call i32 @test()
+  br label %return
+
+if.else:                                          ; preds = %entry
+  %cmp1 = icmp eq i32 %b, 0
+  br i1 %cmp1, label %if.then2, label %if.else4
+
+if.then2:                                         ; preds = %if.else
+  %call3 = tail call i32 @test1()
+  br label %return
+
+if.else4:                                         ; preds = %if.else
+  %cmp5 = icmp sgt i32 %a, %b
+  br i1 %cmp5, label %if.then6, label %if.else8
+
+if.then6:                                         ; preds = %if.else4
+  %call7 = tail call i32 @test2()
+  br label %return
+
+if.else8:                                         ; preds = %if.else4
+  %call9 = tail call i32 @test3()
+  br label %return
+
+return:                                           ; preds = %if.else8, %if.then6, %if.then2, %if.then
+  %retval = phi i32 [ %call, %if.then ], [ %call3, %if.then2 ], [ %call7, %if.then6 ], [ %call9, %if.else8 ]
+  ret i32 %retval
+}
+
+!llvm.module.flags = !{!0, !15, !16}
+!0 = !{i32 1, !"ProfileSummary", !1}
+!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
+!2 = !{!"ProfileFormat", !"InstrProf"}
+!3 = !{!"TotalCount", i64 10000}
+!4 = !{!"MaxCount", i64 10}
+!5 = !{!"MaxInternalCount", i64 1}
+!6 = !{!"MaxFunctionCount", i64 1000}
+!7 = !{!"NumCounts", i64 3}
+!8 = !{!"NumFunctions", i64 3}
+!9 = !{!"DetailedSummary", !10}
+!10 = !{!11, !12, !13}
+!11 = !{i32 10000, i64 100, i32 1}
+!12 = !{i32 999000, i64 100, i32 1}
+!13 = !{i32 999999, i64 1, i32 2}
+!14 = !{!"function_entry_count", i64 0}
+!15 = !{i32 8, !"cf-protection-branch", i32 1}
+!16 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}

>From 8f601dd4799d9ce5c7636a82450981d995b90a9c Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Wed, 6 Aug 2025 17:59:04 +0800
Subject: [PATCH 04/10] fixup: Codegen software-guarded jumps for jump tables
 based on Zicfilp CFI feature adoption instead of Zicfilp extension
 availability

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  4 +-
 .../test/CodeGen/RISCV/jumptable-swguarded.ll | 48 ++++---------------
 2 files changed, 10 insertions(+), 42 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 86d51b8d7d172..0f490cb1890a4 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -24545,8 +24545,8 @@ SDValue RISCVTargetLowering::expandIndirectJTBranch(const SDLoc &dl,
                                                     SDValue Value, SDValue Addr,
                                                     int JTI,
                                                     SelectionDAG &DAG) const {
-  if (Subtarget.hasStdExtZicfilp()) {
-    // When Zicfilp enabled, we need to use software guarded branch for jump
+  if (Subtarget.hasZicfilpCFI()) {
+    // When Zicfilp CFI is used, we need to use software guarded branch for jump
     // table branch.
     SDValue Chain = Value;
     // Jump table debug info is only needed if CodeView is enabled.
diff --git a/llvm/test/CodeGen/RISCV/jumptable-swguarded.ll b/llvm/test/CodeGen/RISCV/jumptable-swguarded.ll
index b4ab0585c0cc9..32e3af6af5ad3 100644
--- a/llvm/test/CodeGen/RISCV/jumptable-swguarded.ll
+++ b/llvm/test/CodeGen/RISCV/jumptable-swguarded.ll
@@ -1,14 +1,11 @@
-; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp < %s | FileCheck %s
-; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp < %s | FileCheck %s
-; RUN: llc -mtriple riscv32 < %s | FileCheck %s --check-prefix=NO-ZICFILP
-; RUN: llc -mtriple riscv64 < %s | FileCheck %s --check-prefix=NO-ZICFILP
+; RUN: llc -mtriple riscv32 < %s | FileCheck %s
+; RUN: llc -mtriple riscv64 < %s | FileCheck %s
 
 ; Test using t2 to jump table branch.
 define void @above_threshold(i32 signext %in, ptr %out) nounwind {
 ; CHECK-LABEL: above_threshold:
 ; CHECK:       # %bb.0: # %entry
-; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    auipc zero, 0
 ; CHECK-NEXT:    addi a0, a0, -1
 ; CHECK-NEXT:    li a2, 5
 ; CHECK-NEXT:    bltu a2, a0, .LBB0_9
@@ -40,40 +37,6 @@ define void @above_threshold(i32 signext %in, ptr %out) nounwind {
 ; CHECK-NEXT:    sw a0, 0(a1)
 ; CHECK-NEXT:  .LBB0_9: # %exit
 ; CHECK-NEXT:    ret
-;
-; NO-ZICFILP-LABEL: above_threshold:
-; NO-ZICFILP:       # %bb.0: # %entry
-; NO-ZICFILP-NEXT:    addi a0, a0, -1
-; NO-ZICFILP-NEXT:    li a2, 5
-; NO-ZICFILP-NEXT:    bltu a2, a0, .LBB0_9
-; NO-ZICFILP-NEXT:  # %bb.1: # %entry
-; NO-ZICFILP-NEXT:    slli a0, a0, 2
-; NO-ZICFILP-NEXT:    lui a2, %hi(.LJTI0_0)
-; NO-ZICFILP-NEXT:    addi a2, a2, %lo(.LJTI0_0)
-; NO-ZICFILP-NEXT:    add a0, a2, a0
-; NO-ZICFILP-NEXT:    lw a0, 0(a0)
-; NO-ZICFILP-NEXT:    jr a0
-; NO-ZICFILP-NEXT:  .LBB0_2: # %bb1
-; NO-ZICFILP-NEXT:    li a0, 4
-; NO-ZICFILP-NEXT:    j .LBB0_8
-; NO-ZICFILP-NEXT:  .LBB0_3: # %bb5
-; NO-ZICFILP-NEXT:    li a0, 100
-; NO-ZICFILP-NEXT:    j .LBB0_8
-; NO-ZICFILP-NEXT:  .LBB0_4: # %bb3
-; NO-ZICFILP-NEXT:    li a0, 2
-; NO-ZICFILP-NEXT:    j .LBB0_8
-; NO-ZICFILP-NEXT:  .LBB0_5: # %bb4
-; NO-ZICFILP-NEXT:    li a0, 1
-; NO-ZICFILP-NEXT:    j .LBB0_8
-; NO-ZICFILP-NEXT:  .LBB0_6: # %bb2
-; NO-ZICFILP-NEXT:    li a0, 3
-; NO-ZICFILP-NEXT:    j .LBB0_8
-; NO-ZICFILP-NEXT:  .LBB0_7: # %bb6
-; NO-ZICFILP-NEXT:    li a0, 200
-; NO-ZICFILP-NEXT:  .LBB0_8: # %exit
-; NO-ZICFILP-NEXT:    sw a0, 0(a1)
-; NO-ZICFILP-NEXT:  .LBB0_9: # %exit
-; NO-ZICFILP-NEXT:    ret
 entry:
   switch i32 %in, label %exit [
     i32 1, label %bb1
@@ -104,3 +67,8 @@ bb6:
 exit:
   ret void
 }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}

>From 876c7cae06b33df4d86ce8a5020c46ad7c3054eb Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Thu, 7 Aug 2025 14:49:38 +0800
Subject: [PATCH 05/10] fixup: Fix codegen of nested functions

---
 llvm/lib/Target/RISCV/RISCVCallingConv.cpp    |  4 +-
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  5 +--
 llvm/test/CodeGen/RISCV/nest-register.ll      | 26 -------------
 .../test/CodeGen/RISCV/rv64-trampoline-cfi.ll | 13 +++----
 .../RISCV/zicfilp-unlabeled-nest-register.ll  | 38 +++++++++++++++++++
 5 files changed, 46 insertions(+), 40 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/zicfilp-unlabeled-nest-register.ll

diff --git a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
index cb6117eb0917b..908b976d6e4bb 100644
--- a/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCallingConv.cpp
@@ -337,9 +337,7 @@ bool llvm::CC_RISCV(unsigned ValNo, MVT ValVT, MVT LocVT,
     // Static chain parameter must not be passed in normal argument registers,
     // so we assign t2/t3 for it as done in GCC's
     // __builtin_call_with_static_chain
-    bool HasCFBranch =
-        Subtarget.hasStdExtZicfilp() &&
-        MF.getFunction().getParent()->getModuleFlag("cf-protection-branch");
+    bool HasCFBranch = Subtarget.hasZicfilpCFI();
 
     // Normal: t2, Branch control flow protection: t3
     const auto StaticChainReg = HasCFBranch ? RISCV::X28 : RISCV::X7;
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0f490cb1890a4..d7d602b102de5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -8528,10 +8528,7 @@ SDValue RISCVTargetLowering::lowerINIT_TRAMPOLINE(SDValue Op,
   //     28: <FunctionAddressOffset>
   //     36:
 
-  const bool HasCFBranch =
-      Subtarget.hasStdExtZicfilp() &&
-      DAG.getMachineFunction().getFunction().getParent()->getModuleFlag(
-          "cf-protection-branch");
+  const bool HasCFBranch = Subtarget.hasZicfilpCFI();
   const unsigned StaticChainIdx = HasCFBranch ? 5 : 4;
   const unsigned StaticChainOffset = StaticChainIdx * 4;
   const unsigned FunctionAddressOffset = StaticChainOffset + 8;
diff --git a/llvm/test/CodeGen/RISCV/nest-register.ll b/llvm/test/CodeGen/RISCV/nest-register.ll
index 6e892e05c4297..e222beee45783 100644
--- a/llvm/test/CodeGen/RISCV/nest-register.ll
+++ b/llvm/test/CodeGen/RISCV/nest-register.ll
@@ -3,10 +3,6 @@
 ; RUN:   | FileCheck -check-prefix=RV32I %s
 ; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \
 ; RUN:   | FileCheck -check-prefix=RV64I %s
-; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfilp -verify-machineinstrs < %s \
-; RUN:   | FileCheck -check-prefix=RV64I-ZICFILP %s
-; RUN: not llc -mtriple=riscv64 -target-abi=lp64e -mattr=+experimental-zicfilp \
-; RUN:   -verify-machineinstrs < %s 2>&1 | FileCheck -check-prefix=LP64E-ZICFILP %s
 
 ; Tests that the 'nest' parameter attribute causes the relevant parameter to be
 ; passed in the right register.
@@ -21,12 +17,6 @@ define ptr @nest_receiver(ptr nest %arg) nounwind {
 ; RV64I:       # %bb.0:
 ; RV64I-NEXT:    mv a0, t2
 ; RV64I-NEXT:    ret
-;
-; RV64I-ZICFILP-LABEL: nest_receiver:
-; RV64I-ZICFILP:       # %bb.0:
-; RV64I-ZICFILP-NEXT:    lpad 0
-; RV64I-ZICFILP-NEXT:    mv a0, t3
-; RV64I-ZICFILP-NEXT:    ret
   ret ptr %arg
 }
 
@@ -50,22 +40,6 @@ define ptr @nest_caller(ptr %arg) nounwind {
 ; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
 ; RV64I-NEXT:    addi sp, sp, 16
 ; RV64I-NEXT:    ret
-;
-; RV64I-ZICFILP-LABEL: nest_caller:
-; RV64I-ZICFILP:       # %bb.0:
-; RV64I-ZICFILP-NEXT:    lpad 0
-; RV64I-ZICFILP-NEXT:    addi sp, sp, -16
-; RV64I-ZICFILP-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
-; RV64I-ZICFILP-NEXT:    mv t3, a0
-; RV64I-ZICFILP-NEXT:    call nest_receiver
-; RV64I-ZICFILP-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
-; RV64I-ZICFILP-NEXT:    addi sp, sp, 16
-; RV64I-ZICFILP-NEXT:    ret
   %result = call ptr @nest_receiver(ptr nest %arg)
   ret ptr %result
 }
-
-; LP64E-ZICFILP: LLVM ERROR: Nested functions with control flow protection are not usable with ILP32E or LP64E ABI.
-!llvm.module.flags = !{!0}
-
-!0 = !{i32 8, !"cf-protection-branch", i32 1}
diff --git a/llvm/test/CodeGen/RISCV/rv64-trampoline-cfi.ll b/llvm/test/CodeGen/RISCV/rv64-trampoline-cfi.ll
index 8a338a855c863..a50fa1924718b 100644
--- a/llvm/test/CodeGen/RISCV/rv64-trampoline-cfi.ll
+++ b/llvm/test/CodeGen/RISCV/rv64-trampoline-cfi.ll
@@ -1,8 +1,6 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
-; RUN: llc -O0 -mtriple=riscv64 -mattr=+experimental-zicfilp -verify-machineinstrs < %s \
-; RUN:   | FileCheck -check-prefix=RV64 %s
-; RUN: llc -O0 -mtriple=riscv64-unknown-linux-gnu -mattr=+experimental-zicfilp -verify-machineinstrs < %s \
-; RUN:   | FileCheck -check-prefix=RV64-LINUX %s
+; RUN: llc -O0 -mtriple=riscv64 -verify-machineinstrs < %s | FileCheck -check-prefix=RV64 %s
+; RUN: llc -O0 -mtriple=riscv64-unknown-linux-gnu -verify-machineinstrs < %s | FileCheck -check-prefix=RV64-LINUX %s
 
 declare void @llvm.init.trampoline(ptr, ptr, ptr)
 declare ptr @llvm.adjust.trampoline(ptr)
@@ -11,7 +9,7 @@ declare i64 @f(ptr nest, i64)
 define i64 @test0(i64 %n, ptr %p) nounwind {
 ; RV64-LABEL: test0:
 ; RV64:       # %bb.0:
-; RV64-NEXT:    lpad 0
+; RV64-NEXT:    auipc zero, 0
 ; RV64-NEXT:    addi sp, sp, -64
 ; RV64-NEXT:    sd ra, 56(sp) # 8-byte Folded Spill
 ; RV64-NEXT:    sd a0, 0(sp) # 8-byte Folded Spill
@@ -50,7 +48,7 @@ define i64 @test0(i64 %n, ptr %p) nounwind {
 ;
 ; RV64-LINUX-LABEL: test0:
 ; RV64-LINUX:       # %bb.0:
-; RV64-LINUX-NEXT:    lpad 0
+; RV64-LINUX-NEXT:    auipc zero, 0
 ; RV64-LINUX-NEXT:    addi sp, sp, -64
 ; RV64-LINUX-NEXT:    sd ra, 56(sp) # 8-byte Folded Spill
 ; RV64-LINUX-NEXT:    sd a0, 0(sp) # 8-byte Folded Spill
@@ -94,6 +92,7 @@ define i64 @test0(i64 %n, ptr %p) nounwind {
   ret i64 %ret
 }
 
-!llvm.module.flags = !{!0}
+!llvm.module.flags = !{!0, !1}
 
 !0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
diff --git a/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-nest-register.ll b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-nest-register.ll
new file mode 100644
index 0000000000000..89454e8f830b1
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zicfilp-unlabeled-nest-register.ll
@@ -0,0 +1,38 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s | \
+; RUN:    FileCheck -check-prefix=RV64I %s
+; RUN: not llc -mtriple=riscv64 -target-abi=lp64e -verify-machineinstrs < %s \
+; RUN:    2>&1 | FileCheck -check-prefix=LP64E %s
+
+; Tests that the 'nest' parameter attribute causes the relevant parameter to be
+; passed in the right register.
+
+define ptr @nest_receiver(ptr nest %arg) nounwind {
+; RV64I-LABEL: nest_receiver:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    auipc zero, 0
+; RV64I-NEXT:    mv a0, t3
+; RV64I-NEXT:    ret
+  ret ptr %arg
+}
+
+define ptr @nest_caller(ptr %arg) nounwind {
+; RV64I-LABEL: nest_caller:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    auipc zero, 0
+; RV64I-NEXT:    addi sp, sp, -16
+; RV64I-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
+; RV64I-NEXT:    mv t3, a0
+; RV64I-NEXT:    call nest_receiver
+; RV64I-NEXT:    ld ra, 8(sp) # 8-byte Folded Reload
+; RV64I-NEXT:    addi sp, sp, 16
+; RV64I-NEXT:    ret
+  %result = call ptr @nest_receiver(ptr nest %arg)
+  ret ptr %result
+}
+
+; LP64E: LLVM ERROR: Nested functions with control flow protection are not usable with ILP32E or LP64E ABI.
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}

>From 32ee08d9bd872e69b3f3c02b2db1fff90760b869 Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Wed, 6 Aug 2025 16:20:29 +0800
Subject: [PATCH 06/10] fixup: Use RISCVSubtarget::ZicfilpLabelScheme in
 RISCVIndirectBranchTracking pass

---
 .../RISCV/RISCVIndirectBranchTracking.cpp     | 26 +++++--------------
 1 file changed, 7 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
index 554f7d5494731..f795031a866f1 100644
--- a/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
+++ b/llvm/lib/Target/RISCV/RISCVIndirectBranchTracking.cpp
@@ -19,14 +19,12 @@
 #include "llvm/CodeGen/MachineFunctionPass.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
 #include "llvm/CodeGen/MachineModuleInfo.h"
-#include "llvm/IR/Module.h"
-#include "llvm/Support/RISCVISAUtils.h"
+#include "llvm/Support/Error.h"
 
 #define DEBUG_TYPE "riscv-indrect-branch-tracking"
 #define PASS_NAME "RISC-V Indirect Branch Tracking"
 
 using namespace llvm;
-using namespace llvm::RISCVISAUtils;
 
 cl::opt<uint32_t> PreferredLandingPadLabel(
     "riscv-landing-pad-label", cl::ReallyHidden,
@@ -66,25 +64,15 @@ static void emitLpad(MachineBasicBlock &MBB, const RISCVInstrInfo *TII,
 
 bool RISCVIndirectBranchTracking::runOnMachineFunction(MachineFunction &MF) {
   const auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
-  const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
-
-  const Module *const M = MF.getFunction().getParent();
-  if (!M)
-    return false;
-  if (const Metadata *const Flag = M->getModuleFlag("cf-protection-branch");
-      !Flag || mdconst::extract<ConstantInt>(Flag)->isZero())
+  if (!Subtarget.hasZicfilpCFI())
     return false;
 
-  StringRef CFBranchLabelScheme;
-  if (const Metadata *const MD = M->getModuleFlag("cf-branch-label-scheme"))
-    CFBranchLabelScheme = cast<MDString>(MD)->getString();
-  else
-    report_fatal_error("missing cf-branch-label-scheme module flag");
+  const RISCVInstrInfo *TII = Subtarget.getInstrInfo();
 
-  const ZicfilpLabelSchemeKind Scheme =
-      getZicfilpLabelScheme(CFBranchLabelScheme);
-  if (Scheme != ZicfilpLabelSchemeKind::Unlabeled)
-    report_fatal_error("unsupported cf-branch-label-scheme module flag");
+  if (Subtarget.getZicfilpLabelScheme() !=
+      RISCVSubtarget::ZicfilpLabelSchemeKind::Unlabeled)
+    reportFatalUsageError(
+        "only cf-branch-label-scheme=unlabeled is supported for now");
 
   uint32_t FixedLabel = 0;
   if (PreferredLandingPadLabel.getNumOccurrences() > 0) {

>From fc0bfdfc6bc098087e9619054d18237f20f6981c Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Thu, 7 Aug 2025 15:02:48 +0800
Subject: [PATCH 07/10] fixup: Codegen landing pad setup insns based on cf
 flags

---
 .../lib/Target/RISCV/RISCVLandingPadSetup.cpp |  2 +-
 llvm/test/CodeGen/RISCV/lpad.ll               | 54 +++++++++----------
 2 files changed, 27 insertions(+), 29 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp b/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp
index 072694e123084..9b5cd1f5d0b80 100644
--- a/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp
+++ b/llvm/lib/Target/RISCV/RISCVLandingPadSetup.cpp
@@ -48,7 +48,7 @@ bool RISCVLandingPadSetup::runOnMachineFunction(MachineFunction &MF) {
   const auto &STI = MF.getSubtarget<RISCVSubtarget>();
   const RISCVInstrInfo &TII = *STI.getInstrInfo();
 
-  if (!STI.hasStdExtZicfilp())
+  if (!STI.hasZicfilpCFI())
     return false;
 
   uint32_t Label = 0;
diff --git a/llvm/test/CodeGen/RISCV/lpad.ll b/llvm/test/CodeGen/RISCV/lpad.ll
index f69b4dad068b5..4676d06a29725 100644
--- a/llvm/test/CodeGen/RISCV/lpad.ll
+++ b/llvm/test/CodeGen/RISCV/lpad.ll
@@ -1,17 +1,15 @@
 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV32
-; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp < %s | FileCheck %s --check-prefixes=CHECK,RV64
-; RUN: llc -mtriple riscv32 -mattr=+experimental-zicfilp \
-; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV32
-; RUN: llc -mtriple riscv64 -mattr=+experimental-zicfilp \
-; RUN: -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV64
+; RUN: llc -mtriple riscv32 < %s | FileCheck %s --check-prefixes=CHECK,RV32
+; RUN: llc -mtriple riscv64 < %s | FileCheck %s --check-prefixes=CHECK,RV64
+; RUN: llc -mtriple riscv32 -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV32
+; RUN: llc -mtriple riscv64 -riscv-landing-pad-label=1 < %s | FileCheck %s --check-prefixes=FIXED-ONE,FIXED-ONE-RV64
 
 ; Check indirectbr.
 @__const.indirctbr.addr = private unnamed_addr constant [2 x ptr] [ptr blockaddress(@indirctbr, %labelA), ptr blockaddress(@indirctbr, %labelB)], align 8
 define void @indirctbr(i32 %i, ptr %p) {
 ; RV32-LABEL: indirctbr:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    lpad 0
+; RV32-NEXT:    auipc zero, 0
 ; RV32-NEXT:    slli a0, a0, 2
 ; RV32-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
 ; RV32-NEXT:    addi a2, a2, %lo(.L__const.indirctbr.addr)
@@ -21,20 +19,20 @@ define void @indirctbr(i32 %i, ptr %p) {
 ; RV32-NEXT:    .p2align 2
 ; RV32-NEXT:  .Ltmp3: # Block address taken
 ; RV32-NEXT:  .LBB0_1: # %labelA
-; RV32-NEXT:    lpad 0
+; RV32-NEXT:    auipc zero, 0
 ; RV32-NEXT:    li a0, 1
 ; RV32-NEXT:    sw a0, 0(a1)
 ; RV32-NEXT:    .p2align 2
 ; RV32-NEXT:  .Ltmp4: # Block address taken
 ; RV32-NEXT:  .LBB0_2: # %labelB
-; RV32-NEXT:    lpad 0
+; RV32-NEXT:    auipc zero, 0
 ; RV32-NEXT:    li a0, 2
 ; RV32-NEXT:    sw a0, 0(a1)
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: indirctbr:
 ; RV64:       # %bb.0: # %entry
-; RV64-NEXT:    lpad 0
+; RV64-NEXT:    auipc zero, 0
 ; RV64-NEXT:    sext.w a0, a0
 ; RV64-NEXT:    slli a0, a0, 3
 ; RV64-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
@@ -45,20 +43,20 @@ define void @indirctbr(i32 %i, ptr %p) {
 ; RV64-NEXT:    .p2align 2
 ; RV64-NEXT:  .Ltmp3: # Block address taken
 ; RV64-NEXT:  .LBB0_1: # %labelA
-; RV64-NEXT:    lpad 0
+; RV64-NEXT:    auipc zero, 0
 ; RV64-NEXT:    li a0, 1
 ; RV64-NEXT:    sw a0, 0(a1)
 ; RV64-NEXT:    .p2align 2
 ; RV64-NEXT:  .Ltmp4: # Block address taken
 ; RV64-NEXT:  .LBB0_2: # %labelB
-; RV64-NEXT:    lpad 0
+; RV64-NEXT:    auipc zero, 0
 ; RV64-NEXT:    li a0, 2
 ; RV64-NEXT:    sw a0, 0(a1)
 ; RV64-NEXT:    ret
 ;
 ; FIXED-ONE-RV32-LABEL: indirctbr:
 ; FIXED-ONE-RV32:       # %bb.0: # %entry
-; FIXED-ONE-RV32-NEXT:    lpad 1
+; FIXED-ONE-RV32-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV32-NEXT:    slli a0, a0, 2
 ; FIXED-ONE-RV32-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
 ; FIXED-ONE-RV32-NEXT:    addi a2, a2, %lo(.L__const.indirctbr.addr)
@@ -69,20 +67,20 @@ define void @indirctbr(i32 %i, ptr %p) {
 ; FIXED-ONE-RV32-NEXT:    .p2align 2
 ; FIXED-ONE-RV32-NEXT:  .Ltmp3: # Block address taken
 ; FIXED-ONE-RV32-NEXT:  .LBB0_1: # %labelA
-; FIXED-ONE-RV32-NEXT:    lpad 1
+; FIXED-ONE-RV32-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV32-NEXT:    li a0, 1
 ; FIXED-ONE-RV32-NEXT:    sw a0, 0(a1)
 ; FIXED-ONE-RV32-NEXT:    .p2align 2
 ; FIXED-ONE-RV32-NEXT:  .Ltmp4: # Block address taken
 ; FIXED-ONE-RV32-NEXT:  .LBB0_2: # %labelB
-; FIXED-ONE-RV32-NEXT:    lpad 1
+; FIXED-ONE-RV32-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV32-NEXT:    li a0, 2
 ; FIXED-ONE-RV32-NEXT:    sw a0, 0(a1)
 ; FIXED-ONE-RV32-NEXT:    ret
 ;
 ; FIXED-ONE-RV64-LABEL: indirctbr:
 ; FIXED-ONE-RV64:       # %bb.0: # %entry
-; FIXED-ONE-RV64-NEXT:    lpad 1
+; FIXED-ONE-RV64-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV64-NEXT:    sext.w a0, a0
 ; FIXED-ONE-RV64-NEXT:    slli a0, a0, 3
 ; FIXED-ONE-RV64-NEXT:    lui a2, %hi(.L__const.indirctbr.addr)
@@ -94,13 +92,13 @@ define void @indirctbr(i32 %i, ptr %p) {
 ; FIXED-ONE-RV64-NEXT:    .p2align 2
 ; FIXED-ONE-RV64-NEXT:  .Ltmp3: # Block address taken
 ; FIXED-ONE-RV64-NEXT:  .LBB0_1: # %labelA
-; FIXED-ONE-RV64-NEXT:    lpad 1
+; FIXED-ONE-RV64-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV64-NEXT:    li a0, 1
 ; FIXED-ONE-RV64-NEXT:    sw a0, 0(a1)
 ; FIXED-ONE-RV64-NEXT:    .p2align 2
 ; FIXED-ONE-RV64-NEXT:  .Ltmp4: # Block address taken
 ; FIXED-ONE-RV64-NEXT:  .LBB0_2: # %labelB
-; FIXED-ONE-RV64-NEXT:    lpad 1
+; FIXED-ONE-RV64-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV64-NEXT:    li a0, 2
 ; FIXED-ONE-RV64-NEXT:    sw a0, 0(a1)
 ; FIXED-ONE-RV64-NEXT:    ret
@@ -122,12 +120,12 @@ labelB:                                           ; preds = %labelA, %entry
 define void @call(ptr %0) {
 ; CHECK-LABEL: call:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    auipc zero, 0
 ; CHECK-NEXT:    jr a0
 ;
 ; FIXED-ONE-LABEL: call:
 ; FIXED-ONE:       # %bb.0:
-; FIXED-ONE-NEXT:    lpad 1
+; FIXED-ONE-NEXT:    auipc zero, 1
 ; FIXED-ONE-NEXT:    lui t2, 1
 ; FIXED-ONE-NEXT:    jr a0
   tail call void %0()
@@ -139,7 +137,7 @@ declare dso_local i32 @__gxx_personality_v0(...)
 define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 {
 ; RV32-LABEL: invoke:
 ; RV32:       # %bb.0: # %entry
-; RV32-NEXT:    lpad 0
+; RV32-NEXT:    auipc zero, 0
 ; RV32-NEXT:    addi sp, sp, -16
 ; RV32-NEXT:    .cfi_def_cfa_offset 16
 ; RV32-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
@@ -161,7 +159,7 @@ define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 {
 ;
 ; RV64-LABEL: invoke:
 ; RV64:       # %bb.0: # %entry
-; RV64-NEXT:    lpad 0
+; RV64-NEXT:    auipc zero, 0
 ; RV64-NEXT:    addi sp, sp, -16
 ; RV64-NEXT:    .cfi_def_cfa_offset 16
 ; RV64-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
@@ -183,7 +181,7 @@ define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 {
 ;
 ; FIXED-ONE-RV32-LABEL: invoke:
 ; FIXED-ONE-RV32:       # %bb.0: # %entry
-; FIXED-ONE-RV32-NEXT:    lpad 1
+; FIXED-ONE-RV32-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV32-NEXT:    addi sp, sp, -16
 ; FIXED-ONE-RV32-NEXT:    .cfi_def_cfa_offset 16
 ; FIXED-ONE-RV32-NEXT:    sw ra, 12(sp) # 4-byte Folded Spill
@@ -206,7 +204,7 @@ define void @invoke(ptr %f) personality ptr @__gxx_personality_v0 {
 ;
 ; FIXED-ONE-RV64-LABEL: invoke:
 ; FIXED-ONE-RV64:       # %bb.0: # %entry
-; FIXED-ONE-RV64-NEXT:    lpad 1
+; FIXED-ONE-RV64-NEXT:    auipc zero, 1
 ; FIXED-ONE-RV64-NEXT:    addi sp, sp, -16
 ; FIXED-ONE-RV64-NEXT:    .cfi_def_cfa_offset 16
 ; FIXED-ONE-RV64-NEXT:    sd ra, 8(sp) # 8-byte Folded Spill
@@ -241,12 +239,12 @@ try.cont:
 define void @external() {
 ; CHECK-LABEL: external:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    auipc zero, 0
 ; CHECK-NEXT:    ret
 ;
 ; FIXED-ONE-LABEL: external:
 ; FIXED-ONE:       # %bb.0:
-; FIXED-ONE-NEXT:    lpad 1
+; FIXED-ONE-NEXT:    auipc zero, 1
 ; FIXED-ONE-NEXT:    ret
   ret void
 }
@@ -268,12 +266,12 @@ define internal void @internal() {
 define internal void @internal2() {
 ; CHECK-LABEL: internal2:
 ; CHECK:       # %bb.0:
-; CHECK-NEXT:    lpad 0
+; CHECK-NEXT:    auipc zero, 0
 ; CHECK-NEXT:    ret
 ;
 ; FIXED-ONE-LABEL: internal2:
 ; FIXED-ONE:       # %bb.0:
-; FIXED-ONE-NEXT:    lpad 1
+; FIXED-ONE-NEXT:    auipc zero, 1
 ; FIXED-ONE-NEXT:    ret
   ret void
 }

>From c8a374d5a4a482740eba1b825ae771ec12dd56ca Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Thu, 7 Aug 2025 15:01:02 +0800
Subject: [PATCH 08/10] fixup: Fix misc Zicfilp-based tests to base on cf flags

---
 .../RISCV/zicfilp-disabled-indirect-branch.ll | 41 +++++++++++++++++++
 .../CodeGen/RISCV/zicfilp-indirect-branch.ll  | 18 ++++----
 2 files changed, 49 insertions(+), 10 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/zicfilp-disabled-indirect-branch.ll

diff --git a/llvm/test/CodeGen/RISCV/zicfilp-disabled-indirect-branch.ll b/llvm/test/CodeGen/RISCV/zicfilp-disabled-indirect-branch.ll
new file mode 100644
index 0000000000000..897260908075c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zicfilp-disabled-indirect-branch.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
+; RUN: llc -mtriple=riscv64 -stop-after=finalize-isel < %s | FileCheck %s
+
+ at brind.arr = internal unnamed_addr constant [2 x ptr] [ptr blockaddress(@brind, %5), ptr blockaddress(@brind, %8)], align 8
+ at x = dso_local global i32 0, align 4
+
+define void @brind(i32 noundef signext %0) {
+  ; CHECK-LABEL: name: brind
+  ; CHECK:   PseudoBRIND killed [[VAR:%.*]], 0
+  %2 = sext i32 %0 to i64
+  %3 = getelementptr inbounds [2 x ptr], ptr @brind.arr, i64 0, i64 %2
+  %4 = load ptr, ptr %3, align 8
+  indirectbr ptr %4, [label %5, label %8]
+
+5:                                                ; preds = %1
+  %6 = load i32, ptr @x, align 4
+  %7 = add nsw i32 %6, 2
+  store i32 %7, ptr @x, align 4
+  br label %8
+
+8:                                                ; preds = %5, %1
+  %9 = load i32, ptr @x, align 4
+  %10 = add nsw i32 %9, 1
+  store i32 %10, ptr @x, align 4
+  ret void
+}
+
+define i32 @indirect_call(ptr %0) {
+  ; CHECK-LABEL: name: indirect_call
+  ; CHECK: PseudoCALLIndirect
+  call void %0()
+  ret i32 0
+}
+
+
+define void @indirect_tail(ptr %0) {
+  ; CHECK-LABEL: name: indirect_tail
+  ; CHECK: PseudoTAILIndirect
+  tail call void %0()
+  ret void
+}
diff --git a/llvm/test/CodeGen/RISCV/zicfilp-indirect-branch.ll b/llvm/test/CodeGen/RISCV/zicfilp-indirect-branch.ll
index bccd28ee7e2b3..277f0d67b1d93 100644
--- a/llvm/test/CodeGen/RISCV/zicfilp-indirect-branch.ll
+++ b/llvm/test/CodeGen/RISCV/zicfilp-indirect-branch.ll
@@ -1,15 +1,12 @@
 ; NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 3
 ; RUN: llc -mtriple=riscv64 -stop-after=finalize-isel < %s | FileCheck %s
-; RUN: llc -mtriple=riscv64 -mattr=+experimental-zicfilp -stop-after=finalize-isel < %s | FileCheck -check-prefixes=ZICFILP %s
 
 @brind.arr = internal unnamed_addr constant [2 x ptr] [ptr blockaddress(@brind, %5), ptr blockaddress(@brind, %8)], align 8
 @x = dso_local global i32 0, align 4
 
 define void @brind(i32 noundef signext %0) {
   ; CHECK-LABEL: name: brind
-  ; CHECK:   PseudoBRIND killed [[VAR:%.*]], 0
-  ; ZICFILP-LABEL: name: brind
-  ; ZICFILP:   PseudoBRINDNonX7 killed [[VAR:%.*]], 0
+  ; CHECK:   PseudoBRINDNonX7 killed [[VAR:%.*]], 0
   %2 = sext i32 %0 to i64
   %3 = getelementptr inbounds [2 x ptr], ptr @brind.arr, i64 0, i64 %2
   %4 = load ptr, ptr %3, align 8
@@ -30,9 +27,7 @@ define void @brind(i32 noundef signext %0) {
 
 define i32 @indirect_call(ptr %0) {
   ; CHECK-LABEL: name: indirect_call
-  ; CHECK: PseudoCALLIndirect
-  ; ZICFILP-LABEL: name: indirect_call
-  ; ZICFILP: PseudoCALLIndirectNonX7
+  ; CHECK: PseudoCALLIndirectNonX7
   call void %0()
   ret i32 0
 }
@@ -40,9 +35,12 @@ define i32 @indirect_call(ptr %0) {
 
 define void @indirect_tail(ptr %0) {
   ; CHECK-LABEL: name: indirect_tail
-  ; CHECK: PseudoTAILIndirect
-  ; ZICFILP-LABEL: name: indirect_tail
-  ; ZICFILP: PseudoTAILIndirectNonX7
+  ; CHECK: PseudoTAILIndirectNonX7
   tail call void %0()
   ret void
 }
+
+!llvm.module.flags = !{!0, !1}
+
+!0 = !{i32 8, !"cf-protection-branch", i32 1}
+!1 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}

>From 3b9222337fab2939304f4d891e856389daf451d4 Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Fri, 8 Aug 2025 11:06:57 +0800
Subject: [PATCH 09/10] fixup: Misc improvements

---
 llvm/lib/Target/RISCV/RISCVSubtarget.h       |  2 +-
 llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 15 +++++++++------
 2 files changed, 10 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 424087b8ca83b..bf545ae594e4a 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -94,7 +94,7 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
 
   enum class ZicfilpLabelSchemeKind {
     Disabled,
-    Unknown,
+    EnabledUnknown,
     Unlabeled,
     FuncSig,
   };
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index fee8a2598be5b..ab4f523205af1 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -270,16 +270,19 @@ RISCVTargetMachine::getSubtargetImpl(const Function &F) const {
           StringSwitch<ZicfilpLabelSchemeKind>(CFBranchLabelScheme)
               .Case("unlabeled", ZicfilpLabelSchemeKind::Unlabeled)
               .Case("func-sig", ZicfilpLabelSchemeKind::FuncSig)
-              .Default(ZicfilpLabelSchemeKind::Unknown);
-      assert(ZicfilpLabelScheme != ZicfilpLabelSchemeKind::Unknown);
+              .Default(ZicfilpLabelSchemeKind::EnabledUnknown);
+      assert(ZicfilpLabelScheme != ZicfilpLabelSchemeKind::EnabledUnknown);
     }
   }
 
   SmallString<512> Key;
-  raw_svector_ostream(Key) << "RVVMin" << RVVBitsMin << "RVVMax" << RVVBitsMax
-                           << "ZicfilpLabelSchemeKind"
-                           << to_underlying(ZicfilpLabelScheme) << CPU
-                           << TuneCPU << FS;
+  {
+    raw_svector_ostream OS(Key);
+    OS << "RVVMin" << RVVBitsMin << "RVVMax" << RVVBitsMax;
+    if (ZicfilpLabelScheme != ZicfilpLabelSchemeKind::Disabled)
+      OS << "ZicfilpLabelSchemeKind" << to_underlying(ZicfilpLabelScheme);
+    OS << CPU << TuneCPU << FS;
+  }
   auto &I = SubtargetMap[Key];
   if (!I) {
     // This needs to be done before we create a new subtarget since any

>From cb9940d684b1d1fc96b8455d7f6c8f3f72eed9b3 Mon Sep 17 00:00:00 2001
From: Ming-Yi Lai <ming-yi.lai at mediatek.com>
Date: Fri, 8 Aug 2025 17:56:34 +0800
Subject: [PATCH 10/10] fixup: Add LTO tests

---
 .../branch-cfi/Inputs/rv32-foo-disabled.ll    | 18 ++++++++
 .../Inputs/rv32-foo-unknown-scheme.ll         | 20 +++++++++
 .../branch-cfi/Inputs/rv32-foo-unlabeled.ll   | 20 +++++++++
 .../branch-cfi/Inputs/rv64-foo-disabled.ll    | 18 ++++++++
 .../Inputs/rv64-foo-unknown-scheme.ll         | 20 +++++++++
 .../branch-cfi/Inputs/rv64-foo-unlabeled.ll   | 20 +++++++++
 .../LTO/RISCV/branch-cfi/rv32-unlabeled.ll    | 43 +++++++++++++++++++
 .../LTO/RISCV/branch-cfi/rv64-unlabeled.ll    | 43 +++++++++++++++++++
 8 files changed, 202 insertions(+)
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-disabled.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unknown-scheme.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unlabeled.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-disabled.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unknown-scheme.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unlabeled.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/rv32-unlabeled.ll
 create mode 100644 llvm/test/LTO/RISCV/branch-cfi/rv64-unlabeled.ll

diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-disabled.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-disabled.ll
new file mode 100644
index 0000000000000..45090922eafd0
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-disabled.ll
@@ -0,0 +1,18 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"ilp32"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv32i2p1"}
+!4 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unknown-scheme.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unknown-scheme.ll
new file mode 100644
index 0000000000000..c390edddb0c0a
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unknown-scheme.ll
@@ -0,0 +1,20 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"ilp32"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv32i2p1"}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unknown-scheme"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unlabeled.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unlabeled.ll
new file mode 100644
index 0000000000000..7c6f56422683e
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv32-foo-unlabeled.ll
@@ -0,0 +1,20 @@
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"ilp32"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv32i2p1"}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-disabled.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-disabled.ll
new file mode 100644
index 0000000000000..e59f8ec41c1a6
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-disabled.ll
@@ -0,0 +1,18 @@
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local signext i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"lp64"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv64i2p1"}
+!4 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unknown-scheme.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unknown-scheme.ll
new file mode 100644
index 0000000000000..f308f10dd718d
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unknown-scheme.ll
@@ -0,0 +1,20 @@
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local signext i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"lp64"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv64i2p1"}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unknown-scheme"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unlabeled.ll b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unlabeled.ll
new file mode 100644
index 0000000000000..0aa7f112ba942
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/Inputs/rv64-foo-unlabeled.ll
@@ -0,0 +1,20 @@
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local signext i32 @foo() #0 {
+entry:
+  ret i32 0
+}
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"lp64"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv64i2p1"}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
diff --git a/llvm/test/LTO/RISCV/branch-cfi/rv32-unlabeled.ll b/llvm/test/LTO/RISCV/branch-cfi/rv32-unlabeled.ll
new file mode 100644
index 0000000000000..cb29af67b777e
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/rv32-unlabeled.ll
@@ -0,0 +1,43 @@
+; RUN: llvm-as %s -o %t.main.bc
+; RUN: llvm-as %p/Inputs/rv32-foo-unlabeled.ll -o %t.foo.unlabeled.bc
+; RUN: llvm-link %t.main.bc %t.foo.unlabeled.bc -S | FileCheck --check-prefix=UNLABELED %s
+
+; RUN: llvm-as %p/Inputs/rv32-foo-disabled.ll -o %t.foo.disabled.bc
+; RUN: llvm-link %t.main.bc %t.foo.disabled.bc -S | FileCheck --check-prefix=DISABLED %s
+
+; RUN: llvm-as %p/Inputs/rv32-foo-unknown-scheme.ll -o %t.foo.unknown.scheme.bc
+; RUN: not llvm-link %t.main.bc %t.foo.unknown.scheme.bc 2>&1 | FileCheck --check-prefix=SCHEME-CONFLICT %s
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32-S128"
+target triple = "riscv32-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, ptr %retval, align 4
+  %call = call i32 @foo()
+  ret i32 %call
+}
+
+declare dso_local i32 @foo() #1
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit" }
+attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv32" "target-features"="+32bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"ilp32"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv32i2p1"}
+; UNLABELED-DAG: [[P_FLAG:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 1}
+; DISABLED-DAG: [[P_FLAG:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 0}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+; UNLABELED-DAG: [[S_FLAG:![0-9]+]] = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
+; UNLABELED-DAG: !llvm.module.flags = !{{[{].*}}[[P_FLAG]]{{, .*}}[[S_FLAG]]{{[,}]}}
+; DISABLED-DAG: !llvm.module.flags = !{{[{].*}}[[P_FLAG]]{{[,}]}}
+
+; SCHEME-CONFLICT: error: linking module flags 'cf-branch-label-scheme': IDs have conflicting values: '!"unknown-scheme"' from {{.*}}, and '!"unlabeled"' from llvm-link
diff --git a/llvm/test/LTO/RISCV/branch-cfi/rv64-unlabeled.ll b/llvm/test/LTO/RISCV/branch-cfi/rv64-unlabeled.ll
new file mode 100644
index 0000000000000..b0897a8462319
--- /dev/null
+++ b/llvm/test/LTO/RISCV/branch-cfi/rv64-unlabeled.ll
@@ -0,0 +1,43 @@
+; RUN: llvm-as %s -o %t.main.bc
+; RUN: llvm-as %p/Inputs/rv64-foo-unlabeled.ll -o %t.foo.unlabeled.bc
+; RUN: llvm-link %t.main.bc %t.foo.unlabeled.bc -S | FileCheck --check-prefix=UNLABELED %s
+
+; RUN: llvm-as %p/Inputs/rv64-foo-disabled.ll -o %t.foo.disabled.bc
+; RUN: llvm-link %t.main.bc %t.foo.disabled.bc -S | FileCheck --check-prefix=DISABLED %s
+
+; RUN: llvm-as %p/Inputs/rv64-foo-unknown-scheme.ll -o %t.foo.unknown.scheme.bc
+; RUN: not llvm-link %t.main.bc %t.foo.unknown.scheme.bc 2>&1 | FileCheck --check-prefix=SCHEME-CONFLICT %s
+
+target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
+target triple = "riscv64-unknown-linux-gnu"
+
+; Function Attrs: noinline nounwind optnone
+define dso_local signext i32 @main() #0 {
+entry:
+  %retval = alloca i32, align 4
+  store i32 0, ptr %retval, align 4
+  %call = call signext i32 @foo()
+  ret i32 %call
+}
+
+declare dso_local signext i32 @foo() #1
+
+attributes #0 = { noinline nounwind optnone "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit" }
+attributes #1 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="generic-rv64" "target-features"="+64bit" }
+
+!llvm.module.flags = !{!0, !1, !2, !4, !5, !6}
+
+!0 = !{i32 1, !"wchar_size", i32 4}
+!1 = !{i32 1, !"target-abi", !"lp64"}
+!2 = !{i32 6, !"riscv-isa", !3}
+!3 = !{!"rv64i2p1"}
+; UNLABELED-DAG: [[P_FLAG:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 1}
+; DISABLED-DAG: [[P_FLAG:![0-9]+]] = !{i32 8, !"cf-protection-branch", i32 0}
+!4 = !{i32 8, !"cf-protection-branch", i32 1}
+; UNLABELED-DAG: [[S_FLAG:![0-9]+]] = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!5 = !{i32 1, !"cf-branch-label-scheme", !"unlabeled"}
+!6 = !{i32 8, !"SmallDataLimit", i32 0}
+; UNLABELED-DAG: !llvm.module.flags = !{{[{].*}}[[P_FLAG]]{{, .*}}[[S_FLAG]]{{[,}]}}
+; DISABLED-DAG: !llvm.module.flags = !{{[{].*}}[[P_FLAG]]{{[,}]}}
+
+; SCHEME-CONFLICT: error: linking module flags 'cf-branch-label-scheme': IDs have conflicting values: '!"unknown-scheme"' from {{.*}}, and '!"unlabeled"' from llvm-link



More information about the llvm-commits mailing list