From 97d50c149070d104e301159b825657af60613fa4 Mon Sep 17 00:00:00 2001 From: Anshul Nigham Date: Mon, 6 Apr 2026 14:01:37 -0700 Subject: [PATCH] [NewPM] Adds a port for AArch64PreLegalizerCombiner (#190567) Standard porting (note that TargetPassConfig dependency was [removed earlier](https://github.com/llvm/llvm-project/commit/e27e7e433974b24c90fed9f0b646bed84e47681e)). --------- Co-authored-by: Matt Arsenault --- llvm/lib/Target/AArch64/AArch64.h | 16 ++- .../Target/AArch64/AArch64PassRegistry.def | 2 + .../Target/AArch64/AArch64TargetMachine.cpp | 2 +- .../GISel/AArch64PreLegalizerCombiner.cpp | 122 +++++++++++++----- .../combine-2-icmps-of-0-and-or.mir | 1 + 5 files changed, 111 insertions(+), 32 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h index 6c3990842efb..8a7c8680da63 100644 --- a/llvm/lib/Target/AArch64/AArch64.h +++ b/llvm/lib/Target/AArch64/AArch64.h @@ -24,6 +24,7 @@ #include struct AArch64O0PreLegalizerCombinerImplRuleConfig; +struct AArch64PreLegalizerCombinerImplRuleConfig; namespace llvm { @@ -87,6 +88,19 @@ public: MachineFunctionAnalysisManager &MFAM); }; +class AArch64PreLegalizerCombinerPass + : public PassInfoMixin { + std::unique_ptr RuleConfig; + +public: + AArch64PreLegalizerCombinerPass(); + AArch64PreLegalizerCombinerPass(AArch64PreLegalizerCombinerPass &&); + ~AArch64PreLegalizerCombinerPass(); + + PreservedAnalyses run(MachineFunction &MF, + MachineFunctionAnalysisManager &MFAM); +}; + FunctionPass *createAArch64O0PreLegalizerCombiner(); FunctionPass *createAArch64PreLegalizerCombiner(); FunctionPass *createAArch64PostLegalizerCombiner(bool IsOptNone); @@ -119,7 +133,7 @@ void initializeAArch64PostCoalescerLegacyPass(PassRegistry &); void initializeAArch64PostLegalizerCombinerPass(PassRegistry &); void initializeAArch64PostLegalizerLoweringPass(PassRegistry &); void initializeAArch64PostSelectOptimizePass(PassRegistry &); -void initializeAArch64PreLegalizerCombinerPass(PassRegistry &); +void initializeAArch64PreLegalizerCombinerLegacyPass(PassRegistry &); void initializeAArch64PromoteConstantPass(PassRegistry&); void initializeAArch64RedundantCopyEliminationPass(PassRegistry&); void initializeAArch64RedundantCondBranchPass(PassRegistry &); diff --git a/llvm/lib/Target/AArch64/AArch64PassRegistry.def b/llvm/lib/Target/AArch64/AArch64PassRegistry.def index c5248f20b6f7..39085fc033c1 100644 --- a/llvm/lib/Target/AArch64/AArch64PassRegistry.def +++ b/llvm/lib/Target/AArch64/AArch64PassRegistry.def @@ -36,6 +36,8 @@ MACHINE_FUNCTION_PASS("aarch64-jump-tables", AArch64CompressJumpTablesPass()) MACHINE_FUNCTION_PASS("aarch64-ldst-opt", AArch64LoadStoreOptPass()) MACHINE_FUNCTION_PASS("aarch64-mi-peephole-opt", AArch64MIPeepholeOptPass()) MACHINE_FUNCTION_PASS("aarch64-post-coalescer", AArch64PostCoalescerPass()) +MACHINE_FUNCTION_PASS("aarch64-prelegalizer-combiner", + AArch64PreLegalizerCombinerPass()) MACHINE_FUNCTION_PASS("aarch64-ptrauth", AArch64PointerAuthPass()) MACHINE_FUNCTION_PASS("aarch64-simd-scalar", AArch64AdvSIMDScalarPass()) MACHINE_FUNCTION_PASS("aarch64-O0-prelegalizer-combiner", diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp index 94fbe709d6fe..950d274ceae7 100644 --- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp +++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp @@ -258,7 +258,7 @@ LLVMInitializeAArch64Target() { initializeAArch64MIPeepholeOptLegacyPass(PR); initializeAArch64SIMDInstrOptPass(PR); initializeAArch64O0PreLegalizerCombinerLegacyPass(PR); - initializeAArch64PreLegalizerCombinerPass(PR); + initializeAArch64PreLegalizerCombinerLegacyPass(PR); initializeAArch64PointerAuthLegacyPass(PR); initializeAArch64PostCoalescerLegacyPass(PR); initializeAArch64PostLegalizerCombinerPass(PR); diff --git a/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp b/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp index cd35a27ea9e9..42e0ab6537a8 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64PreLegalizerCombiner.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "AArch64.h" #include "AArch64GlobalISelUtils.h" #include "AArch64TargetMachine.h" #include "llvm/CodeGen/GlobalISel/CSEInfo.h" @@ -22,11 +23,15 @@ #include "llvm/CodeGen/GlobalISel/MIPatternMatch.h" #include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h" #include "llvm/CodeGen/GlobalISel/Utils.h" +#include "llvm/CodeGen/LibcallLoweringInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineFunctionAnalysisManager.h" #include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/MachinePassManager.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/IR/Instructions.h" +#include #define GET_GICOMBINER_DEPS #include "AArch64GenPreLegalizeGICombiner.inc" @@ -37,12 +42,12 @@ using namespace llvm; using namespace MIPatternMatch; -namespace { - #define GET_GICOMBINER_TYPES #include "AArch64GenPreLegalizeGICombiner.inc" #undef GET_GICOMBINER_TYPES +namespace { + /// Try to match a G_ICMP of a G_TRUNC with zero, in which the truncated bits /// are sign bits. In this case, we can transform the G_ICMP to directly compare /// the wide value with a zero. @@ -800,14 +805,38 @@ bool AArch64PreLegalizerCombinerImpl::tryCombineAll(MachineInstr &MI) const { return false; } +bool runCombiner(MachineFunction &MF, GISelCSEInfo *CSEInfo, + GISelValueTracking *VT, MachineDominatorTree *MDT, + const LibcallLoweringInfo &Libcalls, + const AArch64PreLegalizerCombinerImplRuleConfig &RuleConfig, + bool EnableOpt) { + const AArch64Subtarget &ST = MF.getSubtarget(); + const auto *LI = ST.getLegalizerInfo(); + + const Function &F = MF.getFunction(); + + CombinerInfo CInfo(/*AllowIllegalOps=*/true, /*ShouldLegalizeIllegal=*/false, + /*LegalizerInfo=*/nullptr, EnableOpt, F.hasOptSize(), + F.hasMinSize()); + // Disable fixed-point iteration to reduce compile-time + CInfo.MaxIterations = 1; + CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass; + // This is the first Combiner, so the input IR might contain dead + // instructions. + CInfo.EnableFullDCE = true; + AArch64PreLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST, + Libcalls, MDT, LI); + return Impl.combineMachineInstrs(); +} + // Pass boilerplate // ================ -class AArch64PreLegalizerCombiner : public MachineFunctionPass { +class AArch64PreLegalizerCombinerLegacy : public MachineFunctionPass { public: static char ID; - AArch64PreLegalizerCombiner(); + AArch64PreLegalizerCombinerLegacy(); StringRef getPassName() const override { return "AArch64PreLegalizerCombiner"; @@ -822,7 +851,8 @@ private: }; } // end anonymous namespace -void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { +void AArch64PreLegalizerCombinerLegacy::getAnalysisUsage( + AnalysisUsage &AU) const { AU.setPreservesCFG(); getSelectionDAGFallbackAnalysisUsage(AU); AU.addRequired(); @@ -835,13 +865,14 @@ void AArch64PreLegalizerCombiner::getAnalysisUsage(AnalysisUsage &AU) const { MachineFunctionPass::getAnalysisUsage(AU); } -AArch64PreLegalizerCombiner::AArch64PreLegalizerCombiner() +AArch64PreLegalizerCombinerLegacy::AArch64PreLegalizerCombinerLegacy() : MachineFunctionPass(ID) { if (!RuleConfig.parseCommandLineOption()) report_fatal_error("Invalid rule identifier"); } -bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { +bool AArch64PreLegalizerCombinerLegacy::runOnMachineFunction( + MachineFunction &MF) { if (MF.getProperties().hasFailedISel()) return false; // Enable CSE. @@ -851,47 +882,78 @@ bool AArch64PreLegalizerCombiner::runOnMachineFunction(MachineFunction &MF) { &Wrapper.get(getStandardCSEConfigForOpt(MF.getTarget().getOptLevel())); const AArch64Subtarget &ST = MF.getSubtarget(); - const auto *LI = ST.getLegalizerInfo(); - - const Function &F = MF.getFunction(); - const LibcallLoweringInfo &Libcalls = getAnalysis().getLibcallLowering( - *F.getParent(), ST); + *MF.getFunction().getParent(), ST); - bool EnableOpt = - MF.getTarget().getOptLevel() != CodeGenOptLevel::None && !skipFunction(F); GISelValueTracking *VT = &getAnalysis().get(MF); MachineDominatorTree *MDT = &getAnalysis().getDomTree(); - CombinerInfo CInfo(/*AllowIllegalOps*/ true, /*ShouldLegalizeIllegal*/ false, - /*LegalizerInfo*/ nullptr, EnableOpt, F.hasOptSize(), - F.hasMinSize()); - // Disable fixed-point iteration to reduce compile-time - CInfo.MaxIterations = 1; - CInfo.ObserverLvl = CombinerInfo::ObserverLevel::SinglePass; - // This is the first Combiner, so the input IR might contain dead - // instructions. - CInfo.EnableFullDCE = true; - AArch64PreLegalizerCombinerImpl Impl(MF, CInfo, *VT, CSEInfo, RuleConfig, ST, - Libcalls, MDT, LI); - return Impl.combineMachineInstrs(); + bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None && + !skipFunction(MF.getFunction()); + return runCombiner(MF, CSEInfo, VT, MDT, Libcalls, RuleConfig, EnableOpt); } -char AArch64PreLegalizerCombiner::ID = 0; -INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombiner, DEBUG_TYPE, +char AArch64PreLegalizerCombinerLegacy::ID = 0; +INITIALIZE_PASS_BEGIN(AArch64PreLegalizerCombinerLegacy, DEBUG_TYPE, "Combine AArch64 machine instrs before legalization", false, false) INITIALIZE_PASS_DEPENDENCY(GISelValueTrackingAnalysisLegacy) INITIALIZE_PASS_DEPENDENCY(GISelCSEAnalysisWrapperPass) INITIALIZE_PASS_DEPENDENCY(LibcallLoweringInfoWrapper) -INITIALIZE_PASS_END(AArch64PreLegalizerCombiner, DEBUG_TYPE, +INITIALIZE_PASS_END(AArch64PreLegalizerCombinerLegacy, DEBUG_TYPE, "Combine AArch64 machine instrs before legalization", false, false) +AArch64PreLegalizerCombinerPass::AArch64PreLegalizerCombinerPass() + : RuleConfig( + std::make_unique()) { + if (!RuleConfig->parseCommandLineOption()) + reportFatalUsageError("invalid rule identifier"); +} + +AArch64PreLegalizerCombinerPass::AArch64PreLegalizerCombinerPass( + AArch64PreLegalizerCombinerPass &&) = default; + +AArch64PreLegalizerCombinerPass::~AArch64PreLegalizerCombinerPass() = default; + +PreservedAnalyses +AArch64PreLegalizerCombinerPass::run(MachineFunction &MF, + MachineFunctionAnalysisManager &MFAM) { + if (MF.getProperties().hasFailedISel()) + return PreservedAnalyses::all(); + + auto *CSEInfo = MFAM.getResult(MF).get(); + GISelValueTracking &VT = MFAM.getResult(MF); + MachineDominatorTree &MDT = MFAM.getResult(MF); + + const AArch64Subtarget &ST = MF.getSubtarget(); + auto &MAMProxy = + MFAM.getResult(MF); + const LibcallLoweringModuleAnalysisResult *LibcallResult = + MAMProxy.getCachedResult( + *MF.getFunction().getParent()); + if (!LibcallResult) + reportFatalUsageError("LibcallLoweringModuleAnalysis result not available"); + + const LibcallLoweringInfo &Libcalls = LibcallResult->getLibcallLowering(ST); + + bool EnableOpt = MF.getTarget().getOptLevel() != CodeGenOptLevel::None; + + if (!runCombiner(MF, CSEInfo, &VT, &MDT, Libcalls, *RuleConfig, EnableOpt)) + return PreservedAnalyses::all(); + + PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses(); + PA.preserveSet(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + return PA; +} + namespace llvm { FunctionPass *createAArch64PreLegalizerCombiner() { - return new AArch64PreLegalizerCombiner(); + return new AArch64PreLegalizerCombinerLegacy(); } } // end namespace llvm diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-2-icmps-of-0-and-or.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-2-icmps-of-0-and-or.mir index 2ce5c693f3db..0d1831c8043d 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/combine-2-icmps-of-0-and-or.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-2-icmps-of-0-and-or.mir @@ -1,5 +1,6 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py # RUN: llc -mtriple aarch64 -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs %s -o - | FileCheck %s +# RUN: llc -mtriple aarch64 -passes='require,function(machine-function(aarch64-prelegalizer-combiner))' %s -o - | FileCheck %s # REQUIRES: asserts