If the function is not assumed `noreturn` we should not wait for an
update to mark the call site as "may-return".
This has two kinds of consequences:
- We have less iterations in many tests.
- We have less deductions based on "known information" (since we ask
earlier, point 1, and therefore assumed information is not "known"
yet).
The latter is an artifact that we might want to tackle properly at some
point but which is not easily fixable right now.
100 lines
4.4 KiB
LLVM
100 lines
4.4 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes
|
|
; RUN: opt -attributor -enable-new-pm=0 -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=4 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM
|
|
; RUN: opt -attributor-cgscc -enable-new-pm=0 -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM
|
|
; PR36485
|
|
; musttail call result can't be replaced with a constant, unless the call can be removed
|
|
|
|
declare i32 @external()
|
|
|
|
define i8* @start(i8 %v) {
|
|
; IS__TUNIT____-LABEL: define {{[^@]+}}@start
|
|
; IS__TUNIT____-SAME: (i8 [[V:%.*]]) {
|
|
; IS__TUNIT____-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
|
|
; IS__TUNIT____-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
|
|
; IS__TUNIT____: true:
|
|
; IS__TUNIT____-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 [[V]])
|
|
; IS__TUNIT____-NEXT: ret i8* [[CA]]
|
|
; IS__TUNIT____: false:
|
|
; IS__TUNIT____-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
|
|
; IS__TUNIT____-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
|
|
; IS__TUNIT____: c2_true:
|
|
; IS__TUNIT____-NEXT: ret i8* null
|
|
; IS__TUNIT____: c2_false:
|
|
; IS__TUNIT____-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 undef)
|
|
; IS__TUNIT____-NEXT: ret i8* [[CA2]]
|
|
;
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@start
|
|
; IS__CGSCC____-SAME: (i8 [[V:%.*]]) {
|
|
; IS__CGSCC____-NEXT: [[C1:%.*]] = icmp eq i8 [[V]], 0
|
|
; IS__CGSCC____-NEXT: br i1 [[C1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
|
|
; IS__CGSCC____: true:
|
|
; IS__CGSCC____-NEXT: [[CA:%.*]] = musttail call i8* @side_effects(i8 [[V]])
|
|
; IS__CGSCC____-NEXT: ret i8* [[CA]]
|
|
; IS__CGSCC____: false:
|
|
; IS__CGSCC____-NEXT: [[C2:%.*]] = icmp eq i8 [[V]], 1
|
|
; IS__CGSCC____-NEXT: br i1 [[C2]], label [[C2_TRUE:%.*]], label [[C2_FALSE:%.*]]
|
|
; IS__CGSCC____: c2_true:
|
|
; IS__CGSCC____-NEXT: [[CA1:%.*]] = musttail call i8* @no_side_effects(i8 undef)
|
|
; IS__CGSCC____-NEXT: ret i8* [[CA1]]
|
|
; IS__CGSCC____: c2_false:
|
|
; IS__CGSCC____-NEXT: [[CA2:%.*]] = musttail call i8* @dont_zap_me(i8 undef)
|
|
; IS__CGSCC____-NEXT: ret i8* [[CA2]]
|
|
;
|
|
%c1 = icmp eq i8 %v, 0
|
|
br i1 %c1, label %true, label %false
|
|
true:
|
|
; FIXME: propagate the value information for %v
|
|
%ca = musttail call i8* @side_effects(i8 %v)
|
|
ret i8* %ca
|
|
false:
|
|
%c2 = icmp eq i8 %v, 1
|
|
br i1 %c2, label %c2_true, label %c2_false
|
|
c2_true:
|
|
%ca1 = musttail call i8* @no_side_effects(i8 %v)
|
|
; FIXME: zap this call
|
|
ret i8* %ca1
|
|
c2_false:
|
|
%ca2 = musttail call i8* @dont_zap_me(i8 %v)
|
|
ret i8* %ca2
|
|
}
|
|
|
|
define internal i8* @side_effects(i8 %v) {
|
|
; CHECK-LABEL: define {{[^@]+}}@side_effects
|
|
; CHECK-SAME: (i8 [[V:%.*]]) {
|
|
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
|
|
; CHECK-NEXT: [[CA:%.*]] = musttail call i8* @start(i8 [[V]])
|
|
; CHECK-NEXT: ret i8* [[CA]]
|
|
;
|
|
%i1 = call i32 @external()
|
|
|
|
; since this goes back to `start` the SCPP should be see that the return value
|
|
; is always `null`.
|
|
; The call can't be removed due to `external` call above, though.
|
|
|
|
%ca = musttail call i8* @start(i8 %v)
|
|
|
|
; Thus the result must be returned anyway
|
|
ret i8* %ca
|
|
}
|
|
|
|
define internal i8* @no_side_effects(i8 %v) readonly nounwind {
|
|
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
|
|
; IS__CGSCC____-LABEL: define {{[^@]+}}@no_side_effects
|
|
; IS__CGSCC____-SAME: (i8 [[V:%.*]]) [[ATTR0:#.*]] {
|
|
; IS__CGSCC____-NEXT: ret i8* undef
|
|
;
|
|
ret i8* null
|
|
}
|
|
|
|
define internal i8* @dont_zap_me(i8 %v) {
|
|
; CHECK-LABEL: define {{[^@]+}}@dont_zap_me
|
|
; CHECK-SAME: (i8 [[V:%.*]]) {
|
|
; CHECK-NEXT: [[I1:%.*]] = call i32 @external()
|
|
; CHECK-NEXT: ret i8* undef
|
|
;
|
|
%i1 = call i32 @external()
|
|
ret i8* null
|
|
}
|