[llvm] [NewPM] Port CFGuardLongjmp to the new pass manager (PR #218177)

Bill Wendling via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 22 18:07:55 PDT 2026


https://github.com/isanbard created https://github.com/llvm/llvm-project/pull/218177

Follow the same pattern used for EHContGuardTargets: extract the pass body into a free function, rename the legacy pass to CFGuardLongjmpLegacy, and add a CFGuardLongjmpPass for the new pass manager. Register it in MachinePassRegistry.def and wire it into X86's NewPM CodeGenPassBuilder pipeline (AArch64 and ARM do not yet have a NewPM CodeGenPassBuilder).

The pass only adds post-instruction symbols and never modifies the CFG, so mark it CFG-preserving in both the legacy getAnalysisUsage override and the new-PM run() return value, matching the fix applied to EHContGuardTargets in #217843.

Assisted-by: Claude Sonnet 5

>From 8a6ebe48bebf0c9998b78323a3b322cf5af8c250 Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Sat, 22 Aug 2026 18:06:43 -0700
Subject: [PATCH] [NewPM] Port CFGuardLongjmp to the new pass manager

Follow the same pattern used for EHContGuardTargets: extract the pass
body into a free function, rename the legacy pass to
CFGuardLongjmpLegacy, and add a CFGuardLongjmpPass for the new pass
manager. Register it in MachinePassRegistry.def and wire it into
X86's NewPM CodeGenPassBuilder pipeline (AArch64 and ARM do not yet
have a NewPM CodeGenPassBuilder).

The pass only adds post-instruction symbols and never modifies the
CFG, so mark it CFG-preserving in both the legacy getAnalysisUsage
override and the new-PM run() return value, matching the fix applied
to EHContGuardTargets in #217843.

Assisted-by: Claude Sonnet 5
---
 llvm/include/llvm/CodeGen/CFGuardLongjmp.h    | 24 ++++++
 llvm/include/llvm/CodeGen/Passes.h            |  2 +-
 llvm/include/llvm/InitializePasses.h          |  2 +-
 .../llvm/Passes/MachinePassRegistry.def       |  2 +-
 llvm/lib/CodeGen/CFGuardLongjmp.cpp           | 74 ++++++++++++-------
 llvm/lib/CodeGen/CodeGen.cpp                  |  2 +-
 llvm/lib/Passes/PassBuilder.cpp               |  1 +
 .../Target/AArch64/AArch64TargetMachine.cpp   |  2 +-
 llvm/lib/Target/ARM/ARMTargetMachine.cpp      |  2 +-
 llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp |  4 +-
 llvm/lib/Target/X86/X86TargetMachine.cpp      |  2 +-
 llvm/test/CodeGen/X86/cfguard-longjmp.ll      | 44 +++++++++++
 llvm/test/CodeGen/X86/llc-pipeline-npm.ll     |  2 +
 13 files changed, 126 insertions(+), 37 deletions(-)
 create mode 100644 llvm/include/llvm/CodeGen/CFGuardLongjmp.h
 create mode 100644 llvm/test/CodeGen/X86/cfguard-longjmp.ll

diff --git a/llvm/include/llvm/CodeGen/CFGuardLongjmp.h b/llvm/include/llvm/CodeGen/CFGuardLongjmp.h
new file mode 100644
index 0000000000000..07fbe2cc01460
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/CFGuardLongjmp.h
@@ -0,0 +1,24 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_CFGUARDLONGJMP_H
+#define LLVM_CODEGEN_CFGUARDLONGJMP_H
+
+#include "llvm/CodeGen/MachinePassManager.h"
+
+namespace llvm {
+
+class CFGuardLongjmpPass : public RequiredPassInfoMixin<CFGuardLongjmpPass> {
+public:
+  LLVM_ABI PreservedAnalyses run(MachineFunction &MF,
+                                 MachineFunctionAnalysisManager &MFAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_CFGUARDLONGJMP_H
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 8c2b923aeb807..518f8e71023d5 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -576,7 +576,7 @@ LLVM_ABI FunctionPass *createCFIInstrInserterLegacy();
 
 /// Creates CFGuard longjmp target identification pass.
 /// \see CFGuardLongjmp.cpp
-LLVM_ABI FunctionPass *createCFGuardLongjmpPass();
+LLVM_ABI FunctionPass *createCFGuardLongjmpLegacy();
 
 /// Creates Windows EH Continuation Guard target identification pass.
 /// \see EHContGuardTargets.cpp
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index dec7a5ff0845d..fcdc059fc4fd5 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -73,7 +73,7 @@ LLVM_ABI void initializeBreakFalseDepsLegacyPass(PassRegistry &);
 LLVM_ABI void initializeCanonicalizeFreezeInLoopsPass(PassRegistry &);
 LLVM_ABI void initializeCFGSimplifyPassPass(PassRegistry &);
 LLVM_ABI void initializeCFGuardPass(PassRegistry &);
-LLVM_ABI void initializeCFGuardLongjmpPass(PassRegistry &);
+LLVM_ABI void initializeCFGuardLongjmpLegacyPass(PassRegistry &);
 LLVM_ABI void initializeCFIFixupLegacyPass(PassRegistry &);
 LLVM_ABI void initializeCFIInstrInserterLegacyPass(PassRegistry &);
 LLVM_ABI void initializeCallGraphDOTPrinterPass(PassRegistry &);
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index 1bdfd72c9d736..fdc5b4830e0be 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -69,6 +69,7 @@ MACHINE_FUNCTION_PASS("block-placement-stats", MachineBlockPlacementStatsPass())
 MACHINE_FUNCTION_PASS("branch-relaxation", BranchRelaxationPass())
 MACHINE_FUNCTION_PASS("break-false-deps", BreakFalseDepsPass())
 MACHINE_FUNCTION_PASS("cfi-fixup", CFIFixupPass())
+MACHINE_FUNCTION_PASS("cfguard-longjmp", CFGuardLongjmpPass())
 MACHINE_FUNCTION_PASS("cfi-instr-inserter", CFIInstrInserterPass())
 MACHINE_FUNCTION_PASS("dead-mi-elimination", DeadMachineInstructionElimPass())
 MACHINE_FUNCTION_PASS("detect-dead-lanes", DetectDeadLanesPass())
@@ -246,7 +247,6 @@ DUMMY_MACHINE_MODULE_PASS("pseudo-probe-inserter", PseudoProbeInserterPass)
 #endif
 DUMMY_MACHINE_FUNCTION_PASS("bbsections-prepare", BasicBlockSectionsPass)
 DUMMY_MACHINE_FUNCTION_PASS("bbsections-profile-reader", BasicBlockSectionsProfileReaderPass)
-DUMMY_MACHINE_FUNCTION_PASS("cfguard-longjmp", CFGuardLongjmpPass)
 DUMMY_MACHINE_FUNCTION_PASS("fs-profile-loader", MIRProfileLoaderNewPass)
 DUMMY_MACHINE_FUNCTION_PASS("lrshrink", LiveRangeShrinkPass)
 DUMMY_MACHINE_FUNCTION_PASS("machine-function-splitter", MachineFunctionSplitterPass)
diff --git a/llvm/lib/CodeGen/CFGuardLongjmp.cpp b/llvm/lib/CodeGen/CFGuardLongjmp.cpp
index 76dd274b81857..93f2651ba3046 100644
--- a/llvm/lib/CodeGen/CFGuardLongjmp.cpp
+++ b/llvm/lib/CodeGen/CFGuardLongjmp.cpp
@@ -14,6 +14,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "llvm/CodeGen/CFGuardLongjmp.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
@@ -31,34 +32,7 @@ using namespace llvm;
 STATISTIC(CFGuardLongjmpTargets,
           "Number of Control Flow Guard longjmp targets");
 
-namespace {
-
-/// MachineFunction pass to insert a symbol after each call to _setjmp and store
-/// this in the MachineFunction's LongjmpTargets vector.
-class CFGuardLongjmp : public MachineFunctionPass {
-public:
-  static char ID;
-
-  CFGuardLongjmp() : MachineFunctionPass(ID) {}
-
-  StringRef getPassName() const override {
-    return "Control Flow Guard longjmp targets";
-  }
-
-  bool runOnMachineFunction(MachineFunction &MF) override;
-};
-
-} // end anonymous namespace
-
-char CFGuardLongjmp::ID = 0;
-
-INITIALIZE_PASS(CFGuardLongjmp, "CFGuardLongjmp",
-                "Insert symbols at valid longjmp targets for /guard:cf", false,
-                false)
-FunctionPass *llvm::createCFGuardLongjmpPass() { return new CFGuardLongjmp(); }
-
-bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) {
-
+static bool runCFGuardLongjmp(MachineFunction &MF) {
   // Skip modules for which the cfguard flag is not set.
   if (MF.getFunction().getParent()->getControlFlowGuardMode() ==
       ControlFlowGuardMode::Disabled)
@@ -118,3 +92,47 @@ bool CFGuardLongjmp::runOnMachineFunction(MachineFunction &MF) {
 
   return true;
 }
+
+namespace {
+
+/// MachineFunction pass to insert a symbol after each call to _setjmp and store
+/// this in the MachineFunction's LongjmpTargets vector.
+class CFGuardLongjmpLegacy : public MachineFunctionPass {
+public:
+  static char ID;
+
+  CFGuardLongjmpLegacy() : MachineFunctionPass(ID) {}
+
+  StringRef getPassName() const override {
+    return "Control Flow Guard longjmp targets";
+  }
+
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
+  bool runOnMachineFunction(MachineFunction &MF) override {
+    return runCFGuardLongjmp(MF);
+  }
+};
+
+} // end anonymous namespace
+
+char CFGuardLongjmpLegacy::ID = 0;
+
+INITIALIZE_PASS(CFGuardLongjmpLegacy, "CFGuardLongjmp",
+                "Insert symbols at valid longjmp targets for /guard:cf", false,
+                false)
+FunctionPass *llvm::createCFGuardLongjmpLegacy() {
+  return new CFGuardLongjmpLegacy();
+}
+
+PreservedAnalyses
+CFGuardLongjmpPass::run(MachineFunction &MF,
+                        MachineFunctionAnalysisManager &MFAM) {
+  if (!runCFGuardLongjmp(MF))
+    return PreservedAnalyses::all();
+
+  return getMachineFunctionPassPreservedAnalyses().preserveSet<CFGAnalyses>();
+}
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 7fb2fca6b6494..af973f39fee2d 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -27,7 +27,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeBranchFolderLegacyPass(Registry);
   initializeBranchRelaxationLegacyPass(Registry);
   initializeBreakFalseDepsLegacyPass(Registry);
-  initializeCFGuardLongjmpPass(Registry);
+  initializeCFGuardLongjmpLegacyPass(Registry);
   initializeCFIFixupLegacyPass(Registry);
   initializeCFIInstrInserterLegacyPass(Registry);
   initializeCheckDebugMachineModuleLegacyPass(Registry);
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 545b2905bdaaa..8f4bd4e39e0a2 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -87,6 +87,7 @@
 #include "llvm/CodeGen/BranchFoldingPass.h"
 #include "llvm/CodeGen/BranchRelaxation.h"
 #include "llvm/CodeGen/BreakFalseDeps.h"
+#include "llvm/CodeGen/CFGuardLongjmp.h"
 #include "llvm/CodeGen/CFIFixup.h"
 #include "llvm/CodeGen/CFIInstrInserter.h"
 #include "llvm/CodeGen/CodeGenPrepare.h"
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index bad3ce59bd4a1..ea90a8a4e7b4d 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -928,7 +928,7 @@ void AArch64PassConfig::addPreEmitPass() {
 
   if (TM->getTargetTriple().isOSWindows()) {
     // Identify valid longjmp targets for Windows Control Flow Guard.
-    addPass(createCFGuardLongjmpPass());
+    addPass(createCFGuardLongjmpLegacy());
     // Identify valid eh continuation targets for Windows EHCont Guard.
     addPass(createEHContGuardTargetsLegacy());
   }
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index 3c32b73a82ed7..123380041c08b 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -616,7 +616,7 @@ void ARMPassConfig::addPreEmitPass2() {
 
   if (TM->getTargetTriple().isOSWindows()) {
     // Identify valid longjmp targets for Windows Control Flow Guard.
-    addPass(createCFGuardLongjmpPass());
+    addPass(createCFGuardLongjmpLegacy());
     // Identify valid eh continuation targets for Windows EHCont Guard.
     addPass(createEHContGuardTargetsLegacy());
   }
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index c05bd2ca7f3be..38b5b1482a68b 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -16,6 +16,7 @@
 
 #include "llvm/CodeGen/AtomicExpand.h"
 #include "llvm/CodeGen/BreakFalseDeps.h"
+#include "llvm/CodeGen/CFGuardLongjmp.h"
 #include "llvm/CodeGen/CFIInstrInserter.h"
 #include "llvm/CodeGen/EHContGuardTargets.h"
 #include "llvm/CodeGen/EarlyIfConversion.h"
@@ -237,8 +238,7 @@ void X86CodeGenPassBuilder::addPreEmitPass2(PassManagerWrapper &PMW) {
 
   if (TT.isOSWindows()) {
     // Identify valid longjmp targets for Windows Control Flow Guard.
-    // TODO(boomanaiden154): Add CFGuardLongjmpPass here when it has been
-    // ported.
+    addMachineFunctionPass(CFGuardLongjmpPass(), PMW);
     // Identify valid eh continuation targets for Windows EHCont Guard.
     addMachineFunctionPass(EHContGuardTargetsPass(), PMW);
   }
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index 886405a0c7bae..71d21ce4304e4 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -607,7 +607,7 @@ void X86PassConfig::addPreEmitPass2() {
 
   if (TT.isOSWindows()) {
     // Identify valid longjmp targets for Windows Control Flow Guard.
-    addPass(createCFGuardLongjmpPass());
+    addPass(createCFGuardLongjmpLegacy());
     // Identify valid eh continuation targets for Windows EHCont Guard.
     addPass(createEHContGuardTargetsLegacy());
   }
diff --git a/llvm/test/CodeGen/X86/cfguard-longjmp.ll b/llvm/test/CodeGen/X86/cfguard-longjmp.ll
new file mode 100644
index 0000000000000..25df8314cf9b2
--- /dev/null
+++ b/llvm/test/CodeGen/X86/cfguard-longjmp.ll
@@ -0,0 +1,44 @@
+; RUN: llc < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s
+; RUN: llc -enable-new-pm < %s -mtriple=x86_64-pc-windows-msvc | FileCheck %s
+; Control Flow Guard is currently only available on Windows
+
+; Test that longjmp targets have public labels and are included in the .gljmp section.
+%struct._SETJMP_FLOAT128 = type { [2 x i64] }
+ at buf1 = internal global [16 x %struct._SETJMP_FLOAT128] zeroinitializer, align 16
+
+define i32 @func_cf_setjmp() {
+  %1 = alloca i32, align 4
+  %2 = alloca i32, align 4
+  store i32 0, ptr %1, align 4
+  store i32 -1, ptr %2, align 4
+  %3 = call ptr @llvm.frameaddress(i32 0)
+  %4 = call i32 @_setjmp(ptr @buf1, ptr %3) #0
+
+  ; CHECK-LABEL: func_cf_setjmp
+  ; CHECK:       callq _setjmp
+  ; CHECK-NEXT:  $cfgsj_func_cf_setjmp0:
+
+  %5 = call ptr @llvm.frameaddress(i32 0)
+  %6 = call i32 @_setjmp(ptr @buf1, ptr %5) #0
+
+  ; CHECK:       callq _setjmp
+  ; CHECK-NEXT:  $cfgsj_func_cf_setjmp1:
+
+  store i32 1, ptr %2, align 4
+  %7 = load i32, ptr %2, align 4
+  ret i32 %7
+
+  ; CHECK:       .section .gljmp$y,"dr"
+  ; CHECK-NEXT:  .symidx $cfgsj_func_cf_setjmp0
+  ; CHECK-NEXT:  .symidx $cfgsj_func_cf_setjmp1
+}
+
+declare ptr @llvm.frameaddress(i32)
+
+; Function Attrs: returns_twice
+declare dso_local i32 @_setjmp(ptr, ptr) #0
+
+attributes #0 = { returns_twice }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 2, !"cfguard", i32 2}
diff --git a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
index 52363d9844c00..b3796b11f5c82 100644
--- a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
+++ b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
@@ -275,6 +275,7 @@
 ; O0-WINDOWS-NEXT:     x86-seses
 ; O0-WINDOWS-NEXT:     x86-return-thunks
 ; O0-WINDOWS-NEXT:     x86-avoid-trailing-call
+; O0-WINDOWS-NEXT:     cfguard-longjmp
 ; O0-WINDOWS-NEXT:     eh-cont-guard-targets
 ; O0-WINDOWS-NEXT:     x86-lvi-ret
 ; O0-WINDOWS-NEXT:     x86-wineh-unwindv2
@@ -405,6 +406,7 @@
 ; O3-WINDOWS-NEXT:     x86-seses
 ; O3-WINDOWS-NEXT:     x86-return-thunks
 ; O3-WINDOWS-NEXT:     x86-avoid-trailing-call
+; O3-WINDOWS-NEXT:     cfguard-longjmp
 ; O3-WINDOWS-NEXT:     eh-cont-guard-targets
 ; O3-WINDOWS-NEXT:     x86-lvi-ret
 ; O3-WINDOWS-NEXT:     x86-wineh-unwindv2



More information about the llvm-commits mailing list