[llvm] 91c9dee - [CodeGenPrepare] Eliminate llvm.expect before removing empty blocks
Benjamin Kramer via llvm-commits
llvm-commits at lists.llvm.org
Thu Mar 4 05:48:38 PST 2021
Author: Jann Horn
Date: 2021-03-04T14:48:26+01:00
New Revision: 91c9dee3fb6d89ab3315fac1c1419614d6874b99
URL: https://github.com/llvm/llvm-project/commit/91c9dee3fb6d89ab3315fac1c1419614d6874b99
DIFF: https://github.com/llvm/llvm-project/commit/91c9dee3fb6d89ab3315fac1c1419614d6874b99.diff
LOG: [CodeGenPrepare] Eliminate llvm.expect before removing empty blocks
CodeGenPrepare currently first removes empty blocks, then in a loop
performs other optimizations. One of those optimizations is the removal
of call instructions that invoke @llvm.assume, which can create new
empty blocks.
This means that when a branch only contains a call to __builtin_assume(),
the empty branch will survive into MIR, and will then only be
half-removed by MIR-level optimizations (e.g. removing the branch but
leaving the condition intact).
Fix it by eliminating @llvm.expect builtin calls before removing empty
blocks.
Reviewed By: bkramer
Differential Revision: https://reviews.llvm.org/D97848
Added:
llvm/test/Transforms/CodeGenPrepare/remove-assume-block.ll
Modified:
llvm/lib/CodeGen/CodeGenPrepare.cpp
llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp
index 5d6c8ec0569c..a7e1aef68800 100644
--- a/llvm/lib/CodeGen/CodeGenPrepare.cpp
+++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp
@@ -377,6 +377,7 @@ class TypePromotionTransaction;
}
void removeAllAssertingVHReferences(Value *V);
+ bool eliminateAssumptions(Function &F);
bool eliminateFallThrough(Function &F);
bool eliminateMostlyEmptyBlocks(Function &F);
BasicBlock *findDestBlockOfMergeableEmptyBlock(BasicBlock *BB);
@@ -506,6 +507,11 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
}
}
+ // Get rid of @llvm.assume builtins before attempting to eliminate empty
+ // blocks, since there might be blocks that only contain @llvm.assume calls
+ // (plus arguments that we can get rid of).
+ EverMadeChange |= eliminateAssumptions(F);
+
// Eliminate blocks that contain only PHI nodes and an
// unconditional branch.
EverMadeChange |= eliminateMostlyEmptyBlocks(F);
@@ -614,6 +620,28 @@ bool CodeGenPrepare::runOnFunction(Function &F) {
return EverMadeChange;
}
+bool CodeGenPrepare::eliminateAssumptions(Function &F) {
+ bool MadeChange = false;
+ for (BasicBlock &BB : F) {
+ CurInstIterator = BB.begin();
+ while (CurInstIterator != BB.end()) {
+ Instruction *I = &*(CurInstIterator++);
+ if (IntrinsicInst *II = dyn_cast<IntrinsicInst>(I)) {
+ if (II->getIntrinsicID() != Intrinsic::assume)
+ continue;
+ MadeChange = true;
+ Value *Operand = II->getOperand(0);
+ II->eraseFromParent();
+
+ resetIteratorIfInvalidatedWhileCalling(&BB, [&]() {
+ RecursivelyDeleteTriviallyDeadInstructions(Operand, TLInfo, nullptr);
+ });
+ }
+ }
+ }
+ return MadeChange;
+}
+
/// An instruction is about to be deleted, so remove all references to it in our
/// GEP-tracking data strcutures.
void CodeGenPrepare::removeAllAssertingVHReferences(Value *V) {
@@ -2118,18 +2146,8 @@ bool CodeGenPrepare::optimizeCallInst(CallInst *CI, bool &ModifiedDT) {
if (II) {
switch (II->getIntrinsicID()) {
default: break;
- case Intrinsic::assume: {
- Value *Operand = II->getOperand(0);
- II->eraseFromParent();
- // Prune the operand, it's most likely dead.
- resetIteratorIfInvalidatedWhileCalling(BB, [&]() {
- RecursivelyDeleteTriviallyDeadInstructions(
- Operand, TLInfo, nullptr,
- [&](Value *V) { removeAllAssertingVHReferences(V); });
- });
- return true;
- }
-
+ case Intrinsic::assume:
+ llvm_unreachable("llvm.assume should have been removed already");
case Intrinsic::experimental_widenable_condition: {
// Give up on future widening oppurtunties so that we can fold away dead
// paths and merge blocks before going into block-local instruction
diff --git a/llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll b/llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll
index 54463d0d73a8..44931a1fa8e5 100644
--- a/llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll
+++ b/llvm/test/Transforms/CodeGenPrepare/X86/delete-assume-dead-code.ll
@@ -5,11 +5,6 @@ define i32 @test1(i8* %d) nounwind {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[L:%.*]] = load i8, i8* [[D:%.*]], align 1
-; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[L]], 0
-; CHECK-NEXT: br i1 [[CMP]], label [[EXIT:%.*]], label [[IF_END:%.*]]
-; CHECK: if.end:
-; CHECK-NEXT: br label [[EXIT]]
-; CHECK: exit:
; CHECK-NEXT: [[TMP0:%.*]] = icmp eq i8 [[L]], 0
; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[TMP0]] to i32
; CHECK-NEXT: ret i32 [[CONV]]
diff --git a/llvm/test/Transforms/CodeGenPrepare/remove-assume-block.ll b/llvm/test/Transforms/CodeGenPrepare/remove-assume-block.ll
new file mode 100644
index 000000000000..536a7d1d3d31
--- /dev/null
+++ b/llvm/test/Transforms/CodeGenPrepare/remove-assume-block.ll
@@ -0,0 +1,48 @@
+; RUN: opt -S -codegenprepare < %s | FileCheck %s
+;
+; Ensure that blocks that only contain @llvm.assume are removed completely
+; during CodeGenPrepare.
+
+target triple = "x86_64-unknown-linux-gnu"
+
+; CHECK-LABEL: @simple(
+; CHECK-NEXT: end:
+; CHECK-NEXT: ret void
+define void @simple(i64 %addr, i1 %assumption) {
+ %cmp1 = icmp eq i64 %addr, 0
+ br i1 %cmp1, label %do_assume, label %end
+
+do_assume:
+ tail call void @llvm.assume(i1 %assumption)
+ br label %end
+
+end:
+ ret void
+}
+
+; CHECK-LABEL: @complex_assume(
+; CHECK-NEXT: end:
+; CHECK-NEXT: ret void
+define void @complex_assume(i64 %addr, i1 %assumption_a, i1 %assumption_b,
+ i64 %val_a, i64 %val_b) {
+ %cmp1 = icmp eq i64 %addr, 0
+ br i1 %cmp1, label %do_assume, label %end
+
+do_assume:
+ call void @llvm.assume(i1 %assumption_a)
+ call void @llvm.assume(i1 %assumption_b)
+ %val_xor = xor i64 %val_a, %val_b
+ %val_shifted = lshr i64 %val_xor, 7
+ %assumption_c = trunc i64 %val_shifted to i1
+ call void @llvm.assume(i1 %assumption_c)
+ %assumption_d = call i1 @readonly_func(i64 %val_b)
+ call void @llvm.assume(i1 %assumption_d)
+ br label %end
+
+end:
+ ret void
+}
+
+declare void @llvm.assume(i1 noundef)
+declare i1 @readonly_func(i64) nounwind readonly willreturn;
+
More information about the llvm-commits
mailing list