https://github.com/nikic updated https://github.com/llvm/llvm-project/pull/159403
>From 42ef8db1b8927f3f8c28cd001962139f19343d7d Mon Sep 17 00:00:00 2001 From: Nikita Popov <npo...@redhat.com> Date: Wed, 17 Sep 2025 14:55:50 +0200 Subject: [PATCH 1/3] [DropUnnecessaryAssumes] Add pass for dropping assumes This adds a new pass for dropping assumes that are unlikely to be useful for further optimization. It works by discarding any assumes whose affected values are ephemeral (that is, only used by the assume). This pass currently runs at the start of the module optimization pipeline, that is post-inline (and post-link). Before that point, it is more likely for previously "useless" assumes to become useful again, e.g. because an additional user of the value is introduced after inlining + CSE. --- .../test/CodeGen/inline-asm-x86-flag-output.c | 2 +- .../Scalar/DropUnnecessaryAssumes.h | 28 ++++++ llvm/lib/Passes/PassBuilder.cpp | 1 + llvm/lib/Passes/PassBuilderPipelines.cpp | 4 + llvm/lib/Passes/PassRegistry.def | 1 + llvm/lib/Transforms/Scalar/CMakeLists.txt | 1 + .../Scalar/DropUnnecessaryAssumes.cpp | 59 ++++++++++++ llvm/test/Other/new-pm-defaults.ll | 1 + .../Other/new-pm-thinlto-postlink-defaults.ll | 1 + .../new-pm-thinlto-postlink-pgo-defaults.ll | 1 + ...-pm-thinlto-postlink-samplepgo-defaults.ll | 1 + .../DropUnnecessaryAssumes/basic.ll | 96 +++++++++++++++++++ .../constraint-elimination-placement.ll | 35 +------ llvm/test/Transforms/PhaseOrdering/pr45682.ll | 2 - llvm/test/Transforms/PhaseOrdering/pr45687.ll | 3 - .../pr98799-inline-simplifycfg-ub.ll | 2 - 16 files changed, 200 insertions(+), 38 deletions(-) create mode 100644 llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h create mode 100644 llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp create mode 100644 llvm/test/Transforms/DropUnnecessaryAssumes/basic.ll diff --git a/clang/test/CodeGen/inline-asm-x86-flag-output.c b/clang/test/CodeGen/inline-asm-x86-flag-output.c index 243dc3716ca13..330036512e705 100644 --- a/clang/test/CodeGen/inline-asm-x86-flag-output.c +++ b/clang/test/CodeGen/inline-asm-x86-flag-output.c @@ -389,7 +389,7 @@ int test_assume_boolean_flag(long nr, volatile long *addr) { : "=@cca"(x), "=@ccae"(y), "=m"(*(volatile long *)(addr)) : "r"(nr) : "cc"); - if (x) + if (x && y) return 0; return 1; } diff --git a/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h b/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h new file mode 100644 index 0000000000000..192139cbfd94d --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h @@ -0,0 +1,28 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Pass that drops assumes that are unlikely to be useful. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_DROPUNNECESSARYASSUMES_H +#define LLVM_TRANSFORMS_SCALAR_DROPUNNECESSARYASSUMES_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class DropUnnecessaryAssumesPass + : public PassInfoMixin<DropUnnecessaryAssumesPass> { +public: + PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_DROPUNNECESSARYASSUMES_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp index 8cf277657a54a..53319031b1aba 100644 --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -273,6 +273,7 @@ #include "llvm/Transforms/Scalar/DFAJumpThreading.h" #include "llvm/Transforms/Scalar/DeadStoreElimination.h" #include "llvm/Transforms/Scalar/DivRemPairs.h" +#include "llvm/Transforms/Scalar/DropUnnecessaryAssumes.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/FlattenCFG.h" #include "llvm/Transforms/Scalar/Float2Int.h" diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index c3f35f0f5e7fa..3b75a5a83dd9a 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -92,6 +92,7 @@ #include "llvm/Transforms/Scalar/DFAJumpThreading.h" #include "llvm/Transforms/Scalar/DeadStoreElimination.h" #include "llvm/Transforms/Scalar/DivRemPairs.h" +#include "llvm/Transforms/Scalar/DropUnnecessaryAssumes.h" #include "llvm/Transforms/Scalar/EarlyCSE.h" #include "llvm/Transforms/Scalar/Float2Int.h" #include "llvm/Transforms/Scalar/GVN.h" @@ -1498,6 +1499,9 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, invokeOptimizerEarlyEPCallbacks(MPM, Level, LTOPhase); FunctionPassManager OptimizePM; + if (!isLTOPreLink(LTOPhase)) + OptimizePM.addPass(DropUnnecessaryAssumesPass()); + // Scheduling LoopVersioningLICM when inlining is over, because after that // we may see more accurate aliasing. Reason to run this late is that too // early versioning may prevent further inlining due to increase of code diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def index 1d015971dfbdf..924aa3eb5d492 100644 --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -425,6 +425,7 @@ FUNCTION_PASS("dot-post-dom", PostDomPrinter()) FUNCTION_PASS("dot-post-dom-only", PostDomOnlyPrinter()) FUNCTION_PASS("dse", DSEPass()) FUNCTION_PASS("dwarf-eh-prepare", DwarfEHPreparePass(TM)) +FUNCTION_PASS("drop-unnecessary-assumes", DropUnnecessaryAssumesPass()) FUNCTION_PASS("expand-large-div-rem", ExpandLargeDivRemPass(TM)) FUNCTION_PASS("expand-memcmp", ExpandMemCmpPass(TM)) FUNCTION_PASS("expand-reductions", ExpandReductionsPass()) diff --git a/llvm/lib/Transforms/Scalar/CMakeLists.txt b/llvm/lib/Transforms/Scalar/CMakeLists.txt index 765059d0c3b20..37dbb34605646 100644 --- a/llvm/lib/Transforms/Scalar/CMakeLists.txt +++ b/llvm/lib/Transforms/Scalar/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_component_library(LLVMScalarOpts DeadStoreElimination.cpp DFAJumpThreading.cpp DivRemPairs.cpp + DropUnnecessaryAssumes.cpp EarlyCSE.cpp FlattenCFGPass.cpp Float2Int.cpp diff --git a/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp b/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp new file mode 100644 index 0000000000000..847be47a050c9 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp @@ -0,0 +1,59 @@ +//===------------------------------------------------------------*- C++ -*-===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/DropUnnecessaryAssumes.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/Utils/Local.h" + +using namespace llvm; + +PreservedAnalyses +DropUnnecessaryAssumesPass::run(Function &F, FunctionAnalysisManager &FAM) { + AssumptionCache &AC = FAM.getResult<AssumptionAnalysis>(F); + bool Changed = false; + + for (AssumptionCache::ResultElem &Elem : AC.assumptions()) { + auto *Assume = cast_or_null<AssumeInst>(Elem.Assume); + if (!Assume) + continue; + + // TODO: Handle assumes with operand bundles. + if (Assume->hasOperandBundles()) + continue; + + Value *Cond = Assume->getArgOperand(0); + // Don't drop type tests, which have special semantics. + if (match(Cond, PatternMatch::m_Intrinsic<Intrinsic::type_test>())) + continue; + + SmallPtrSet<Value *, 8> Affected; + findValuesAffectedByCondition(Cond, /*IsAssume=*/true, + [&](Value *A) { Affected.insert(A); }); + + // If all the affected uses have only one use (part of the assume), then + // the assume does not provide useful information. Note that additional + // users may appear as a result of inlining and CSE, so we should only + // make this assumption late in the optimization pipeline. + // TODO: Handle dead cyclic usages. + if (!all_of(Affected, [](Value *V) { return V->hasOneUse(); })) + continue; + + Assume->eraseFromParent(); + RecursivelyDeleteTriviallyDeadInstructions(Cond); + } + + if (Changed) { + PreservedAnalyses PA; + PA.preserveSet<CFGAnalyses>(); + return PA; + } + return PreservedAnalyses::all(); +} diff --git a/llvm/test/Other/new-pm-defaults.ll b/llvm/test/Other/new-pm-defaults.ll index c554fdbf4c799..94e860b8ce304 100644 --- a/llvm/test/Other/new-pm-defaults.ll +++ b/llvm/test/Other/new-pm-defaults.ll @@ -244,6 +244,7 @@ ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass ; CHECK-EP-OPTIMIZER-EARLY: Running pass: NoOpModulePass +; CHECK-DEFAULT-NEXT: Running pass: DropUnnecessaryAssumesPass ; CHECK-O-NEXT: Running pass: Float2IntPass ; CHECK-O-NEXT: Running pass: LowerConstantIntrinsicsPass on foo ; CHECK-MATRIX: Running pass: LowerMatrixIntrinsicsPass on f diff --git a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll index 62bb02d9b3c40..a08a140a35166 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-defaults.ll @@ -167,6 +167,7 @@ ; CHECK-POSTLINK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-POSTLINK-O-NEXT: Running pass: RecomputeGlobalsAAPass ; CHECK-POST-EP-OPT-EARLY-NEXT: Running pass: NoOpModulePass +; CHECK-POSTLINK-O-NEXT: Running pass: DropUnnecessaryAssumesPass ; CHECK-POSTLINK-O-NEXT: Running pass: Float2IntPass ; CHECK-POSTLINK-O-NEXT: Running pass: LowerConstantIntrinsicsPass ; CHECK-POSTLINK-O3-NEXT: Running pass: ControlHeightReductionPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll index 0da7a9f73bdce..d9e2dd37a7985 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll @@ -150,6 +150,7 @@ ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass +; CHECK-O-NEXT: Running pass: DropUnnecessaryAssumesPass ; CHECK-O-NEXT: Running pass: Float2IntPass ; CHECK-O-NEXT: Running pass: LowerConstantIntrinsicsPass ; CHECK-O3-NEXT: Running pass: ControlHeightReductionPass diff --git a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll index 38b7890682783..2f6fa4b27d354 100644 --- a/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll +++ b/llvm/test/Other/new-pm-thinlto-postlink-samplepgo-defaults.ll @@ -159,6 +159,7 @@ ; CHECK-O-NEXT: Running pass: EliminateAvailableExternallyPass ; CHECK-O-NEXT: Running pass: ReversePostOrderFunctionAttrsPass ; CHECK-O-NEXT: Running pass: RecomputeGlobalsAAPass +; CHECK-O-NEXT: Running pass: DropUnnecessaryAssumesPass ; CHECK-O-NEXT: Running pass: Float2IntPass ; CHECK-O-NEXT: Running pass: LowerConstantIntrinsicsPass ; CHECK-O3-NEXT: Running pass: ControlHeightReductionPass diff --git a/llvm/test/Transforms/DropUnnecessaryAssumes/basic.ll b/llvm/test/Transforms/DropUnnecessaryAssumes/basic.ll new file mode 100644 index 0000000000000..ea0d5d3fca8ff --- /dev/null +++ b/llvm/test/Transforms/DropUnnecessaryAssumes/basic.ll @@ -0,0 +1,96 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt -S -passes=drop-unnecessary-assumes < %s | FileCheck %s + +define void @basic_dead(i32 %x) { +; CHECK-LABEL: define void @basic_dead( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: ret void +; + %cond = icmp sge i32 %x, 0 + call void @llvm.assume(i1 %cond) + ret void +} + +define i32 @basic_live(i32 %x) { +; CHECK-LABEL: define i32 @basic_live( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = icmp sge i32 [[X]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) +; CHECK-NEXT: ret i32 [[X]] +; + %cond = icmp sge i32 %x, 0 + call void @llvm.assume(i1 %cond) + ret i32 %x +} + +; Affected value is not direct operand of the condition. +define i32 @complex_live(i32 %x) { +; CHECK-LABEL: define i32 @complex_live( +; CHECK-SAME: i32 [[X:%.*]]) { +; CHECK-NEXT: [[AND:%.*]] = and i32 [[X]], 1 +; CHECK-NEXT: [[COND:%.*]] = icmp ne i32 [[AND]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) +; CHECK-NEXT: ret i32 [[X]] +; + %and = and i32 %x, 1 + %cond = icmp ne i32 %and, 0 + call void @llvm.assume(i1 %cond) + ret i32 %x +} + +; There are multiple affected values, and not all are one-use. +define i32 @multiple_live1(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @multiple_live1( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X]], [[Y]] +; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) +; CHECK-NEXT: ret i32 [[X]] +; + %cond = icmp eq i32 %x, %y + call void @llvm.assume(i1 %cond) + ret i32 %x +} + +define i32 @multiple_live2(i32 %x, i32 %y) { +; CHECK-LABEL: define i32 @multiple_live2( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[COND:%.*]] = icmp eq i32 [[X]], [[Y]] +; CHECK-NEXT: call void @llvm.assume(i1 [[COND]]) +; CHECK-NEXT: ret i32 [[Y]] +; + %cond = icmp eq i32 %x, %y + call void @llvm.assume(i1 %cond) + ret i32 %y +} + +define void @operand_bundle_dead(ptr %x) { +; CHECK-LABEL: define void @operand_bundle_dead( +; CHECK-SAME: ptr [[X:%.*]]) { +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[X]], i64 8) ] +; CHECK-NEXT: ret void +; + call void @llvm.assume(i1 true) ["align"(ptr %x, i64 8)] + ret void +} + +define ptr @operand_bundle_live(ptr %x) { +; CHECK-LABEL: define ptr @operand_bundle_live( +; CHECK-SAME: ptr [[X:%.*]]) { +; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[X]], i64 8) ] +; CHECK-NEXT: ret ptr [[X]] +; + call void @llvm.assume(i1 true) ["align"(ptr %x, i64 8)] + ret ptr %x +} + +define void @type_test(ptr %x) { +; CHECK-LABEL: define void @type_test( +; CHECK-SAME: ptr [[X:%.*]]) { +; CHECK-NEXT: [[TEST:%.*]] = call i1 @llvm.type.test(ptr [[X]], metadata !"typeid") +; CHECK-NEXT: call void @llvm.assume(i1 [[TEST]]) +; CHECK-NEXT: ret void +; + %test = call i1 @llvm.type.test(ptr %x, metadata !"typeid") + call void @llvm.assume(i1 %test) + ret void +} diff --git a/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll b/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll index bbdbd95c6017a..f60812f2f39be 100644 --- a/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll +++ b/llvm/test/Transforms/PhaseOrdering/AArch64/constraint-elimination-placement.ll @@ -98,25 +98,11 @@ define void @test2(ptr %this) #0 { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[CALL1_I_I:%.*]] = tail call i1 @test2_fn4(i8 undef) ; CHECK-NEXT: [[CALL2_I_I:%.*]] = load i64, ptr inttoptr (i64 8 to ptr), align 8 -; CHECK-NEXT: [[COND_I_I:%.*]] = select i1 [[CALL1_I_I]], i64 [[CALL2_I_I]], i64 0 -; CHECK-NEXT: switch i64 [[COND_I_I]], label [[COMMON_RET:%.*]] [ -; CHECK-NEXT: i64 11, label [[IF_END_I:%.*]] -; CHECK-NEXT: i64 13, label [[TEST2_FN2_EXIT12:%.*]] -; CHECK-NEXT: i64 17, label [[IF_END_I31:%.*]] -; CHECK-NEXT: ] -; CHECK: if.end.i: -; CHECK-NEXT: [[CALL8_I_I:%.*]] = tail call fastcc noundef i32 @test2_fn6() -; CHECK-NEXT: [[TRUNC_I_I:%.*]] = trunc i32 [[CALL8_I_I]] to i8 -; CHECK-NEXT: [[CALL1_I1_I:%.*]] = tail call i1 @test2_fn4(i8 [[TRUNC_I_I]]) -; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[CALL1_I1_I]], true -; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP0]]) -; CHECK-NEXT: br label [[COMMON_RET]] +; CHECK-NEXT: [[COND38:%.*]] = icmp eq i64 [[CALL2_I_I]], 13 +; CHECK-NEXT: [[COND:%.*]] = select i1 [[CALL1_I_I]], i1 [[COND38]], i1 false +; CHECK-NEXT: br i1 [[COND]], label [[TEST2_FN2_EXIT12:%.*]], label [[COMMON_RET:%.*]] ; CHECK: test2_fn2.exit12: ; CHECK-NEXT: [[CALL8_I_I8:%.*]] = tail call fastcc noundef i32 @test2_fn6() -; CHECK-NEXT: [[TRUNC_I_I9:%.*]] = trunc i32 [[CALL8_I_I8]] to i8 -; CHECK-NEXT: [[CALL1_I1_I10:%.*]] = tail call i1 @test2_fn4(i8 [[TRUNC_I_I9]]) -; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[CALL1_I1_I10]], true -; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP1]]) ; CHECK-NEXT: [[CMP4_I11:%.*]] = icmp eq i32 [[CALL8_I_I8]], 0 ; CHECK-NEXT: br i1 [[CMP4_I11]], label [[TEST2_FN2_EXIT24:%.*]], label [[COMMON_RET]] ; CHECK: common.ret: @@ -124,13 +110,6 @@ define void @test2(ptr %this) #0 { ; CHECK: test2_fn2.exit24: ; CHECK-NEXT: store i8 0, ptr [[THIS]], align 4 ; CHECK-NEXT: br label [[COMMON_RET]] -; CHECK: if.end.i31: -; CHECK-NEXT: [[CALL8_I_I32:%.*]] = tail call fastcc noundef i32 @test2_fn6() -; CHECK-NEXT: [[TRUNC_I_I33:%.*]] = trunc i32 [[CALL8_I_I32]] to i8 -; CHECK-NEXT: [[CALL1_I1_I34:%.*]] = tail call i1 @test2_fn4(i8 [[TRUNC_I_I33]]) -; CHECK-NEXT: [[TMP2:%.*]] = xor i1 [[CALL1_I1_I34]], true -; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP2]]) -; CHECK-NEXT: br label [[COMMON_RET]] ; entry: %call16 = call i1 @test2_fn2(ptr @.str.78) @@ -163,10 +142,6 @@ define i1 @test2_fn2(ptr %__rhs) #0 { ; CHECK-NEXT: br i1 [[CMP2_NOT]], label [[IF_END:%.*]], label [[CLEANUP:%.*]] ; CHECK: if.end: ; CHECK-NEXT: [[CALL8_I:%.*]] = tail call fastcc noundef i32 @test2_fn6() -; CHECK-NEXT: [[TRUNC_I:%.*]] = trunc i32 [[CALL8_I]] to i8 -; CHECK-NEXT: [[CALL1_I1:%.*]] = tail call i1 @test2_fn4(i8 [[TRUNC_I]]) -; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[CALL1_I1]], true -; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP0]]) ; CHECK-NEXT: [[CMP4:%.*]] = icmp eq i32 [[CALL8_I]], 0 ; CHECK-NEXT: br label [[CLEANUP]] ; CHECK: cleanup: @@ -210,7 +185,7 @@ cond.end: ; preds = %cond.true, %entry define i1 @test2_fn4(i8 %bf.load) { ; CHECK-LABEL: define i1 @test2_fn4( -; CHECK-SAME: i8 [[BF_LOAD:%.*]]) local_unnamed_addr #[[ATTR5:[0-9]+]] { +; CHECK-SAME: i8 [[BF_LOAD:%.*]]) local_unnamed_addr #[[ATTR4:[0-9]+]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: [[TOBOOL:%.*]] = icmp slt i8 [[BF_LOAD]], 0 ; CHECK-NEXT: ret i1 [[TOBOOL]] @@ -232,7 +207,7 @@ entry: define internal i32 @test2_fn6() { ; CHECK-LABEL: define internal fastcc noundef i32 @test2_fn6( -; CHECK-SAME: ) unnamed_addr #[[ATTR5]] { +; CHECK-SAME: ) unnamed_addr #[[ATTR4]] { ; CHECK-NEXT: entry: ; CHECK-NEXT: ret i32 0 ; diff --git a/llvm/test/Transforms/PhaseOrdering/pr45682.ll b/llvm/test/Transforms/PhaseOrdering/pr45682.ll index 46ee19178e356..50e31f1bf632d 100644 --- a/llvm/test/Transforms/PhaseOrdering/pr45682.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr45682.ll @@ -5,8 +5,6 @@ define void @PR45682(i32 %x, i32 %y) { ; CHECK-LABEL: @PR45682( ; CHECK-NEXT: entry: -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[Y:%.*]], 0 -; CHECK-NEXT: tail call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: ret void ; entry: diff --git a/llvm/test/Transforms/PhaseOrdering/pr45687.ll b/llvm/test/Transforms/PhaseOrdering/pr45687.ll index f0064b58820e4..36d7c24f2bd79 100644 --- a/llvm/test/Transforms/PhaseOrdering/pr45687.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr45687.ll @@ -3,9 +3,6 @@ define void @PR45687(i32 %0) { ; CHECK-LABEL: @PR45687( -; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0:%.*]], 1 -; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i32 [[TMP2]], 3 -; CHECK-NEXT: tail call void @llvm.assume(i1 [[TMP3]]) ; CHECK-NEXT: ret void ; %2 = add i32 %0, 1 diff --git a/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll index 2bb78dd5ec773..5c4ada38bd302 100644 --- a/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll +++ b/llvm/test/Transforms/PhaseOrdering/pr98799-inline-simplifycfg-ub.ll @@ -34,8 +34,6 @@ define i32 @foo(ptr %arg, i1 %arg1) { ; O2-LABEL: define i32 @foo( ; O2-SAME: ptr captures(none) [[ARG:%.*]], i1 [[ARG1:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { ; O2-NEXT: [[BB:.*:]] -; O2-NEXT: [[TMP0:%.*]] = xor i1 [[ARG1]], true -; O2-NEXT: tail call void @llvm.assume(i1 [[TMP0]]) ; O2-NEXT: [[I_I:%.*]] = load ptr, ptr [[ARG]], align 8, !nonnull [[META0:![0-9]+]], !noundef [[META0]] ; O2-NEXT: [[I3_I:%.*]] = getelementptr inbounds nuw i8, ptr [[I_I]], i64 1 ; O2-NEXT: store ptr [[I3_I]], ptr [[ARG]], align 8 >From 27d97462ce77aa7ae24a8efa60634c32268f8e47 Mon Sep 17 00:00:00 2001 From: Nikita Popov <npo...@redhat.com> Date: Thu, 18 Sep 2025 09:40:00 +0200 Subject: [PATCH 2/3] review comments --- .../llvm/Transforms/Scalar/DropUnnecessaryAssumes.h | 3 +-- llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h b/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h index 192139cbfd94d..4ff442ff80c76 100644 --- a/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h +++ b/llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h @@ -17,9 +17,8 @@ namespace llvm { -class DropUnnecessaryAssumesPass +struct DropUnnecessaryAssumesPass : public PassInfoMixin<DropUnnecessaryAssumesPass> { -public: PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); }; diff --git a/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp b/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp index 847be47a050c9..c2e58ba393553 100644 --- a/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp +++ b/llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp @@ -14,6 +14,7 @@ #include "llvm/Transforms/Utils/Local.h" using namespace llvm; +using namespace llvm::PatternMatch; PreservedAnalyses DropUnnecessaryAssumesPass::run(Function &F, FunctionAnalysisManager &FAM) { @@ -31,7 +32,7 @@ DropUnnecessaryAssumesPass::run(Function &F, FunctionAnalysisManager &FAM) { Value *Cond = Assume->getArgOperand(0); // Don't drop type tests, which have special semantics. - if (match(Cond, PatternMatch::m_Intrinsic<Intrinsic::type_test>())) + if (match(Cond, m_Intrinsic<Intrinsic::type_test>())) continue; SmallPtrSet<Value *, 8> Affected; @@ -43,11 +44,13 @@ DropUnnecessaryAssumesPass::run(Function &F, FunctionAnalysisManager &FAM) { // users may appear as a result of inlining and CSE, so we should only // make this assumption late in the optimization pipeline. // TODO: Handle dead cyclic usages. - if (!all_of(Affected, [](Value *V) { return V->hasOneUse(); })) + // TODO: Handle multiple dead assumes on the same value. + if (!all_of(Affected, match_fn(m_OneUse(m_Value())))) continue; Assume->eraseFromParent(); RecursivelyDeleteTriviallyDeadInstructions(Cond); + Changed = true; } if (Changed) { >From d65b96a2409f42b84ec1542daa4ee60f05b90f74 Mon Sep 17 00:00:00 2001 From: Nikita Popov <npo...@redhat.com> Date: Thu, 18 Sep 2025 16:11:24 +0200 Subject: [PATCH 3/3] add comment --- llvm/lib/Passes/PassBuilderPipelines.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/llvm/lib/Passes/PassBuilderPipelines.cpp b/llvm/lib/Passes/PassBuilderPipelines.cpp index 3b75a5a83dd9a..30c6f06be139d 100644 --- a/llvm/lib/Passes/PassBuilderPipelines.cpp +++ b/llvm/lib/Passes/PassBuilderPipelines.cpp @@ -1499,6 +1499,10 @@ PassBuilder::buildModuleOptimizationPipeline(OptimizationLevel Level, invokeOptimizerEarlyEPCallbacks(MPM, Level, LTOPhase); FunctionPassManager OptimizePM; + + // Only drop unnecessary assumes post-inline and post-link, as otherwise + // additional uses of the affected value may be introduced through inlining + // and CSE. if (!isLTOPreLink(LTOPhase)) OptimizePM.addPass(DropUnnecessaryAssumesPass()); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits