Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion clang/test/CodeGen/inline-asm-x86-flag-output.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
27 changes: 27 additions & 0 deletions llvm/include/llvm/Transforms/Scalar/DropUnnecessaryAssumes.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===------------------------------------------------------------*- 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 {

struct DropUnnecessaryAssumesPass
: public PassInfoMixin<DropUnnecessaryAssumesPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_DROPUNNECESSARYASSUMES_H
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/Passes/PassBuilderPipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -1498,6 +1499,13 @@ 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))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It deserves a comment here to explain why it only runs at post-inline and post-link.

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
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -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())
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ add_llvm_component_library(LLVMScalarOpts
DeadStoreElimination.cpp
DFAJumpThreading.cpp
DivRemPairs.cpp
DropUnnecessaryAssumes.cpp
EarlyCSE.cpp
FlattenCFGPass.cpp
Float2Int.cpp
Expand Down
62 changes: 62 additions & 0 deletions llvm/lib/Transforms/Scalar/DropUnnecessaryAssumes.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//===------------------------------------------------------------*- 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;
using namespace llvm::PatternMatch;

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, 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.
// 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) {
PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
return PA;
}
return PreservedAnalyses::all();
}
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-thinlto-postlink-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Other/new-pm-thinlto-postlink-pgo-defaults.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
96 changes: 96 additions & 0 deletions llvm/test/Transforms/DropUnnecessaryAssumes/basic.ll
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
Expand Up @@ -98,39 +98,18 @@ 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:
; CHECK-NEXT: ret void
; 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)
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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]]
Expand All @@ -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
;
Expand Down
2 changes: 0 additions & 2 deletions llvm/test/Transforms/PhaseOrdering/pr45682.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
3 changes: 0 additions & 3 deletions llvm/test/Transforms/PhaseOrdering/pr45687.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down