Skip to content

Commit

Permalink
llvm-reduce: Fix block reduction with unreachable blocks
Browse files Browse the repository at this point in the history
Previously this would produce many invalid reductions with
"Instruction does not dominate uses" verifier errors.

This fixes issues in cases where the incoming IR
has unreachable blocks, and the resulting reduction
introduced new reachable blocks.

Have basic-blocks skip functions that have unreachable
blocks, Introduce a separate reduction which only
deletes unreachable blocks. Cleanup any newly unreachable
blocks after trimming out the requested deletions.

Includes a variety of meta-reduced tests for llvm-reduce
itself with -abort-on-invalid-reduction that were failing
on different iterations of this patch.

Bugpoint's implementation is much simpler (but currently I don't
understand how it avoids disconnecting interesting blocks from the CFG).
  • Loading branch information
arsenm committed Oct 29, 2022
1 parent bc405e3 commit 45a91c1
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 45 deletions.
@@ -0,0 +1,52 @@
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck %s < %t


; Check that no invalid reduction is produced. Remaining unreachable
; blocks can leave instructions that dominate uses. When %bb3 was made
; unreachable it produced this verifier error:
; Instruction does not dominate all uses!
; %i4 = icmp eq i32 0, 0
; %i6 = select i1 %i4, i1 false, i1 false


; CHECK: define void @func() {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label %bb1

; CHECK: bb1:
; CHECK-NEXT: label %bb3

; CHECK: bb2:
; CHECK-NEXT: br i1 false, label %bb1, label %bb2

; CHECK: bb3:
; CHECK-NEXT: %i = phi i32 [ 0, %bb1 ]
; CHECK: %i4 = icmp eq i32 0, 0
; CHECK-NEXT: br label %bb5

; CHECK: bb5:
; CHECK-NEXT: %i6 = select i1 %i4, i1 false, i1 false
; CHECK-NEXT: store i32 0
; CHECK-NEXT: ret void
define void @func() {
bb:
br label %bb1

bb1: ; preds = %bb2, %bb
br label %bb3

bb2: ; preds = %bb2
br i1 false, label %bb1, label %bb2

bb3: ; preds = %bb1
%i = phi i32 [ 0, %bb1 ]
%i4 = icmp eq i32 0, 0
br label %bb5

bb5: ; preds = %bb3
%i6 = select i1 %i4, i1 false, i1 false
; CHECK-INTERESTINGNESS: store
store i32 0, ptr undef, align 4
ret void
}
@@ -0,0 +1,61 @@
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=unreachable-basic-blocks,basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck %s < %t


; CHECK-INTERESTINGNESS: @func(

; CHECK-INTERESTINGNESS: store
; CHECK-INTERESTINGNESS: store
; CHECK-INTERESTINGNESS: store


; CHECK: bb:
; CHECK-NEXT: br i1 %arg1, label %bb3, label %bb7

; CHECK: bb3: ; preds = %bb
; CHECK-NEXT: br i1 %arg2, label %bb4, label %bb7

; CHECK: bb4: ; preds = %bb3
; CHECK-NEXT: store i32 0, ptr addrspace(1) null, align 4
; CHECK-NEXT: br label %bb10

; CHECK: bb7: ; preds = %bb3, %bb
; CHECK-NEXT: %i = phi i1 [ false, %bb ], [ true, %bb3 ]
; CHECK-NEXT: store i32 1, ptr addrspace(1) null, align 4
; CHECK-NEXT: br label %bb10

; CHECK: bb10: ; preds = %bb7, %bb4
; CHECK-NEXT: store i32 2, ptr addrspace(1) null, align 4
; CHECK-NEXT: unreachable
define amdgpu_kernel void @func(i1 %arg, i1 %arg1, i1 %arg2) {
bb:
br i1 %arg1, label %bb3, label %bb7

bb3: ; preds = %bb
br i1 %arg2, label %bb4, label %bb7

bb4: ; preds = %bb3
store i32 0, ptr addrspace(1) null
br label %bb5

bb5: ; preds = %bb4
unreachable

bb6: ; No predecessors!
unreachable

bb7: ; preds = %bb3, %bb
%i = phi i1 [ false, %bb ], [ true, %bb3 ]
store i32 1, ptr addrspace(1) null
br i1 %arg, label %bb10, label %bb8

bb8: ; preds = %bb7
br i1 %i, label %bb9, label %bb9

bb9: ; preds = %bb8, %bb8
unreachable

bb10: ; preds = %bb7
store i32 2, ptr addrspace(1) null
unreachable
}
@@ -0,0 +1,47 @@
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck %s < %t

; Make sure an invalid reduction isn't produced due to leaving behind
; invalid code in %bb8 after it becomes unreachable.

; CHECK-INTERESTINGNESS: store i32 0,
; CHECK-INTERESTINGNESS: store i32 1,
; CHECK-INTERESTINGNESS: store i32 2,


; CHECK: bb:
; CHECK-NEXT: store i32 0, ptr addrspace(3) null, align 4

; CHECK: bb6: ; preds = %bb8, %bb
; CHECK-NEXT: store i32 1, ptr addrspace(3) null, align 4

; CHECK: bb8: ; preds = %bb6
; CHECK-NEXT: %tmp = phi ptr addrspace(5) [ null, %bb6 ]
define amdgpu_kernel void @foo(i32 %arg) {
bb:
store i32 0, ptr addrspace(3) null
br label %bb6

bb6: ; preds = %bb10, %bb9, %bb8, %bb
store i32 1, ptr addrspace(3) null
switch i32 0, label %bb7 [
i32 0, label %bb8
]

bb7: ; preds = %bb6
unreachable

bb8: ; preds = %bb6
%tmp = phi ptr addrspace(5) [ null, %bb6 ]
store i32 2, ptr addrspace(5) %tmp
switch i32 %arg, label %bb6 [
i32 0, label %bb10
i32 1, label %bb9
]

bb9: ; preds = %bb8
br label %bb6

bb10: ; preds = %bb8
br label %bb6
}
@@ -0,0 +1,60 @@
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=unreachable-basic-blocks,basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck %s < %t


; CHECK-INTERESTINGNESS: store i32 0,
; CHECK-INTERESTINGNESS: store i32 1,


; CHECK: bb:
; CHECK-NEXT: %tmp = icmp eq i8 0, 0
; CHECK-NEXT: %tmp12 = load i32, ptr addrspace(4) inttoptr (i64 3016 to ptr addrspace(4)), align 8
; CHECK-NEXT: %tmp13 = load i32, ptr addrspace(4) null, align 8
; CHECK-NEXT: br label %bb20

; CHECK: bb20:
; CHECK-NEXT: store i32 0, ptr addrspace(3) null, align 4
; CHECK-NEXT: br label %bb21

; CHECK: bb21:
; CHECK-NEXT: store i32 1, ptr addrspace(3) null, align 4
; CHECK-NEXT: ret void

define void @snork() {
bb:
%tmp = icmp eq i8 0, 0
%tmp12 = load i32, ptr addrspace(4) inttoptr (i64 3016 to ptr addrspace(4)), align 8
%tmp13 = load i32, ptr addrspace(4) null, align 8
br label %bb14

bb14: ; preds = %bb21, %bb20, %bb19, %bb14, %bb
switch i32 %tmp12, label %bb22 [
i32 2, label %bb14
i32 1, label %bb19
]

bb15: ; preds = %bb17
%tmp16 = fadd contract double %tmp18, 1.000000e+00
unreachable

bb17: ; preds = %bb17
%tmp18 = fadd contract double 0.000000e+00, 0.000000e+00
br i1 false, label %bb15, label %bb17

bb19: ; preds = %bb14
switch i32 %tmp13, label %bb14 [
i32 2, label %bb21
i32 1, label %bb20
]

bb20: ; preds = %bb19
store i32 0, ptr addrspace(3) null, align 4
br label %bb14

bb21: ; preds = %bb19
store i32 1, ptr addrspace(3) null, align 4
br label %bb14

bb22: ; preds = %bb14
unreachable
}
@@ -0,0 +1,51 @@
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=basic-blocks --test=FileCheck --test-arg=--check-prefix=CHECK-INTERESTINGNESS --test-arg=%s --test-arg=--input-file %s -o %t
; RUN: FileCheck %s < %t

; Make sure an invalid reduction isn't tried when deleting %bb5,
; causing the or in %bb6 to use its own output value.


; CHECK-INTERESTINGNESS: store i32 0
; CHECK-INTERESTINGNESS: store i32 1
; CHECK-INTERESTINGNESS: store i32 2

; CHECK: store i32 0
; CHECK-NEXT: br label %bb5

; CHECK: bb5:
; CHECK-NEXT: switch

; CHECK: bb6:
; CHECK-NEXT: %tmp = phi i32 [ %tmp7, %bb6 ]
; CHECK-NEXT: store i32 1
; CHECK-NEXT: %tmp7 = or i32 %tmp, 0
; CHECK-NEXT: br label %bb6

; CHECK-NOT: bb7
; CHECK: bb8:
; CHECK-NEXT: store i32 2,
define amdgpu_kernel void @snork(i32 %arg, i1 %arg1) {
bb:
store i32 0, ptr addrspace(3) null
br i1 %arg1, label %bb5, label %bb7

bb5: ; preds = %bb5, %bb
switch i32 %arg, label %bb5 [
i32 0, label %bb8
i32 1, label %bb6
]

bb6: ; preds = %bb6, %bb5
%tmp = phi i32 [ %tmp7, %bb6 ], [ 0, %bb5 ]
store i32 1, ptr addrspace(3) null
%tmp7 = or i32 %tmp, 0
br label %bb6

bb7:
store i32 3, ptr addrspace(3) null
br label %bb8

bb8: ; preds = %bb5
store i32 2, ptr addrspace(3) null
unreachable
}
5 changes: 1 addition & 4 deletions llvm/test/tools/llvm-reduce/remove-bb-switch-default.ll
Expand Up @@ -16,14 +16,12 @@
; RESULT0-NEXT: br i1 %arg0, label %bb1, label %bb2

; RESULT0: bb1:
; RESULT0-NEXT: %bb1.phi = phi i32 [ %bb.load, %bb ], [ %bb2.phi, %bb2 ], [ %bb2.phi, %bb2 ]
; RESULT0-NEXT: store i32 1, ptr null, align 4
; RESULT0-NEXT: ret void

; RESULT0: bb2: ; preds = %bb
; RESULT0-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
; RESULT0-NEXT: store i32 2, ptr null, align 4
; RESULT0-NEXT: switch i32 %bb2.phi, label %bb1 [
; RESULT0-NEXT: switch i32 %bb.load, label %bb1 [
; RESULT0-NEXT: i32 0, label %bb1
; RESULT0-NEXT: ]

Expand All @@ -34,7 +32,6 @@
; RESULT1-NEXT: br label %bb2

; RESULT1: bb2:
; RESULT1-NEXT: %bb2.phi = phi i32 [ %bb.load, %bb ]
; RESULT1-NEXT: store i32 2, ptr null, align 4
; RESULT1-NEXT: ret void
define void @main(i1 %arg0) {
Expand Down
46 changes: 40 additions & 6 deletions llvm/test/tools/llvm-reduce/remove-bbs-unreachable.ll
@@ -1,16 +1,31 @@
; Check that verification doesn't fail when reducing a function with
; unreachable blocks.
;
; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=unreachable-basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck -check-prefix=UNREACHABLE %s < %t

; RUN: llvm-reduce --abort-on-invalid-reduction --delta-passes=basic-blocks --test FileCheck --test-arg --check-prefixes=CHECK-INTERESTINGNESS --test-arg %s --test-arg --input-file %s -o %t
; RUN: FileCheck %s < %t
; RUN: FileCheck -check-prefix=REACHABLE %s < %t

; CHECK-INTERESTINGNESS: test0
; CHECK-INTERESTINGNESS: test1

; UNREACHABLE: define void @test0() {
; UNREACHABLE-NEXT: entry:
; UNREACHABLE-NEXT: br label %exit

; UNREACHABLE-NOT: unreachable
; UNREACHABLE: exit:
; UNREACHABLE-NEXT: ret void

; CHECK-INTERESTINGNESS: test

; CHECK: define void @test() {
; CHECK-NEXT: entry:
; CHECK-NEXT: ret void
; basic-blocks cannot deal with unreachable blocks, leave it behind
; REACHABLE: define void @test0() {
; REACHABLE: entry:
; REACHABLE: unreachable:
; REACHABLE: exit:

define void @test() {
define void @test0() {
entry:
br label %exit

Expand All @@ -20,3 +35,22 @@ unreachable: ; No predecessors!
exit:
ret void
}

; UNREACHABLE: define void @test1() {
; UNREACHABLE-NEXT: entry:
; UNREACHABLE-NEXT: br label %exit

; REACHABLE: define void @test1() {
; REACHABLE: entry:
; REACHABLE: unreachable:
; REACHABLE: exit:
define void @test1() {
entry:
br label %exit

unreachable:
br label %unreachable

exit:
ret void
}
3 changes: 2 additions & 1 deletion llvm/tools/llvm-reduce/DeltaManager.cpp
Expand Up @@ -76,7 +76,9 @@ static cl::list<std::string>
DELTA_PASS("aliases", reduceAliasesDeltaPass) \
DELTA_PASS("simplify-conditionals-true", reduceConditionalsTrueDeltaPass) \
DELTA_PASS("simplify-conditionals-false", reduceConditionalsFalseDeltaPass)\
DELTA_PASS("unreachable-basic-blocks", reduceUnreachableBasicBlocksDeltaPass) \
DELTA_PASS("basic-blocks", reduceBasicBlocksDeltaPass) \
DELTA_PASS("simplify-cfg", reduceUsingSimplifyCFGDeltaPass) \
DELTA_PASS("global-values", reduceGlobalValuesDeltaPass) \
DELTA_PASS("global-objects", reduceGlobalObjectsDeltaPass) \
DELTA_PASS("global-initializers", reduceGlobalsInitializersDeltaPass) \
Expand All @@ -93,7 +95,6 @@ static cl::list<std::string>
DELTA_PASS("operands-to-args", reduceOperandsToArgsDeltaPass) \
DELTA_PASS("operands-skip", reduceOperandsSkipDeltaPass) \
DELTA_PASS("operand-bundles", reduceOperandBundesDeltaPass) \
DELTA_PASS("simplify-cfg", reduceUsingSimplifyCFGDeltaPass) \
DELTA_PASS("attributes", reduceAttributesDeltaPass) \
DELTA_PASS("module-data", reduceModuleDataDeltaPass) \
DELTA_PASS("opcodes", reduceOpcodesDeltaPass) \
Expand Down

0 comments on commit 45a91c1

Please sign in to comment.