Files
revng-revng/tests/unit/llvm_lit_tests/EnforceSingleExit.ll
2025-04-30 16:10:54 +02:00

271 lines
5.6 KiB
LLVM

;
; This file is distributed under the MIT License. See LICENSE.md for details.
;
; RUN: %revngopt %s -enforce-single-exit -S -o - | FileCheck %s
; function tags metadata needed for all the tests
declare !revng.tags !0 void @scope_closer(ptr)
declare !revng.tags !1 void @goto_block()
!0 = !{!"marker", !"scope-closer"}
!1 = !{!"marker", !"goto-block"}
; two trivial exits test
define void @f() {
block_a:
br i1 undef, label %block_b, label %block_c
block_b:
ret void
block_c:
br i1 undef, label %block_b, label %block_d
block_d:
ret void
}
; CHECK-LABEL: define void @f
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_c
; CHECK: block_b:
; CHECK-NEXT: ret void
; CHECK: block_c:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_d
; CHECK: block_d:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@f, %block_b))
; CHECK-NEXT: ret void
; one trivial, one non-trivial exit test
define void @g() {
block_a:
br i1 undef, label %block_b, label %block_c
block_b:
ret void
block_c:
br label %block_d
block_d:
br label %block_c
}
; CHECK-LABEL: define void @g
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_c
; CHECK: block_b:
; CHECK-NEXT: ret void
; CHECK: block_c:
; CHECK-NEXT: br label %block_d
; CHECK: block_d:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@g, %block_b))
; CHECK-NEXT: br label %block_c
; one trivial, one non-trivial exit (self loop) test
define void @h() {
block_a:
br i1 undef, label %block_b, label %block_c
block_b:
ret void
block_c:
br label %block_c
}
; CHECK-LABEL: define void @h
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_c
; CHECK: block_b:
; CHECK-NEXT: ret void
; CHECK: block_c:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@h, %block_b))
; CHECK-NEXT: br label %block_c
; two trivial exit, with one scope_closer edge already present test
define void @i() {
block_a:
br i1 undef, label %block_b, label %block_c
block_b:
ret void
block_c:
call void @scope_closer(ptr blockaddress(@i, %block_b))
br label %block_d
block_d:
ret void
}
; CHECK-LABEL: define void @i
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_c
; CHECK: block_b:
; CHECK-NEXT: ret void
; CHECK: block_c:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@i, %block_b))
; CHECK-NEXT: br label %block_d
; CHECK: block_d:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@i, %block_b))
; CHECK-NEXT: ret void
; SCC composed by a `scope_closer` edge test
define void @l() {
block_a:
br i1 undef, label %block_c, label %block_b
block_b:
br i1 undef, label %block_e, label %block_d
block_c:
call void @scope_closer(ptr blockaddress(@l, %block_d))
unreachable
block_d:
br label %block_c
block_e:
ret void
}
; CHECK-LABEL: define void @l
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_c, label %block_b
; CHECK: block_b:
; CHECK-NEXT: br i1 undef, label %block_e, label %block_d
; CHECK: block_c:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@l, %block_d))
; CHECK-NEXT: unreachable
; CHECK: block_d:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@l, %block_e))
; CHECK-NEXT: br label %block_c
; CHECK: block_e:
; CHECK-NEXT: ret void
; no trivial exit, one non-trivial exit
define void @m() {
block_a:
br label %block_b
block_b:
br label %block_c
block_c:
br label %block_b
}
; CHECK-LABEL: define void @m
; CHECK: new_entry_block:
; CHECK-NEXT: br i1 true, label %block_a, label %sink_block
; CHECK: block_a:
; CHECK-NEXT: br label %block_b
; CHECK: block_b:
; CHECK-NEXT: br label %block_c
; CHECK: block_c:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@m, %sink_block))
; CHECK-NEXT: br label %block_b
; CHECK: sink_block:
; CHECK-NEXT: unreachable
; two trivial exits
define void @n() {
block_a:
br i1 true, label %block_b, label %block_d
block_b:
br label %block_c
block_c:
br label %block_b
block_d:
br label %block_e
block_e:
br label %block_d
}
; CHECK-LABEL: define void @n
; CHECK: new_entry_block:
; CHECK-NEXT: br i1 true, label %block_a, label %sink_block
; CHECK: block_a:
; CHECK-NEXT: br i1 true, label %block_b, label %block_d
; CHECK: block_b:
; CHECK-NEXT: br label %block_c
; CHECK: block_c:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@n, %sink_block))
; CHECK-NEXT: br label %block_b
; CHECK: block_d:
; CHECK-NEXT: br label %block_e
; CHECK: block_e:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@n, %sink_block))
; CHECK-NEXT: br label %block_d
; CHECK: sink_block:
; CHECK-NEXT: unreachable
; one trivial exit, no modification test
define void @o() {
block_a:
br i1 undef, label %block_b, label %block_c
block_b:
br label %block_d
block_c:
br label %block_d
block_d:
ret void
}
; CHECK-LABEL: define void @o
; CHECK: block_a:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_c
; CHECK: block_b:
; CHECK-NEXT: br label %block_d
; CHECK: block_c:
; CHECK-NEXT: br label %block_d
; CHECK: block_d:
; CHECK-NEXT: ret void
; two nested sccs
define void @p() {
block_a:
br label %block_b
block_b:
br label %block_c
block_c:
br i1 undef, label %block_b, label %block_d
block_d:
br label %block_b
}
; CHECK-LABEL: define void @p
; CHECK: new_entry_block:
; CHECK-NEXT: br i1 true, label %block_a, label %sink_block
; CHECK: block_a:
; CHECK-NEXT: br label %block_b
; CHECK: block_b:
; CHECK-NEXT: br label %block_c
; CHECK: block_c:
; CHECK-NEXT: br i1 undef, label %block_b, label %block_d
; CHECK: block_d:
; CHECK-NEXT: call void @scope_closer(ptr blockaddress(@p, %sink_block))
; CHECK-NEXT: br label %block_b
; CHECK: sink_block:
; CHECK-NEXT: unreachable