When hoisting/moving calls to locations, we strip unknown metadata. Such calls are usually marked `speculatable`, i.e. they are guaranteed to not cause undefined behaviour when run anywhere. So, we should strip attributes that can cause immediate undefined behaviour if those attributes are not valid in the context where the call is moved to. This patch introduces such an API and uses it in relevant passes. See updated tests. Fix for PR50744. Reviewed By: nikic, jdoerfert, lebedev.ri Differential Revision: https://reviews.llvm.org/D104641
73 lines
1.8 KiB
LLVM
73 lines
1.8 KiB
LLVM
; RUN: opt -S -simplifycfg -simplifycfg-require-and-preserve-domtree=1 < %s | FileCheck %s
|
|
|
|
; CHECK-LABEL: @speculatable_attribute
|
|
; CHECK: select
|
|
define i32 @speculatable_attribute(i32 %a) {
|
|
entry:
|
|
%c = icmp sgt i32 %a, 64
|
|
br i1 %c, label %end, label %if
|
|
|
|
if:
|
|
%val = call i32 @func() #0
|
|
br label %end
|
|
|
|
end:
|
|
%ret = phi i32 [%val, %if], [0, %entry]
|
|
ret i32 %ret
|
|
}
|
|
|
|
define i32 @func() #0 {
|
|
ret i32 1
|
|
}
|
|
|
|
; We should correctly drop the attribute since it may no longer be valid
|
|
; in the context the call is moved to.
|
|
; Since the function is speculatable, the nonnull attribute need not be dropped
|
|
; since it propagates poison (and call executes fine) if the parameter is indeed
|
|
; null.
|
|
define i32 @strip_attr(i32 * %p) {
|
|
; CHECK-LABEL: strip_attr
|
|
; CHECK-LABEL: entry:
|
|
; CHECK: %nullchk = icmp ne i32* %p, null
|
|
; CHECK: %val = call i32 @func_nonnull(i32* nonnull %p)
|
|
; CHECK: select
|
|
entry:
|
|
%nullchk = icmp ne i32* %p, null
|
|
br i1 %nullchk, label %if, label %end
|
|
|
|
if:
|
|
%val = call i32 @func_nonnull(i32* nonnull %p) #1
|
|
br label %end
|
|
|
|
end:
|
|
%ret = phi i32 [%val, %if], [0, %entry]
|
|
ret i32 %ret
|
|
}
|
|
|
|
; We should strip the deref attribute since it can cause UB when the
|
|
; speculatable call is moved.
|
|
define i32 @strip_attr2(i32 * %p) {
|
|
; CHECK-LABEL: strip_attr2
|
|
; CHECK-LABEL: entry:
|
|
; CHECK: %nullchk = icmp ne i32* %p, null
|
|
; CHECK: %val = call i32 @func_nonnull(i32* %p)
|
|
; CHECK: select
|
|
entry:
|
|
%nullchk = icmp ne i32* %p, null
|
|
br i1 %nullchk, label %if, label %end
|
|
|
|
if:
|
|
%val = call i32 @func_nonnull(i32* dereferenceable(12) %p) #1
|
|
br label %end
|
|
|
|
end:
|
|
%ret = phi i32 [%val, %if], [0, %entry]
|
|
ret i32 %ret
|
|
}
|
|
|
|
declare i32 @func_nonnull(i32*) #1
|
|
|
|
attributes #0 = { nounwind readnone speculatable }
|
|
attributes #1 = { nounwind argmemonly speculatable }
|
|
|