[llvm] [RISCV][Zicfilp] Codegen LPAD insns by looking at module flags (PR #152121)

Ming-Yi Lai via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 5 04:06:29 PDT 2025


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

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.

>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] [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"}



More information about the llvm-commits mailing list