[llvm] [NewPM] Port EHContGuardTargets to the new pass manager (PR #217843)

Bill Wendling via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 21 16:51:25 PDT 2026


https://github.com/isanbard updated https://github.com/llvm/llvm-project/pull/217843

>From f40f3176229795048b46f4949211cc91ee15c6af Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Thu, 20 Aug 2026 18:52:12 -0700
Subject: [PATCH 1/2] [NewPM] Port EHContGuardTargets to the new pass manager

Adds a newPM pass for EHContGuardTargets (eh-cont-guard-targets).

- Extracts the pass's logic (which has no per-instance state) into a
  shared runEHContGuardTargets free function, called by both the
  legacy pass and the new pass manager pass.
- Renames the old pass with the "Legacy" suffix, and (matching the
  same convention already applied to CFIInstrInserter) renames
  createEHContGuardTargetsPass() to createEHContGuardTargetsLegacy()
  at all three legacy call sites (X86, AArch64, ARM).
- Adds the new pass manager pass EHContGuardTargetsPass, using
  RequiredPassInfoMixin: the legacy pass's runOnMachineFunction never
  calls skipFunction, so it always runs unconditionally and should not
  be skippable in the new PM either.
- Updates MachinePassRegistry.def and PassBuilder.
- Wires the pass into X86's newPM pipeline, replacing an existing TODO
  inside the already-correct TT.isOSWindows() conditional in
  X86CodeGenPassBuilder.cpp. AArch64 and ARM have no newPM
  CodeGenPassBuilder yet (legacy-only), so no wiring was needed there.
- Adds a -enable-new-pm RUN line to ehcontguard.ll (X86 only, the only
  target with newPM support), since no dedicated unit test existed to
  extend, and updates llc-pipeline-npm.ll's O0-WINDOWS/O3-WINDOWS
  pipeline-dump expectations (verified empirically where the pass
  lands in the dump).

Assisted-by: Claude Sonnet 5
---
 .../include/llvm/CodeGen/EHContGuardTargets.h | 25 +++++++
 llvm/include/llvm/CodeGen/Passes.h            |  2 +-
 llvm/include/llvm/InitializePasses.h          |  2 +-
 .../llvm/Passes/MachinePassRegistry.def       |  2 +-
 llvm/lib/CodeGen/CodeGen.cpp                  |  2 +-
 llvm/lib/CodeGen/EHContGuardTargets.cpp       | 65 +++++++++++--------
 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/ehcontguard.ll          |  1 +
 llvm/test/CodeGen/X86/llc-pipeline-npm.ll     |  2 +
 13 files changed, 76 insertions(+), 36 deletions(-)
 create mode 100644 llvm/include/llvm/CodeGen/EHContGuardTargets.h

diff --git a/llvm/include/llvm/CodeGen/EHContGuardTargets.h b/llvm/include/llvm/CodeGen/EHContGuardTargets.h
new file mode 100644
index 0000000000000..052183d39226a
--- /dev/null
+++ b/llvm/include/llvm/CodeGen/EHContGuardTargets.h
@@ -0,0 +1,25 @@
+//===----------------------------------------------------------------------===//
+//
+// 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_EHCONTGUARDTARGETS_H
+#define LLVM_CODEGEN_EHCONTGUARDTARGETS_H
+
+#include "llvm/CodeGen/MachinePassManager.h"
+
+namespace llvm {
+
+class EHContGuardTargetsPass
+    : public RequiredPassInfoMixin<EHContGuardTargetsPass> {
+public:
+  LLVM_ABI PreservedAnalyses run(MachineFunction &MF,
+                                 MachineFunctionAnalysisManager &MFAM);
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_EHCONTGUARDTARGETS_H
diff --git a/llvm/include/llvm/CodeGen/Passes.h b/llvm/include/llvm/CodeGen/Passes.h
index 0009373a68c78..8c2b923aeb807 100644
--- a/llvm/include/llvm/CodeGen/Passes.h
+++ b/llvm/include/llvm/CodeGen/Passes.h
@@ -580,7 +580,7 @@ LLVM_ABI FunctionPass *createCFGuardLongjmpPass();
 
 /// Creates Windows EH Continuation Guard target identification pass.
 /// \see EHContGuardTargets.cpp
-LLVM_ABI FunctionPass *createEHContGuardTargetsPass();
+LLVM_ABI FunctionPass *createEHContGuardTargetsLegacy();
 
 /// Create Hardware Loop pass. \see HardwareLoops.cpp
 LLVM_ABI FunctionPass *createHardwareLoopsLegacyPass();
diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h
index 921f1586049d8..3c05a2bd8472d 100644
--- a/llvm/include/llvm/InitializePasses.h
+++ b/llvm/include/llvm/InitializePasses.h
@@ -111,7 +111,7 @@ LLVM_ABI void initializeEarlyIfPredicatorPass(PassRegistry &);
 LLVM_ABI void initializeEarlyMachineLICMPass(PassRegistry &);
 LLVM_ABI void initializeEarlyTailDuplicateLegacyPass(PassRegistry &);
 LLVM_ABI void initializeEdgeBundlesWrapperLegacyPass(PassRegistry &);
-LLVM_ABI void initializeEHContGuardTargetsPass(PassRegistry &);
+LLVM_ABI void initializeEHContGuardTargetsLegacyPass(PassRegistry &);
 LLVM_ABI void initializeExpandIRInstsLegacyPassPass(PassRegistry &);
 LLVM_ABI void initializeExpandPostRALegacyPass(PassRegistry &);
 LLVM_ABI void initializeExpandReductionsPass(PassRegistry &);
diff --git a/llvm/include/llvm/Passes/MachinePassRegistry.def b/llvm/include/llvm/Passes/MachinePassRegistry.def
index de0ba23ad2818..d82b525b4a3af 100644
--- a/llvm/include/llvm/Passes/MachinePassRegistry.def
+++ b/llvm/include/llvm/Passes/MachinePassRegistry.def
@@ -76,6 +76,7 @@ MACHINE_FUNCTION_PASS("dot-machine-cfg", MachineCFGPrinterPass())
 MACHINE_FUNCTION_PASS("early-ifcvt", EarlyIfConverterPass())
 MACHINE_FUNCTION_PASS("early-machinelicm", EarlyMachineLICMPass())
 MACHINE_FUNCTION_PASS("early-tailduplication", EarlyTailDuplicatePass())
+MACHINE_FUNCTION_PASS("eh-cont-guard-targets", EHContGuardTargetsPass())
 MACHINE_FUNCTION_PASS("fentry-insert", FEntryInserterPass())
 MACHINE_FUNCTION_PASS("finalize-isel", FinalizeISelPass())
 MACHINE_FUNCTION_PASS("finalizebundle-test", FinalizeBundleTestPass())
@@ -245,7 +246,6 @@ DUMMY_MACHINE_MODULE_PASS("pseudo-probe-inserter", PseudoProbeInserterPass)
 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("eh-cont-guard-targets", EHContGuardTargetsPass)
 DUMMY_MACHINE_FUNCTION_PASS("fs-profile-loader", MIRProfileLoaderNewPass)
 DUMMY_MACHINE_FUNCTION_PASS("instruction-select", InstructionSelectPass)
 DUMMY_MACHINE_FUNCTION_PASS("lrshrink", LiveRangeShrinkPass)
diff --git a/llvm/lib/CodeGen/CodeGen.cpp b/llvm/lib/CodeGen/CodeGen.cpp
index 6be46b0f6cef1..7fb2fca6b6494 100644
--- a/llvm/lib/CodeGen/CodeGen.cpp
+++ b/llvm/lib/CodeGen/CodeGen.cpp
@@ -38,7 +38,7 @@ void llvm::initializeCodeGen(PassRegistry &Registry) {
   initializeDetectDeadLanesLegacyPass(Registry);
   initializeDummyCGSCCPassPass(Registry);
   initializeDwarfEHPrepareLegacyPassPass(Registry);
-  initializeEHContGuardTargetsPass(Registry);
+  initializeEHContGuardTargetsLegacyPass(Registry);
   initializeEarlyIfConverterLegacyPass(Registry);
   initializeEarlyIfPredicatorPass(Registry);
   initializeEarlyMachineLICMPass(Registry);
diff --git a/llvm/lib/CodeGen/EHContGuardTargets.cpp b/llvm/lib/CodeGen/EHContGuardTargets.cpp
index 9ad3f671798c9..daf82ef2e26be 100644
--- a/llvm/lib/CodeGen/EHContGuardTargets.cpp
+++ b/llvm/lib/CodeGen/EHContGuardTargets.cpp
@@ -15,6 +15,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "llvm/CodeGen/EHContGuardTargets.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
@@ -29,53 +30,63 @@ using namespace llvm;
 
 STATISTIC(EHContGuardTargetsFound, "Number of EHCont Guard targets");
 
+static bool runEHContGuardTargets(MachineFunction &MF) {
+  // Skip modules for which the ehcontguard flag is not set.
+  if (!MF.getFunction().getParent()->getModuleFlag("ehcontguard"))
+    return false;
+
+  // Skip functions that do not have targets
+  if (!MF.hasEHContTarget())
+    return false;
+
+  bool Result = false;
+
+  for (MachineBasicBlock &MBB : MF) {
+    if (MBB.isEHContTarget()) {
+      MF.addEHContTarget(MBB.getEHContSymbol());
+      EHContGuardTargetsFound++;
+      Result = true;
+    }
+  }
+
+  return Result;
+}
+
 namespace {
 
 /// MachineFunction pass to insert a symbol before each valid catchret target
 /// and store these in the MachineFunction's CatchRetTargets vector.
-class EHContGuardTargets : public MachineFunctionPass {
+class EHContGuardTargetsLegacy : public MachineFunctionPass {
 public:
   static char ID;
 
-  EHContGuardTargets() : MachineFunctionPass(ID) {}
+  EHContGuardTargetsLegacy() : MachineFunctionPass(ID) {}
 
   StringRef getPassName() const override {
     return "EH Cont Guard catchret targets";
   }
 
-  bool runOnMachineFunction(MachineFunction &MF) override;
+  bool runOnMachineFunction(MachineFunction &MF) override {
+    return runEHContGuardTargets(MF);
+  }
 };
 
 } // end anonymous namespace
 
-char EHContGuardTargets::ID = 0;
+char EHContGuardTargetsLegacy::ID = 0;
 
-INITIALIZE_PASS(EHContGuardTargets, "EHContGuardTargets",
+INITIALIZE_PASS(EHContGuardTargetsLegacy, "EHContGuardTargets",
                 "Insert symbols at valid targets for /guard:ehcont", false,
                 false)
-FunctionPass *llvm::createEHContGuardTargetsPass() {
-  return new EHContGuardTargets();
+FunctionPass *llvm::createEHContGuardTargetsLegacy() {
+  return new EHContGuardTargetsLegacy();
 }
 
-bool EHContGuardTargets::runOnMachineFunction(MachineFunction &MF) {
-
-  // Skip modules for which the ehcontguard flag is not set.
-  if (!MF.getFunction().getParent()->getModuleFlag("ehcontguard"))
-    return false;
-
-  // Skip functions that do not have targets
-  if (!MF.hasEHContTarget())
-    return false;
-
-  bool Result = false;
-
-  for (MachineBasicBlock &MBB : MF) {
-    if (MBB.isEHContTarget()) {
-      MF.addEHContTarget(MBB.getEHContSymbol());
-      EHContGuardTargetsFound++;
-      Result = true;
-    }
-  }
+PreservedAnalyses
+EHContGuardTargetsPass::run(MachineFunction &MF,
+                            MachineFunctionAnalysisManager &MFAM) {
+  if (!runEHContGuardTargets(MF))
+    return PreservedAnalyses::all();
 
-  return Result;
+  return getMachineFunctionPassPreservedAnalyses();
 }
diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp
index 64c7c1237456a..27df98c0d892d 100644
--- a/llvm/lib/Passes/PassBuilder.cpp
+++ b/llvm/lib/Passes/PassBuilder.cpp
@@ -94,6 +94,7 @@
 #include "llvm/CodeGen/DeadMachineInstructionElim.h"
 #include "llvm/CodeGen/DetectDeadLanes.h"
 #include "llvm/CodeGen/DwarfEHPrepare.h"
+#include "llvm/CodeGen/EHContGuardTargets.h"
 #include "llvm/CodeGen/EarlyIfConversion.h"
 #include "llvm/CodeGen/EdgeBundles.h"
 #include "llvm/CodeGen/ExpandIRInsts.h"
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 2669647a8f56b..beec7897f5962 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -930,7 +930,7 @@ void AArch64PassConfig::addPreEmitPass() {
     // Identify valid longjmp targets for Windows Control Flow Guard.
     addPass(createCFGuardLongjmpPass());
     // Identify valid eh continuation targets for Windows EHCont Guard.
-    addPass(createEHContGuardTargetsPass());
+    addPass(createEHContGuardTargetsLegacy());
   }
 
   if (TM->getOptLevel() != CodeGenOptLevel::None && EnableCollectLOH &&
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index ea993dd33f550..dd05e38c075ea 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -618,7 +618,7 @@ void ARMPassConfig::addPreEmitPass2() {
     // Identify valid longjmp targets for Windows Control Flow Guard.
     addPass(createCFGuardLongjmpPass());
     // Identify valid eh continuation targets for Windows EHCont Guard.
-    addPass(createEHContGuardTargetsPass());
+    addPass(createEHContGuardTargetsLegacy());
   }
 }
 
diff --git a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
index ca8a324ae590b..c05bd2ca7f3be 100644
--- a/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/X86/X86CodeGenPassBuilder.cpp
@@ -17,6 +17,7 @@
 #include "llvm/CodeGen/AtomicExpand.h"
 #include "llvm/CodeGen/BreakFalseDeps.h"
 #include "llvm/CodeGen/CFIInstrInserter.h"
+#include "llvm/CodeGen/EHContGuardTargets.h"
 #include "llvm/CodeGen/EarlyIfConversion.h"
 #include "llvm/CodeGen/IndirectBrExpand.h"
 #include "llvm/CodeGen/InterleavedAccess.h"
@@ -239,8 +240,7 @@ void X86CodeGenPassBuilder::addPreEmitPass2(PassManagerWrapper &PMW) {
     // TODO(boomanaiden154): Add CFGuardLongjmpPass here when it has been
     // ported.
     // Identify valid eh continuation targets for Windows EHCont Guard.
-    // TODO(boomanaiden154): Add EHContGuardTargetsPass when it has been
-    // ported.
+    addMachineFunctionPass(EHContGuardTargetsPass(), PMW);
   }
 
   addMachineFunctionPass(X86LoadValueInjectionRetHardeningPass(), PMW);
diff --git a/llvm/lib/Target/X86/X86TargetMachine.cpp b/llvm/lib/Target/X86/X86TargetMachine.cpp
index c3f6d42c45d8a..a32a30e4bae34 100644
--- a/llvm/lib/Target/X86/X86TargetMachine.cpp
+++ b/llvm/lib/Target/X86/X86TargetMachine.cpp
@@ -609,7 +609,7 @@ void X86PassConfig::addPreEmitPass2() {
     // Identify valid longjmp targets for Windows Control Flow Guard.
     addPass(createCFGuardLongjmpPass());
     // Identify valid eh continuation targets for Windows EHCont Guard.
-    addPass(createEHContGuardTargetsPass());
+    addPass(createEHContGuardTargetsLegacy());
   }
   addPass(createX86LoadValueInjectionRetHardeningLegacyPass());
 
diff --git a/llvm/test/CodeGen/X86/ehcontguard.ll b/llvm/test/CodeGen/X86/ehcontguard.ll
index e868209babce6..6cd5d2e8935d3 100644
--- a/llvm/test/CodeGen/X86/ehcontguard.ll
+++ b/llvm/test/CodeGen/X86/ehcontguard.ll
@@ -1,4 +1,5 @@
 ; 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
 ; EHCont Guard is currently only available on Windows
 
 ; CHECK: @feat.00 = 16384
diff --git a/llvm/test/CodeGen/X86/llc-pipeline-npm.ll b/llvm/test/CodeGen/X86/llc-pipeline-npm.ll
index d0369d93d1710..52363d9844c00 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:     eh-cont-guard-targets
 ; O0-WINDOWS-NEXT:     x86-lvi-ret
 ; O0-WINDOWS-NEXT:     x86-wineh-unwindv2
 ; O0-WINDOWS-NEXT:     verify
@@ -404,6 +405,7 @@
 ; O3-WINDOWS-NEXT:     x86-seses
 ; O3-WINDOWS-NEXT:     x86-return-thunks
 ; O3-WINDOWS-NEXT:     x86-avoid-trailing-call
+; O3-WINDOWS-NEXT:     eh-cont-guard-targets
 ; O3-WINDOWS-NEXT:     x86-lvi-ret
 ; O3-WINDOWS-NEXT:     x86-wineh-unwindv2
 ; O3-WINDOWS-NEXT:     verify

>From 886562218e014d2cd4f7be0d9812d8caa41bbd05 Mon Sep 17 00:00:00 2001
From: Bill Wendling <isanbard at gmail.com>
Date: Fri, 21 Aug 2026 16:50:44 -0700
Subject: [PATCH 2/2] [NewPM] Mark EHContGuardTargets as CFG-preserving

Address review feedback on #217843: the pass only inserts symbols at
existing instructions and never modifies the CFG, so it should
preserve CFG analyses. Add the corresponding getAnalysisUsage
override for the legacy pass, matching passes like
ExpandPostRAPseudos and BreakFalseDeps.

Assisted-by: Claude Sonnet 5
---
 llvm/lib/CodeGen/EHContGuardTargets.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/CodeGen/EHContGuardTargets.cpp b/llvm/lib/CodeGen/EHContGuardTargets.cpp
index daf82ef2e26be..f4db86506c218 100644
--- a/llvm/lib/CodeGen/EHContGuardTargets.cpp
+++ b/llvm/lib/CodeGen/EHContGuardTargets.cpp
@@ -66,6 +66,11 @@ class EHContGuardTargetsLegacy : public MachineFunctionPass {
     return "EH Cont Guard catchret targets";
   }
 
+  void getAnalysisUsage(AnalysisUsage &AU) const override {
+    AU.setPreservesCFG();
+    MachineFunctionPass::getAnalysisUsage(AU);
+  }
+
   bool runOnMachineFunction(MachineFunction &MF) override {
     return runEHContGuardTargets(MF);
   }
@@ -88,5 +93,5 @@ EHContGuardTargetsPass::run(MachineFunction &MF,
   if (!runEHContGuardTargets(MF))
     return PreservedAnalyses::all();
 
-  return getMachineFunctionPassPreservedAnalyses();
+  return getMachineFunctionPassPreservedAnalyses().preserveSet<CFGAnalyses>();
 }



More information about the llvm-commits mailing list