mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #84811 from rjmccall/verify-dead-end-edges
Strengthen the SIL verifier's rules for edges into dead-end regions
This commit is contained in:
@@ -55,11 +55,16 @@ bb3:
|
||||
return %1 : $()
|
||||
}
|
||||
|
||||
// CHECK: Begin Error in function test_missing_end_borrow
|
||||
// CHECK: SIL verification failed: inconsistent active-operations sets entering basic block: state.ActiveOps == foundState.ActiveOps || isUnreachable()
|
||||
// CHECK: Verifying instruction:
|
||||
// CHECK: -> br bb3 // id: %5
|
||||
// CHECK: End Error in function test_missing_end_borrow
|
||||
// CHECK: Begin Error in function test_missing_end_borrow
|
||||
// CHECK-NEXT: SIL verification failed: inconsistent active-operations sets entering basic block
|
||||
// CHECK-NEXT: Entering basic block bb3
|
||||
// CHECK-NEXT: Current active operations: []
|
||||
// CHECK-NEXT: Recorded active operations: [
|
||||
// CHECK-NEXT: %2 = store_borrow %0 to %1 : $*Klass
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Verifying instruction:
|
||||
// CHECK-NEXT: -> br bb3 // id: %5
|
||||
// CHECK-NEXT: End Error in function test_missing_end_borrow
|
||||
sil [ossa] @test_missing_end_borrow_dead : $@convention(thin) (@guaranteed Klass) -> () {
|
||||
bb0(%0 : @guaranteed $Klass):
|
||||
%stk = alloc_stack $Klass
|
||||
|
||||
333
test/SIL/verifier-fail-stack.sil
Normal file
333
test/SIL/verifier-fail-stack.sil
Normal file
@@ -0,0 +1,333 @@
|
||||
// RUN: %target-sil-opt -verify-continue-on-failure -o /dev/null %s 2>&1 | %FileCheck %s
|
||||
|
||||
// REQUIRES: asserts
|
||||
|
||||
sil_stage canonical
|
||||
|
||||
import Builtin
|
||||
|
||||
// Check that join points normally require the stack to match.
|
||||
// CHECK-LABEL: Begin Error in function require_match_1
|
||||
// CHECK-LABEL: Begin Error in function require_match_1
|
||||
// CHECK: SIL verification failed: inconsistent stack states entering basic block
|
||||
// CHECK-NEXT: Entering basic block bb3
|
||||
// CHECK-NEXT: Current stack state: []
|
||||
// CHECK-NEXT: Recorded stack state: [
|
||||
// CHECK-NEXT: %0 = alloc_stack $Builtin.Int32
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-LABEL: End Error in function require_match_1
|
||||
sil @require_match_1 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
%result = tuple ()
|
||||
return %result : $()
|
||||
}
|
||||
|
||||
// Same as above, just with the branches switched around.
|
||||
// CHECK-LABEL: Begin Error in function require_match_2
|
||||
// CHECK-LABEL: Begin Error in function require_match_2
|
||||
// CHECK: SIL verification failed: inconsistent stack states entering basic block
|
||||
// CHECK-NEXT: Entering basic block bb3
|
||||
// CHECK-NEXT: Current stack state: [
|
||||
// CHECK-NEXT: %0 = alloc_stack $Builtin.Int32
|
||||
// CHECK-NEXT: ]
|
||||
// CHECK-NEXT: Recorded stack state: []
|
||||
// CHECK-LABEL: End Error in function require_match_2
|
||||
sil @require_match_2 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
%result = tuple ()
|
||||
return %result : $()
|
||||
}
|
||||
|
||||
// Check that such a join point is okay if it's a branch into a dead-end region.
|
||||
// CHECK-NOT: Begin Error in function merge_unreachable_okay_1
|
||||
sil @merge_unreachable_okay_1 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
unreachable
|
||||
}
|
||||
|
||||
// Same as above, just with the branches switched around.
|
||||
// CHECK-NOT: Begin Error in function merge_unreachable_okay_1
|
||||
sil @merge_unreachable_okay_2 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
unreachable
|
||||
}
|
||||
|
||||
// Check that it's not okay to subsequently dealloc the allocation.
|
||||
// CHECK-LABEL: Begin Error in function merge_unreachable_then_dealloc_1
|
||||
// CHECK: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
// CHECK-NEXT: Current stack state: []
|
||||
// CHECK-NEXT: Stack allocation:
|
||||
// CHECK-NEXT: %0 = alloc_stack $Builtin.Int32
|
||||
// CHECK-LABEL: End Error in function merge_unreachable_then_dealloc_1
|
||||
sil @merge_unreachable_then_dealloc_1 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %0
|
||||
unreachable
|
||||
}
|
||||
|
||||
// Same as above, just with the branches switched around.
|
||||
// CHECK-LABEL: Begin Error in function merge_unreachable_then_dealloc_2
|
||||
// CHECK: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
// CHECK-NEXT: Current stack state: []
|
||||
// CHECK-NEXT: Stack allocation:
|
||||
// CHECK-NEXT: %0 = alloc_stack $Builtin.Int32
|
||||
// CHECK-LABEL: End Error in function merge_unreachable_then_dealloc_2
|
||||
sil @merge_unreachable_then_dealloc_2 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb3:
|
||||
dealloc_stack %0
|
||||
unreachable
|
||||
}
|
||||
|
||||
// Parallel branches with inconsistent stack state into a dead-end loop
|
||||
// CHECK-NOT: Begin Error in function parallel_branches_into_dead_1
|
||||
sil @parallel_branches_into_dead_1 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Same as above, just with the dealloc switched around to trigger
|
||||
// a different visitation pattern.
|
||||
// CHECK-NOT: Begin Error in function parallel_branches_into_dead_2
|
||||
sil @parallel_branches_into_dead_2 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Add an unreachable block that also branches to the dead-end region to
|
||||
// make sure we don't fail to visit anything.
|
||||
// CHECK-NOT: Begin Error in function parallel_branches_into_dead_with_unreachable_block
|
||||
sil @parallel_branches_into_dead_with_unreachable_block : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
|
||||
bb5: // unreachable
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Parallel branches with inconsistent stack state into a dead-end loop
|
||||
// that contains a dealloc
|
||||
// CHECK-LABEL: Begin Error in function parallel_branches_into_dead_dealloc_1
|
||||
// CHECK-NEXT: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
sil @parallel_branches_into_dead_dealloc_1 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Same as above, just with the dealloc switched around to trigger
|
||||
// a different visitation pattern.
|
||||
// CHECK-LABEL: Begin Error in function parallel_branches_into_dead_dealloc_2
|
||||
// CHECK-NEXT: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
sil @parallel_branches_into_dead_dealloc_2 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Yet another visitation pattern.
|
||||
// CHECK-LABEL: Begin Error in function parallel_branches_into_dead_dealloc_3
|
||||
// CHECK-NEXT: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
sil @parallel_branches_into_dead_dealloc_3 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
}
|
||||
|
||||
// Yet another visitation pattern.
|
||||
// CHECK-LABEL: Begin Error in function parallel_branches_into_dead_dealloc_4
|
||||
// CHECK-NEXT: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
sil @parallel_branches_into_dead_dealloc_4 : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
dealloc_stack %0
|
||||
br bb3
|
||||
}
|
||||
|
||||
// And again, add an unreachable block.
|
||||
// CHECK-LABEL: Begin Error in function parallel_branches_into_dead_dealloc_with_unreachable_block
|
||||
// CHECK-NEXT: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
sil @parallel_branches_into_dead_dealloc_with_unreachable_block : $@convention(thin) () -> () {
|
||||
bb0:
|
||||
%0 = alloc_stack $Builtin.Int32
|
||||
cond_br undef, bb1, bb2
|
||||
|
||||
bb1:
|
||||
br bb3
|
||||
|
||||
bb2:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb3:
|
||||
dealloc_stack %0
|
||||
br bb4
|
||||
|
||||
bb4:
|
||||
br bb3
|
||||
|
||||
bb5: // unreachable
|
||||
br bb3
|
||||
}
|
||||
@@ -19,7 +19,10 @@ sil @alloc_pack_metadata_before_tuple : $@convention(thin) () -> () {
|
||||
}
|
||||
|
||||
// CHECK-LABEL: Begin Error in function dealloc_pack_metadata_with_bad_operand
|
||||
// CHECK: SIL verification failed: stack dealloc does not match most recent stack alloc:
|
||||
// CHECK: SIL verification failed: deallocating allocation that is not the top of the stack
|
||||
// CHECK-LABEL: End Error in function dealloc_pack_metadata_with_bad_operand
|
||||
// CHECK-LABEL: Begin Error in function dealloc_pack_metadata_with_bad_operand
|
||||
// CHECK: SIL verification failed: return with stack allocs that haven't been deallocated
|
||||
// CHECK-LABEL: End Error in function dealloc_pack_metadata_with_bad_operand
|
||||
// CHECK-LABEL: Begin Error in function dealloc_pack_metadata_with_bad_operand
|
||||
// CHECK: SIL verification failed: Must have alloc_pack_metadata operand
|
||||
|
||||
Reference in New Issue
Block a user