This switches everything to use the memory attribute proposed in https://discourse.llvm.org/t/rfc-unify-memory-effect-attributes/65579. The old argmemonly, inaccessiblememonly and inaccessiblemem_or_argmemonly attributes are dropped. The readnone, readonly and writeonly attributes are restricted to parameters only. The old attributes are auto-upgraded both in bitcode and IR. The bitcode upgrade is a policy requirement that has to be retained indefinitely. The IR upgrade is mainly there so it's not necessary to update all tests using memory attributes in this patch, which is already large enough. We could drop that part after migrating tests, or retain it longer term, to make it easier to import IR from older LLVM versions. High-level Function/CallBase APIs like doesNotAccessMemory() or setDoesNotAccessMemory() are mapped transparently to the memory attribute. Code that directly manipulates attributes (e.g. via AttributeList) on the other hand needs to switch to working with the memory attribute instead. Differential Revision: https://reviews.llvm.org/D135780
1363 lines
49 KiB
LLVM
1363 lines
49 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=13 -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT
|
|
; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC
|
|
|
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
|
declare void @f(i32)
|
|
declare token @llvm.call.preallocated.setup(i32)
|
|
declare i8* @llvm.call.preallocated.arg(token, i32)
|
|
|
|
@ConstAS3Ptr = addrspace(3) global i32 0, align 4
|
|
|
|
;.
|
|
; CHECK: @[[CONSTAS3PTR:[a-zA-Z0-9_$"\\.-]+]] = addrspace(3) global i32 0, align 4
|
|
; CHECK: @[[S:[a-zA-Z0-9_$"\\.-]+]] = external global [[STRUCT_X:%.*]]
|
|
; CHECK: @[[G:[a-zA-Z0-9_$"\\.-]+]] = internal constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (void (i8***)* @f1 to i8*), i8* bitcast (void (i1 (i8*)*)* @f2 to i8*)] }
|
|
;.
|
|
define internal i32 addrspace(3)* @const_ptr_return_as3() {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return_as3
|
|
; CGSCC-SAME: () #[[ATTR1:[0-9]+]] {
|
|
; CGSCC-NEXT: ret i32 addrspace(3)* @ConstAS3Ptr
|
|
;
|
|
ret i32 addrspace(3)* @ConstAS3Ptr
|
|
}
|
|
define internal i32* @const_ptr_return() {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@const_ptr_return
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: ret i32* addrspacecast (i32 addrspace(3)* @ConstAS3Ptr to i32*)
|
|
;
|
|
ret i32* addrspacecast (i32 addrspace(3)* @ConstAS3Ptr to i32*)
|
|
}
|
|
|
|
; Test1: Replace argument with constant
|
|
define internal void @test1(i32 %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@test1() {
|
|
; CHECK-NEXT: tail call void @f(i32 noundef 1)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
tail call void @f(i32 %a)
|
|
ret void
|
|
}
|
|
|
|
define void @test1_helper() {
|
|
; CHECK-LABEL: define {{[^@]+}}@test1_helper() {
|
|
; CHECK-NEXT: tail call void @test1()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
tail call void @test1(i32 1)
|
|
ret void
|
|
}
|
|
|
|
; TEST 2 : Simplify return value
|
|
define i32 @return0() {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@return0
|
|
; CHECK-SAME: () #[[ATTR1:[0-9]+]] {
|
|
; CHECK-NEXT: ret i32 0
|
|
;
|
|
ret i32 0
|
|
}
|
|
|
|
define i32 @return1() {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@return1
|
|
; CHECK-SAME: () #[[ATTR1]] {
|
|
; CHECK-NEXT: ret i32 1
|
|
;
|
|
ret i32 1
|
|
}
|
|
|
|
define i32 @test2_1(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test2_1
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; TUNIT: if.true:
|
|
; TUNIT-NEXT: [[RET0:%.*]] = add i32 0, 1
|
|
; TUNIT-NEXT: br label [[END:%.*]]
|
|
; TUNIT: if.false:
|
|
; TUNIT-NEXT: br label [[END]]
|
|
; TUNIT: end:
|
|
; TUNIT-NEXT: [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
|
|
; TUNIT-NEXT: ret i32 1
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test2_1
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CGSCC: if.true:
|
|
; CGSCC-NEXT: [[CALL:%.*]] = tail call i32 @return0() #[[ATTR12:[0-9]+]]
|
|
; CGSCC-NEXT: [[RET0:%.*]] = add i32 [[CALL]], 1
|
|
; CGSCC-NEXT: br label [[END:%.*]]
|
|
; CGSCC: if.false:
|
|
; CGSCC-NEXT: [[RET1:%.*]] = tail call i32 @return1() #[[ATTR12]]
|
|
; CGSCC-NEXT: br label [[END]]
|
|
; CGSCC: end:
|
|
; CGSCC-NEXT: [[RET:%.*]] = phi i32 [ [[RET0]], [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
|
|
; CGSCC-NEXT: ret i32 1
|
|
;
|
|
br i1 %c, label %if.true, label %if.false
|
|
if.true:
|
|
%call = tail call i32 @return0()
|
|
%ret0 = add i32 %call, 1
|
|
br label %end
|
|
if.false:
|
|
%ret1 = tail call i32 @return1()
|
|
br label %end
|
|
end:
|
|
|
|
%ret = phi i32 [ %ret0, %if.true ], [ %ret1, %if.false ]
|
|
|
|
ret i32 1
|
|
}
|
|
|
|
|
|
|
|
define i32 @test2_2(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test2_2
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i32 1
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test2_2
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[RET:%.*]] = tail call noundef i32 @test2_1(i1 [[C]]) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32 [[RET]]
|
|
;
|
|
%ret = tail call i32 @test2_1(i1 %c)
|
|
ret i32 %ret
|
|
}
|
|
|
|
declare void @use(i32)
|
|
define void @test3(i1 %c) {
|
|
; TUNIT-LABEL: define {{[^@]+}}@test3
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) {
|
|
; TUNIT-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; TUNIT: if.true:
|
|
; TUNIT-NEXT: br label [[END:%.*]]
|
|
; TUNIT: if.false:
|
|
; TUNIT-NEXT: br label [[END]]
|
|
; TUNIT: end:
|
|
; TUNIT-NEXT: [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
|
|
; TUNIT-NEXT: tail call void @use(i32 noundef 1)
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@test3
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CGSCC: if.true:
|
|
; CGSCC-NEXT: br label [[END:%.*]]
|
|
; CGSCC: if.false:
|
|
; CGSCC-NEXT: [[RET1:%.*]] = tail call i32 @return1() #[[ATTR12]]
|
|
; CGSCC-NEXT: br label [[END]]
|
|
; CGSCC: end:
|
|
; CGSCC-NEXT: [[R:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ [[RET1]], [[IF_FALSE]] ]
|
|
; CGSCC-NEXT: tail call void @use(i32 noundef [[R]])
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
br i1 %c, label %if.true, label %if.false
|
|
if.true:
|
|
br label %end
|
|
if.false:
|
|
%ret1 = tail call i32 @return1()
|
|
br label %end
|
|
end:
|
|
|
|
%r = phi i32 [ 1, %if.true ], [ %ret1, %if.false ]
|
|
|
|
tail call void @use(i32 %r)
|
|
ret void
|
|
}
|
|
|
|
define void @test-select-phi(i1 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@test-select-phi
|
|
; CHECK-SAME: (i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: tail call void @use(i32 noundef 1)
|
|
; CHECK-NEXT: [[SELECT_NOT_SAME:%.*]] = select i1 [[C]], i32 1, i32 0
|
|
; CHECK-NEXT: tail call void @use(i32 noundef [[SELECT_NOT_SAME]])
|
|
; CHECK-NEXT: br i1 [[C]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]]
|
|
; CHECK: if-true:
|
|
; CHECK-NEXT: br label [[END:%.*]]
|
|
; CHECK: if-false:
|
|
; CHECK-NEXT: br label [[END]]
|
|
; CHECK: end:
|
|
; CHECK-NEXT: [[PHI_SAME:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[PHI_NOT_SAME:%.*]] = phi i32 [ 0, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[PHI_SAME_PROP:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ 1, [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[PHI_SAME_UNDEF:%.*]] = phi i32 [ 1, [[IF_TRUE]] ], [ undef, [[IF_FALSE]] ]
|
|
; CHECK-NEXT: [[SELECT_NOT_SAME_UNDEF:%.*]] = select i1 [[C]], i32 [[PHI_NOT_SAME]], i32 undef
|
|
; CHECK-NEXT: tail call void @use(i32 noundef 1)
|
|
; CHECK-NEXT: tail call void @use(i32 noundef [[PHI_NOT_SAME]])
|
|
; CHECK-NEXT: tail call void @use(i32 noundef 1)
|
|
; CHECK-NEXT: tail call void @use(i32 1)
|
|
; CHECK-NEXT: tail call void @use(i32 [[SELECT_NOT_SAME_UNDEF]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%select-same = select i1 %c, i32 1, i32 1
|
|
tail call void @use(i32 %select-same)
|
|
|
|
%select-not-same = select i1 %c, i32 1, i32 0
|
|
tail call void @use(i32 %select-not-same)
|
|
br i1 %c, label %if-true, label %if-false
|
|
if-true:
|
|
br label %end
|
|
if-false:
|
|
br label %end
|
|
end:
|
|
%phi-same = phi i32 [ 1, %if-true ], [ 1, %if-false ]
|
|
%phi-not-same = phi i32 [ 0, %if-true ], [ 1, %if-false ]
|
|
%phi-same-prop = phi i32 [ 1, %if-true ], [ %select-same, %if-false ]
|
|
%phi-same-undef = phi i32 [ 1, %if-true ], [ undef, %if-false ]
|
|
%select-not-same-undef = select i1 %c, i32 %phi-not-same, i32 undef
|
|
|
|
|
|
tail call void @use(i32 %phi-same)
|
|
|
|
tail call void @use(i32 %phi-not-same)
|
|
|
|
tail call void @use(i32 %phi-same-prop)
|
|
|
|
tail call void @use(i32 %phi-same-undef)
|
|
|
|
tail call void @use(i32 %select-not-same-undef)
|
|
|
|
ret void
|
|
|
|
}
|
|
|
|
define i32 @ipccp1(i32 %a) {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@ipccp1
|
|
; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[F:%.*]]
|
|
; CHECK: t:
|
|
; CHECK-NEXT: ret i32 [[A]]
|
|
; CHECK: f:
|
|
; CHECK-NEXT: unreachable
|
|
;
|
|
br i1 true, label %t, label %f
|
|
t:
|
|
ret i32 %a
|
|
f:
|
|
%r = call i32 @ipccp1(i32 5)
|
|
ret i32 %r
|
|
}
|
|
|
|
define internal i1 @ipccp2i(i1 %a) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp2i
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: br label [[T:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: ret i1 true
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: unreachable
|
|
;
|
|
br i1 %a, label %t, label %f
|
|
t:
|
|
ret i1 %a
|
|
f:
|
|
%r = call i1 @ipccp2i(i1 false)
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @ipccp2() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@ipccp2
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i1 true
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp2
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[R:%.*]] = call noundef i1 @ipccp2i() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[R]]
|
|
;
|
|
%r = call i1 @ipccp2i(i1 true)
|
|
ret i1 %r
|
|
}
|
|
|
|
define internal i1 @ipccp2ib(i1 %a) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp2ib
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: br label [[T:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: ret i1 true
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: unreachable
|
|
;
|
|
br i1 %a, label %t, label %f
|
|
t:
|
|
ret i1 true
|
|
f:
|
|
%r = call i1 @ipccp2ib(i1 false)
|
|
ret i1 %r
|
|
}
|
|
|
|
define i1 @ipccp2b() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@ipccp2b
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i1 true
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp2b
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[R:%.*]] = call noundef i1 @ipccp2ib() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[R]]
|
|
;
|
|
%r = call i1 @ipccp2ib(i1 true)
|
|
ret i1 %r
|
|
}
|
|
|
|
define internal i32 @ipccp3i(i32 %a) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp3i
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: br label [[T:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: ret i32 7
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: unreachable
|
|
;
|
|
%c = icmp eq i32 %a, 7
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
ret i32 %a
|
|
f:
|
|
%r = call i32 @ipccp3i(i32 5)
|
|
ret i32 %r
|
|
}
|
|
|
|
define i32 @ipccp3() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@ipccp3
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i32 7
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp3
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[R:%.*]] = call noundef i32 @ipccp3i() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32 [[R]]
|
|
;
|
|
%r = call i32 @ipccp3i(i32 7)
|
|
ret i32 %r
|
|
}
|
|
|
|
define internal i32 @ipccp4ia(i1 %c) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp4ia
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: ret i32 0
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: ret i32 1
|
|
;
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
ret i32 0
|
|
f:
|
|
ret i32 1
|
|
}
|
|
define internal i32 @ipccp4ib(i32 %a) {
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp4ib
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: br label [[T:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: [[R:%.*]] = call noundef i32 @ipccp4ia(i1 noundef true) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32 [[R]]
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: unreachable
|
|
;
|
|
%c = icmp eq i32 %a, 7
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
%r = call i32 @ipccp4ia(i1 %c)
|
|
ret i32 %r
|
|
f:
|
|
ret i32 1
|
|
}
|
|
|
|
define i32 @ipccp4(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@ipccp4
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; TUNIT: t:
|
|
; TUNIT-NEXT: br label [[F]]
|
|
; TUNIT: f:
|
|
; TUNIT-NEXT: ret i32 0
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ipccp4
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: br label [[F]]
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: [[R:%.*]] = call noundef i32 @ipccp4ib() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32 [[R]]
|
|
;
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
%q = call i32 @ipccp4ia(i1 undef)
|
|
br label %f
|
|
f:
|
|
%r = call i32 @ipccp4ib(i32 7)
|
|
ret i32 %r
|
|
}
|
|
|
|
; Do not touch complicated arguments (for now)
|
|
%struct.X = type { i8* }
|
|
define internal i32* @test_inalloca(i32* inalloca(i32) %a) {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@test_inalloca
|
|
; CHECK-SAME: (i32* noalias nofree nonnull returned writeonly inalloca(i32) dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: ret i32* [[A]]
|
|
;
|
|
ret i32* %a
|
|
}
|
|
define i32* @complicated_args_inalloca(i32* %arg) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_inalloca
|
|
; TUNIT-SAME: (i32* nofree readnone "no-capture-maybe-returned" [[ARG:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: [[CALL:%.*]] = call nonnull dereferenceable(4) i32* @test_inalloca(i32* noalias nofree writeonly inalloca(i32) "no-capture-maybe-returned" [[ARG]]) #[[ATTR9:[0-9]+]]
|
|
; TUNIT-NEXT: ret i32* [[CALL]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_inalloca
|
|
; CGSCC-SAME: (i32* nofree noundef nonnull readnone dereferenceable(4) [[ARG:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call noalias nonnull dereferenceable(4) i32* @test_inalloca(i32* noalias nofree noundef nonnull writeonly inalloca(i32) dereferenceable(4) [[ARG]]) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32* [[CALL]]
|
|
;
|
|
%call = call i32* @test_inalloca(i32* inalloca(i32) %arg)
|
|
ret i32* %call
|
|
}
|
|
|
|
define internal i32* @test_preallocated(i32* preallocated(i32) %a) {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@test_preallocated
|
|
; CHECK-SAME: (i32* noalias nofree noundef nonnull returned writeonly preallocated(i32) align 4294967296 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: ret i32* [[A]]
|
|
;
|
|
ret i32* %a
|
|
}
|
|
define i32* @complicated_args_preallocated() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_preallocated
|
|
; TUNIT-SAME: () #[[ATTR2:[0-9]+]] {
|
|
; TUNIT-NEXT: [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR10:[0-9]+]]
|
|
; TUNIT-NEXT: [[CALL:%.*]] = call noundef nonnull align 4294967296 dereferenceable(4) i32* @test_preallocated(i32* noalias nocapture nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR9]] [ "preallocated"(token [[C]]) ]
|
|
; TUNIT-NEXT: ret i32* [[CALL]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_preallocated
|
|
; CGSCC-SAME: () #[[ATTR3:[0-9]+]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call token @llvm.call.preallocated.setup(i32 noundef 1) #[[ATTR12]]
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call i32* @test_preallocated(i32* noalias nocapture nofree noundef writeonly preallocated(i32) align 4294967296 null) #[[ATTR13:[0-9]+]] [ "preallocated"(token [[C]]) ]
|
|
; CGSCC-NEXT: ret i32* null
|
|
;
|
|
%c = call token @llvm.call.preallocated.setup(i32 1)
|
|
%call = call i32* @test_preallocated(i32* preallocated(i32) null) ["preallocated"(token %c)]
|
|
ret i32* %call
|
|
}
|
|
|
|
define internal void @test_sret(%struct.X* sret(%struct.X) %a, %struct.X** %b) {
|
|
;
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_sret
|
|
; TUNIT-SAME: (%struct.X* noalias nofree noundef nonnull writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR3:[0-9]+]] {
|
|
; TUNIT-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_sret
|
|
; CGSCC-SAME: (%struct.X* noalias nofree noundef nonnull writeonly sret([[STRUCT_X:%.*]]) align 4294967296 dereferenceable(8) [[A:%.*]], %struct.X** nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR4:[0-9]+]] {
|
|
; CGSCC-NEXT: store %struct.X* [[A]], %struct.X** [[B]], align 8
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
store %struct.X* %a, %struct.X** %b
|
|
ret void
|
|
}
|
|
; FIXME: Alignment and dereferenceability are not propagated to the argument
|
|
define void @complicated_args_sret(%struct.X** %b) {
|
|
;
|
|
;
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_sret
|
|
; TUNIT-SAME: (%struct.X** nocapture nofree writeonly [[B:%.*]]) #[[ATTR3]] {
|
|
; TUNIT-NEXT: call void @test_sret(%struct.X* noalias nocapture nofree noundef writeonly sret([[STRUCT_X:%.*]]) align 4294967296 null, %struct.X** nocapture nofree writeonly align 8 [[B]]) #[[ATTR9]]
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(argmem: write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_sret
|
|
; CGSCC-SAME: (%struct.X** nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[B:%.*]]) #[[ATTR5:[0-9]+]] {
|
|
; CGSCC-NEXT: unreachable
|
|
;
|
|
call void @test_sret(%struct.X* sret(%struct.X) null, %struct.X** %b)
|
|
ret void
|
|
}
|
|
|
|
define internal %struct.X* @test_nest(%struct.X* nest %a) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_nest
|
|
; CGSCC-SAME: (%struct.X* nest noalias nocapture nofree readnone align 4294967296 [[A:%.*]]) #[[ATTR1]] {
|
|
; CGSCC-NEXT: ret %struct.X* null
|
|
;
|
|
ret %struct.X* %a
|
|
}
|
|
define %struct.X* @complicated_args_nest() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_nest
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret %struct.X* null
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_nest
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call noalias noundef align 4294967296 %struct.X* @test_nest(%struct.X* noalias nocapture nofree noundef readnone align 4294967296 null) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret %struct.X* [[CALL]]
|
|
;
|
|
%call = call %struct.X* @test_nest(%struct.X* null)
|
|
ret %struct.X* %call
|
|
}
|
|
|
|
@S = external global %struct.X
|
|
define internal void @test_byval(%struct.X* byval(%struct.X) %a) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_byval
|
|
; TUNIT-SAME: (i8* [[TMP0:%.*]]) #[[ATTR3]] {
|
|
; TUNIT-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
|
|
; TUNIT-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.X* [[A_PRIV]] to i8**
|
|
; TUNIT-NEXT: store i8* [[TMP0]], i8** [[A_PRIV_CAST]], align 8
|
|
; TUNIT-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X]], %struct.X* [[A_PRIV]], i32 0, i32 0
|
|
; TUNIT-NEXT: store i8* null, i8** [[G0]], align 8
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_byval
|
|
; CGSCC-SAME: (i8* [[TMP0:%.*]]) #[[ATTR4]] {
|
|
; CGSCC-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
|
|
; CGSCC-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.X* [[A_PRIV]] to i8**
|
|
; CGSCC-NEXT: store i8* [[TMP0]], i8** [[A_PRIV_CAST]], align 8
|
|
; CGSCC-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X]], %struct.X* [[A_PRIV]], i32 0, i32 0
|
|
; CGSCC-NEXT: store i8* null, i8** [[G0]], align 8
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
%g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0
|
|
store i8* null, i8** %g0
|
|
ret void
|
|
}
|
|
define void @complicated_args_byval() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval
|
|
; TUNIT-SAME: () #[[ATTR4:[0-9]+]] {
|
|
; TUNIT-NEXT: [[S_CAST:%.*]] = bitcast %struct.X* @S to i8**
|
|
; TUNIT-NEXT: [[TMP1:%.*]] = load i8*, i8** [[S_CAST]], align 8
|
|
; TUNIT-NEXT: call void @test_byval(i8* [[TMP1]]) #[[ATTR9]]
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval
|
|
; CGSCC-SAME: () #[[ATTR3]] {
|
|
; CGSCC-NEXT: [[TMP1:%.*]] = load i8*, i8** getelementptr inbounds ([[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0), align 8
|
|
; CGSCC-NEXT: call void @test_byval(i8* nofree writeonly [[TMP1]]) #[[ATTR13]]
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
call void @test_byval(%struct.X* byval(%struct.X) @S)
|
|
ret void
|
|
}
|
|
|
|
declare void @sync()
|
|
; Make sure we *do not* load @S here!
|
|
define internal i8*@test_byval2(%struct.X* byval(%struct.X) %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@test_byval2
|
|
; CHECK-SAME: (i8* [[TMP0:%.*]]) {
|
|
; CHECK-NEXT: [[A_PRIV:%.*]] = alloca [[STRUCT_X:%.*]], align 8
|
|
; CHECK-NEXT: [[A_PRIV_CAST:%.*]] = bitcast %struct.X* [[A_PRIV]] to i8**
|
|
; CHECK-NEXT: store i8* [[TMP0]], i8** [[A_PRIV_CAST]], align 8
|
|
; CHECK-NEXT: call void @sync()
|
|
; CHECK-NEXT: [[G0:%.*]] = getelementptr [[STRUCT_X]], %struct.X* [[A_PRIV]], i32 0, i32 0
|
|
; CHECK-NEXT: [[L:%.*]] = load i8*, i8** [[G0]], align 8
|
|
; CHECK-NEXT: ret i8* [[L]]
|
|
;
|
|
call void @sync()
|
|
%g0 = getelementptr %struct.X, %struct.X* %a, i32 0, i32 0
|
|
%l = load i8*, i8** %g0
|
|
ret i8* %l
|
|
}
|
|
define i8* @complicated_args_byval2() {
|
|
;
|
|
; TUNIT-LABEL: define {{[^@]+}}@complicated_args_byval2() {
|
|
; TUNIT-NEXT: [[S_CAST:%.*]] = bitcast %struct.X* @S to i8**
|
|
; TUNIT-NEXT: [[TMP1:%.*]] = load i8*, i8** [[S_CAST]], align 8
|
|
; TUNIT-NEXT: [[C:%.*]] = call i8* @test_byval2(i8* [[TMP1]])
|
|
; TUNIT-NEXT: ret i8* [[C]]
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@complicated_args_byval2() {
|
|
; CGSCC-NEXT: [[TMP1:%.*]] = load i8*, i8** getelementptr inbounds ([[STRUCT_X:%.*]], %struct.X* @S, i32 0, i32 0), align 8
|
|
; CGSCC-NEXT: [[C:%.*]] = call i8* @test_byval2(i8* [[TMP1]])
|
|
; CGSCC-NEXT: ret i8* [[C]]
|
|
;
|
|
%c = call i8* @test_byval2(%struct.X* byval(%struct.X) @S)
|
|
ret i8* %c
|
|
}
|
|
|
|
define void @fixpoint_changed(i32* %p) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@fixpoint_changed
|
|
; TUNIT-SAME: (i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR3]] {
|
|
; TUNIT-NEXT: entry:
|
|
; TUNIT-NEXT: br label [[FOR_COND:%.*]]
|
|
; TUNIT: for.cond:
|
|
; TUNIT-NEXT: [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
|
|
; TUNIT-NEXT: [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
|
|
; TUNIT-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
|
|
; TUNIT: for.body:
|
|
; TUNIT-NEXT: switch i32 [[J_0]], label [[SW_EPILOG]] [
|
|
; TUNIT-NEXT: i32 1, label [[SW_BB:%.*]]
|
|
; TUNIT-NEXT: ]
|
|
; TUNIT: sw.bb:
|
|
; TUNIT-NEXT: br label [[SW_EPILOG]]
|
|
; TUNIT: sw.epilog:
|
|
; TUNIT-NEXT: [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
|
|
; TUNIT-NEXT: store i32 [[X_0]], i32* [[P]], align 4
|
|
; TUNIT-NEXT: [[INC]] = add nsw i32 [[J_0]], 1
|
|
; TUNIT-NEXT: br label [[FOR_COND]]
|
|
; TUNIT: for.end:
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@fixpoint_changed
|
|
; CGSCC-SAME: (i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR4]] {
|
|
; CGSCC-NEXT: entry:
|
|
; CGSCC-NEXT: br label [[FOR_COND:%.*]]
|
|
; CGSCC: for.cond:
|
|
; CGSCC-NEXT: [[J_0:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[INC:%.*]], [[SW_EPILOG:%.*]] ]
|
|
; CGSCC-NEXT: [[CMP:%.*]] = icmp slt i32 [[J_0]], 30
|
|
; CGSCC-NEXT: br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
|
|
; CGSCC: for.body:
|
|
; CGSCC-NEXT: switch i32 [[J_0]], label [[SW_EPILOG]] [
|
|
; CGSCC-NEXT: i32 1, label [[SW_BB:%.*]]
|
|
; CGSCC-NEXT: ]
|
|
; CGSCC: sw.bb:
|
|
; CGSCC-NEXT: br label [[SW_EPILOG]]
|
|
; CGSCC: sw.epilog:
|
|
; CGSCC-NEXT: [[X_0:%.*]] = phi i32 [ 255, [[FOR_BODY]] ], [ 253, [[SW_BB]] ]
|
|
; CGSCC-NEXT: store i32 [[X_0]], i32* [[P]], align 4
|
|
; CGSCC-NEXT: [[INC]] = add nsw i32 [[J_0]], 1
|
|
; CGSCC-NEXT: br label [[FOR_COND]]
|
|
; CGSCC: for.end:
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %for.cond
|
|
|
|
for.cond:
|
|
%j.0 = phi i32 [ 0, %entry ], [ %inc, %sw.epilog ]
|
|
%cmp = icmp slt i32 %j.0, 30
|
|
br i1 %cmp, label %for.body, label %for.end
|
|
|
|
for.body:
|
|
switch i32 %j.0, label %sw.epilog [
|
|
i32 1, label %sw.bb
|
|
]
|
|
|
|
sw.bb:
|
|
br label %sw.epilog
|
|
|
|
sw.epilog:
|
|
%x.0 = phi i32 [ 255, %for.body ], [ 253, %sw.bb ]
|
|
store i32 %x.0, i32* %p
|
|
%inc = add nsw i32 %j.0, 1
|
|
br label %for.cond
|
|
|
|
for.end:
|
|
ret void
|
|
}
|
|
|
|
; Check we merge undef and a constant properly.
|
|
define i8 @caller0() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller0
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller0
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 undef)
|
|
ret i8 %c
|
|
}
|
|
define i8 @caller1() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller1
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller1
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 undef)
|
|
ret i8 %c
|
|
}
|
|
define i8 @caller2() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller2
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller2
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 undef)
|
|
ret i8 %c
|
|
}
|
|
define i8 @caller_middle() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller_middle
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller_middle
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 42)
|
|
ret i8 %c
|
|
}
|
|
define i8 @caller3() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller3
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller3
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 undef)
|
|
ret i8 %c
|
|
}
|
|
define i8 @caller4() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@caller4
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i8 49
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@caller4
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i8 @callee() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i8 [[C]]
|
|
;
|
|
%c = call i8 @callee(i8 undef)
|
|
ret i8 %c
|
|
}
|
|
define internal i8 @callee(i8 %a) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@callee
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: ret i8 49
|
|
;
|
|
%c = add i8 %a, 7
|
|
ret i8 %c
|
|
}
|
|
|
|
define void @user_as3() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@user_as3
|
|
; TUNIT-SAME: () #[[ATTR4]] {
|
|
; TUNIT-NEXT: store i32 0, i32 addrspace(3)* @ConstAS3Ptr, align 4
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@user_as3
|
|
; CGSCC-SAME: () #[[ATTR6:[0-9]+]] {
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call fastcc align 4 i32 addrspace(3)* @const_ptr_return_as3() #[[ATTR12]]
|
|
; CGSCC-NEXT: store i32 0, i32 addrspace(3)* [[CALL]], align 4
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
%call = call fastcc i32 addrspace(3)* @const_ptr_return_as3()
|
|
store i32 0, i32 addrspace(3)* %call
|
|
ret void
|
|
}
|
|
define void @user() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@user
|
|
; TUNIT-SAME: () #[[ATTR4]] {
|
|
; TUNIT-NEXT: store i32 0, i32* addrspacecast (i32 addrspace(3)* @ConstAS3Ptr to i32*), align 4
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@user
|
|
; CGSCC-SAME: () #[[ATTR6]] {
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call fastcc align 4 i32* @const_ptr_return() #[[ATTR12]]
|
|
; CGSCC-NEXT: store i32 0, i32* [[CALL]], align 4
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
%call = call fastcc i32* @const_ptr_return()
|
|
store i32 0, i32* %call
|
|
ret void
|
|
}
|
|
|
|
|
|
define i1 @test_merge_with_undef_values_ptr(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i1 false
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values_ptr
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[R1:%.*]] = call noundef i1 @undef_then_null(i1 [[C]]) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[R1]]
|
|
;
|
|
%r1 = call i1 @undef_then_null(i1 %c, i32* undef, i32* undef)
|
|
ret i1 %r1
|
|
}
|
|
define internal i1 @undef_then_null(i1 %c, i32* %i32Aptr, i32* %i32Bptr) {
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@undef_then_null
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
|
|
; CGSCC: a:
|
|
; CGSCC-NEXT: ret i1 false
|
|
; CGSCC: b:
|
|
; CGSCC-NEXT: ret i1 false
|
|
;
|
|
%cmp1 = icmp eq i32* %i32Aptr, %i32Bptr
|
|
%cmp2 = icmp eq i1 %cmp1, false
|
|
%or = or i1 %cmp2, %c
|
|
br i1 %or, label %a, label %b
|
|
a:
|
|
%r2 = call i1 @undef_then_null(i1 false, i32* null, i32* null)
|
|
ret i1 %r2
|
|
b:
|
|
ret i1 %cmp2
|
|
}
|
|
|
|
define i1 @test_merge_with_undef_values(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_merge_with_undef_values
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i1 false
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_merge_with_undef_values
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[R1:%.*]] = call noundef i1 @undef_then_1(i1 [[C]]) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[R1]]
|
|
;
|
|
%r1 = call i1 @undef_then_1(i1 %c, i32 undef, i32 undef)
|
|
ret i1 %r1
|
|
}
|
|
define internal i1 @undef_then_1(i1 %c, i32 %i32A, i32 %i32B) {
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@undef_then_1
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: br i1 [[C]], label [[A:%.*]], label [[B:%.*]]
|
|
; CGSCC: a:
|
|
; CGSCC-NEXT: ret i1 false
|
|
; CGSCC: b:
|
|
; CGSCC-NEXT: ret i1 false
|
|
;
|
|
%cmp1 = icmp eq i32 %i32A, %i32B
|
|
%cmp2 = icmp eq i1 %cmp1, false
|
|
%or = or i1 %cmp2, %c
|
|
br i1 %or, label %a, label %b
|
|
a:
|
|
%r2 = call i1 @undef_then_1(i1 false, i32 1, i32 1)
|
|
ret i1 %r2
|
|
b:
|
|
ret i1 %cmp2
|
|
}
|
|
|
|
define i32 @test_select(i32 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_select
|
|
; TUNIT-SAME: (i32 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i32 42
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_select
|
|
; CGSCC-SAME: (i32 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[CALL:%.*]] = call noundef i32 @select() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i32 [[CALL]]
|
|
;
|
|
%call = call i32 @select(i1 1, i32 42, i32 %c)
|
|
ret i32 %call
|
|
}
|
|
|
|
define internal i32 @select(i1 %a, i32 %b, i32 %c) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@select
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: ret i32 42
|
|
;
|
|
%s = select i1 %a, i32 %b, i32 %c
|
|
ret i32 %s
|
|
}
|
|
|
|
define i1 @icmp() {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@icmp
|
|
; CHECK-SAME: () #[[ATTR1]] {
|
|
; CHECK-NEXT: ret i1 true
|
|
;
|
|
%c = icmp eq i8* null, null
|
|
ret i1 %c
|
|
}
|
|
|
|
define void @test_callee_is_undef(void (i32)* %fn) {
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_callee_is_undef
|
|
; TUNIT-SAME: (void (i32)* nocapture nofree [[FN:%.*]]) {
|
|
; TUNIT-NEXT: call void @callee_is_undef()
|
|
; TUNIT-NEXT: call void @unknown_calle_arg_is_undef(void (i32)* nocapture nofree [[FN]])
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_callee_is_undef
|
|
; CGSCC-SAME: (void (i32)* nocapture nofree [[FN:%.*]]) {
|
|
; CGSCC-NEXT: call void @callee_is_undef()
|
|
; CGSCC-NEXT: call void @unknown_calle_arg_is_undef(void (i32)* nocapture nofree noundef nonnull [[FN]])
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
call void @callee_is_undef(void ()* undef)
|
|
call void @unknown_calle_arg_is_undef(void (i32)* %fn, i32 undef)
|
|
ret void
|
|
}
|
|
define internal void @callee_is_undef(void ()* %fn) {
|
|
;
|
|
; CHECK-LABEL: define {{[^@]+}}@callee_is_undef() {
|
|
; CHECK-NEXT: call void poison()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void %fn()
|
|
ret void
|
|
}
|
|
define internal void @unknown_calle_arg_is_undef(void (i32)* %fn, i32 %arg) {
|
|
;
|
|
; CHECK-LABEL: define {{[^@]+}}@unknown_calle_arg_is_undef
|
|
; CHECK-SAME: (void (i32)* nocapture nofree noundef nonnull [[FN:%.*]]) {
|
|
; CHECK-NEXT: call void [[FN]](i32 undef)
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
call void %fn(i32 %arg)
|
|
ret void
|
|
}
|
|
|
|
; Taken from 50683
|
|
; {{{
|
|
|
|
@g = internal constant { [2 x i8*] } { [2 x i8*] [i8* bitcast (void (i8***)* @f1 to i8*), i8* bitcast (void (i1 (i8*)*)* @f2 to i8*)] }
|
|
|
|
define internal void @f1(i8*** %a) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; TUNIT-LABEL: define {{[^@]+}}@f1
|
|
; TUNIT-SAME: (i8*** nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR3]] {
|
|
; TUNIT-NEXT: entry:
|
|
; TUNIT-NEXT: store i8** getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @g, i32 0, i32 0, i32 0), i8*** [[A]], align 8
|
|
; TUNIT-NEXT: ret void
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: write)
|
|
; CGSCC-LABEL: define {{[^@]+}}@f1
|
|
; CGSCC-SAME: (i8*** nocapture nofree noundef nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) #[[ATTR4]] {
|
|
; CGSCC-NEXT: entry:
|
|
; CGSCC-NEXT: store i8** getelementptr inbounds ({ [2 x i8*] }, { [2 x i8*] }* @g, i32 0, i32 0, i32 0), i8*** [[A]], align 8
|
|
; CGSCC-NEXT: ret void
|
|
;
|
|
entry:
|
|
%x = getelementptr { [2 x i8*] }, { [2 x i8*] }* @g, i32 0, i32 0, i32 0
|
|
store i8** %x , i8*** %a, align 8
|
|
ret void
|
|
}
|
|
|
|
define internal void @f2(i1 (i8*)* %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@f2
|
|
; CHECK-SAME: (i1 (i8*)* [[A:%.*]]) {
|
|
; CHECK-NEXT: cont461:
|
|
; CHECK-NEXT: [[C1:%.*]] = bitcast i1 (i8*)* [[A]] to i8*
|
|
; CHECK-NEXT: call void @f3(i8* [[C1]], i1 (i8*)* nocapture nofree [[A]])
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
cont461:
|
|
%c1 = bitcast i1 (i8*)* %a to i8*
|
|
call void @f3(i8* %c1, i1 (i8*)* %a)
|
|
ret void
|
|
}
|
|
|
|
define internal void @f3(i8* %a1, i1 (i8*)* %a) {
|
|
; CHECK-LABEL: define {{[^@]+}}@f3
|
|
; CHECK-SAME: (i8* [[A1:%.*]], i1 (i8*)* nocapture nofree [[A:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: [[CALL20:%.*]] = call i1 @f9()
|
|
; CHECK-NEXT: br i1 [[CALL20]], label [[LAND_LHS_TRUE:%.*]], label [[IF_END40:%.*]]
|
|
; CHECK: land.lhs.true:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = call i1 [[A]](i8* [[A1]])
|
|
; CHECK-NEXT: br label [[IF_END40]]
|
|
; CHECK: if.end40:
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
%call20 = call i1 @f9()
|
|
br i1 %call20, label %land.lhs.true, label %if.end40
|
|
|
|
land.lhs.true:
|
|
call i1 %a(i8* %a1)
|
|
br label %if.end40
|
|
|
|
if.end40:
|
|
ret void
|
|
}
|
|
|
|
define linkonce_odr i1 @f9() {
|
|
; CHECK-LABEL: define {{[^@]+}}@f9() {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: ret i1 false
|
|
;
|
|
entry:
|
|
ret i1 false
|
|
}
|
|
|
|
; }}}
|
|
|
|
|
|
define i1 @test_cmp_null_after_cast() {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
|
|
; TUNIT-SAME: () #[[ATTR1]] {
|
|
; TUNIT-NEXT: ret i1 true
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_cmp_null_after_cast
|
|
; CGSCC-SAME: () #[[ATTR2]] {
|
|
; CGSCC-NEXT: [[C:%.*]] = call noundef i1 @cmp_null_after_cast() #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[C]]
|
|
;
|
|
%c = call i1 @cmp_null_after_cast(i32 0, i8 0)
|
|
ret i1 %c
|
|
}
|
|
define internal i1 @cmp_null_after_cast(i32 %a, i8 %b) {
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@cmp_null_after_cast
|
|
; CGSCC-SAME: () #[[ATTR1]] {
|
|
; CGSCC-NEXT: ret i1 true
|
|
;
|
|
%t = trunc i32 %a to i8
|
|
%c = icmp eq i8 %t, %b
|
|
ret i1 %c
|
|
}
|
|
|
|
|
|
declare i8* @m()
|
|
|
|
define i32 @test(i1 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@test
|
|
; CHECK-SAME: (i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: [[R1:%.*]] = call i32 @ctx_test1(i1 [[C]])
|
|
; CHECK-NEXT: [[R2:%.*]] = call i32 @ctx_test2(i1 [[C]])
|
|
; CHECK-NEXT: [[ADD:%.*]] = add i32 [[R1]], [[R2]]
|
|
; CHECK-NEXT: ret i32 [[ADD]]
|
|
;
|
|
%r1 = call i32 @ctx_test1(i1 %c)
|
|
%r2 = call i32 @ctx_test2(i1 %c)
|
|
%add = add i32 %r1, %r2
|
|
ret i32 %add
|
|
}
|
|
|
|
define internal i32 @ctx_test1(i1 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@ctx_test1
|
|
; CHECK-SAME: (i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
|
|
; CHECK: then:
|
|
; CHECK-NEXT: [[M:%.*]] = tail call i8* @m()
|
|
; CHECK-NEXT: [[I:%.*]] = ptrtoint i8* [[M]] to i64
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[RET:%.*]] = trunc i64 [[PHI]] to i32
|
|
; CHECK-NEXT: ret i32 [[RET]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %then, label %join
|
|
|
|
then:
|
|
%m = tail call i8* @m()
|
|
%i = ptrtoint i8* %m to i64
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i64 [ %i, %then ], [ undef, %entry ]
|
|
%ret = trunc i64 %phi to i32
|
|
ret i32 %ret
|
|
}
|
|
|
|
define internal i32 @ctx_test2(i1 %c) {
|
|
; CHECK-LABEL: define {{[^@]+}}@ctx_test2
|
|
; CHECK-SAME: (i1 [[C:%.*]]) {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C]], label [[THEN:%.*]], label [[JOIN:%.*]]
|
|
; CHECK: then:
|
|
; CHECK-NEXT: [[M:%.*]] = tail call i8* @m()
|
|
; CHECK-NEXT: [[I:%.*]] = ptrtoint i8* [[M]] to i32
|
|
; CHECK-NEXT: br label [[JOIN]]
|
|
; CHECK: join:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[I]], [[THEN]] ], [ undef, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[RET:%.*]] = lshr i32 [[PHI]], 1
|
|
; CHECK-NEXT: ret i32 [[RET]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %then, label %join
|
|
|
|
then:
|
|
%m = tail call i8* @m()
|
|
%i = ptrtoint i8* %m to i32
|
|
br label %join
|
|
|
|
join:
|
|
%phi = phi i32 [ %i, %then ], [ undef, %entry ]
|
|
%ret = lshr i32 %phi, 1
|
|
ret i32 %ret
|
|
|
|
uselistorder label %join, { 1, 0 }
|
|
}
|
|
|
|
define i1 @test_liveness(i1 %c) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_liveness
|
|
; TUNIT-SAME: (i1 [[C:%.*]]) #[[ATTR1]] {
|
|
; TUNIT-NEXT: entry:
|
|
; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; TUNIT: t:
|
|
; TUNIT-NEXT: br label [[F]]
|
|
; TUNIT: f:
|
|
; TUNIT-NEXT: [[P:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[T]] ]
|
|
; TUNIT-NEXT: [[RC1:%.*]] = call i1 @ret(i1 noundef [[P]]) #[[ATTR9]]
|
|
; TUNIT-NEXT: ret i1 [[RC1]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_liveness
|
|
; CGSCC-SAME: (i1 [[C:%.*]]) #[[ATTR2]] {
|
|
; CGSCC-NEXT: entry:
|
|
; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; CGSCC: t:
|
|
; CGSCC-NEXT: br label [[F]]
|
|
; CGSCC: f:
|
|
; CGSCC-NEXT: [[P:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ false, [[T]] ]
|
|
; CGSCC-NEXT: [[RC1:%.*]] = call noundef i1 @ret(i1 noundef [[P]]) #[[ATTR12]]
|
|
; CGSCC-NEXT: ret i1 [[RC1]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
br label %f
|
|
f:
|
|
%p = phi i1 [true, %entry], [false, %t]
|
|
%rc1 = call i1 @ret(i1 %p)
|
|
ret i1 %rc1
|
|
}
|
|
|
|
define internal i1 @ret(i1 %c) {
|
|
; CHECK: Function Attrs: nofree norecurse nosync nounwind willreturn memory(none)
|
|
; CHECK-LABEL: define {{[^@]+}}@ret
|
|
; CHECK-SAME: (i1 noundef [[C:%.*]]) #[[ATTR1]] {
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]]
|
|
; CHECK: t:
|
|
; CHECK-NEXT: br label [[F]]
|
|
; CHECK: f:
|
|
; CHECK-NEXT: [[P:%.*]] = phi i1 [ [[C]], [[ENTRY:%.*]] ], [ false, [[T]] ]
|
|
; CHECK-NEXT: ret i1 [[P]]
|
|
;
|
|
entry:
|
|
br i1 %c, label %t, label %f
|
|
t:
|
|
br label %f
|
|
f:
|
|
%p = phi i1 [%c, %entry], [false, %t]
|
|
ret i1 %p
|
|
}
|
|
|
|
declare i8* @unknown()
|
|
define internal i8 @dead_ret() {
|
|
; CHECK-LABEL: define {{[^@]+}}@dead_ret() {
|
|
; CHECK-NEXT: [[R:%.*]] = call i8* @unknown()
|
|
; CHECK-NEXT: ret i8 undef
|
|
;
|
|
%r = call i8* @unknown()
|
|
%l = load i8, i8* %r
|
|
ret i8 %l
|
|
}
|
|
|
|
define void @dead_ret_caller() {
|
|
; CHECK-LABEL: define {{[^@]+}}@dead_ret_caller() {
|
|
; CHECK-NEXT: [[R:%.*]] = call i8 @dead_ret()
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
%r = call i8 @dead_ret()
|
|
ret void
|
|
}
|
|
|
|
declare void @llvm.memcpy(i8* %dest, i8* %src, i32 %len, i1 %isvolatile)
|
|
define internal i8 @memcpy_uses_store(i8 %arg) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn
|
|
; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store
|
|
; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
|
|
; TUNIT-NEXT: [[SRC:%.*]] = alloca i8, align 1
|
|
; TUNIT-NEXT: [[DST:%.*]] = alloca i8, align 1
|
|
; TUNIT-NEXT: store i8 [[ARG]], i8* [[SRC]], align 1
|
|
; TUNIT-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], i8* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR11:[0-9]+]]
|
|
; TUNIT-NEXT: [[L:%.*]] = load i8, i8* [[DST]], align 1
|
|
; TUNIT-NEXT: ret i8 [[L]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn
|
|
; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store
|
|
; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR7:[0-9]+]] {
|
|
; CGSCC-NEXT: [[SRC:%.*]] = alloca i8, align 1
|
|
; CGSCC-NEXT: [[DST:%.*]] = alloca i8, align 1
|
|
; CGSCC-NEXT: store i8 [[ARG]], i8* [[SRC]], align 1
|
|
; CGSCC-NEXT: call void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[DST]], i8* noalias nocapture nofree noundef nonnull readonly dereferenceable(1) [[SRC]], i32 noundef 1, i1 noundef false) #[[ATTR14:[0-9]+]]
|
|
; CGSCC-NEXT: [[L:%.*]] = load i8, i8* [[DST]], align 1
|
|
; CGSCC-NEXT: ret i8 [[L]]
|
|
;
|
|
%src = alloca i8
|
|
%dst = alloca i8
|
|
store i8 %arg, i8* %src
|
|
call void @llvm.memcpy(i8* %dst, i8* %src, i32 1, i1 false)
|
|
%l = load i8, i8* %dst
|
|
ret i8 %l
|
|
}
|
|
|
|
define i8 @memcpy_uses_store_caller(i8 %arg) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn
|
|
; TUNIT-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
|
|
; TUNIT-SAME: (i8 [[ARG:%.*]]) #[[ATTR2]] {
|
|
; TUNIT-NEXT: [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR9]]
|
|
; TUNIT-NEXT: ret i8 [[R]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree nosync nounwind willreturn
|
|
; CGSCC-LABEL: define {{[^@]+}}@memcpy_uses_store_caller
|
|
; CGSCC-SAME: (i8 [[ARG:%.*]]) #[[ATTR3]] {
|
|
; CGSCC-NEXT: [[R:%.*]] = call i8 @memcpy_uses_store(i8 [[ARG]]) #[[ATTR13]]
|
|
; CGSCC-NEXT: ret i8 [[R]]
|
|
;
|
|
%r = call i8 @memcpy_uses_store(i8 %arg)
|
|
ret i8 %r
|
|
}
|
|
|
|
|
|
declare i32 @speculatable() speculatable readnone
|
|
|
|
define i32 @test_speculatable_expr() norecurse {
|
|
; TUNIT: Function Attrs: norecurse nosync memory(none)
|
|
; TUNIT-LABEL: define {{[^@]+}}@test_speculatable_expr
|
|
; TUNIT-SAME: () #[[ATTR6:[0-9]+]] {
|
|
; TUNIT-NEXT: [[STACK:%.*]] = alloca i32, align 4
|
|
; TUNIT-NEXT: [[SPEC_RESULT:%.*]] = call i32 @speculatable()
|
|
; TUNIT-NEXT: [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
|
|
; TUNIT-NEXT: store i32 [[PLUS1]], i32* [[STACK]], align 4
|
|
; TUNIT-NEXT: [[TMP1:%.*]] = load i32, i32* [[STACK]], align 4
|
|
; TUNIT-NEXT: [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[TMP1]]) #[[ATTR12:[0-9]+]]
|
|
; TUNIT-NEXT: ret i32 [[RSPEC]]
|
|
;
|
|
; CGSCC: Function Attrs: norecurse nosync memory(none)
|
|
; CGSCC-LABEL: define {{[^@]+}}@test_speculatable_expr
|
|
; CGSCC-SAME: () #[[ATTR9:[0-9]+]] {
|
|
; CGSCC-NEXT: [[STACK:%.*]] = alloca i32, align 4
|
|
; CGSCC-NEXT: [[SPEC_RESULT:%.*]] = call i32 @speculatable()
|
|
; CGSCC-NEXT: [[PLUS1:%.*]] = add i32 [[SPEC_RESULT]], 1
|
|
; CGSCC-NEXT: store i32 [[PLUS1]], i32* [[STACK]], align 4
|
|
; CGSCC-NEXT: [[RSPEC:%.*]] = call i32 @ret_speculatable_expr(i32 [[PLUS1]])
|
|
; CGSCC-NEXT: ret i32 [[RSPEC]]
|
|
;
|
|
%stack = alloca i32
|
|
%spec_result = call i32 @speculatable()
|
|
%plus1 = add i32 %spec_result, 1
|
|
store i32 %plus1, i32* %stack
|
|
%rspec = call i32 @ret_speculatable_expr(i32* %stack, i32 13)
|
|
ret i32 %rspec
|
|
}
|
|
|
|
define internal i32 @ret_speculatable_expr(i32* %mem, i32 %a2) {
|
|
; TUNIT: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; TUNIT-LABEL: define {{[^@]+}}@ret_speculatable_expr
|
|
; TUNIT-SAME: (i32 [[TMP0:%.*]]) #[[ATTR7:[0-9]+]] {
|
|
; TUNIT-NEXT: [[MEM_PRIV:%.*]] = alloca i32, align 4
|
|
; TUNIT-NEXT: store i32 [[TMP0]], i32* [[MEM_PRIV]], align 4
|
|
; TUNIT-NEXT: [[L:%.*]] = load i32, i32* [[MEM_PRIV]], align 4
|
|
; TUNIT-NEXT: [[MUL:%.*]] = mul i32 [[L]], 13
|
|
; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 7
|
|
; TUNIT-NEXT: ret i32 [[ADD]]
|
|
;
|
|
; CGSCC: Function Attrs: nofree norecurse nosync nounwind willreturn memory(argmem: read)
|
|
; CGSCC-LABEL: define {{[^@]+}}@ret_speculatable_expr
|
|
; CGSCC-SAME: (i32 [[TMP0:%.*]]) #[[ATTR10:[0-9]+]] {
|
|
; CGSCC-NEXT: [[MEM_PRIV:%.*]] = alloca i32, align 4
|
|
; CGSCC-NEXT: store i32 [[TMP0]], i32* [[MEM_PRIV]], align 4
|
|
; CGSCC-NEXT: [[L:%.*]] = load i32, i32* [[MEM_PRIV]], align 4
|
|
; CGSCC-NEXT: [[MUL:%.*]] = mul i32 [[L]], 13
|
|
; CGSCC-NEXT: [[ADD:%.*]] = add i32 [[MUL]], 7
|
|
; CGSCC-NEXT: ret i32 [[ADD]]
|
|
;
|
|
%l = load i32, i32* %mem
|
|
%mul = mul i32 %l, %a2
|
|
%add = add i32 %mul, 7
|
|
ret i32 %add
|
|
}
|
|
|
|
|
|
;.
|
|
; TUNIT: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
|
|
; TUNIT: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(none) }
|
|
; TUNIT: attributes #[[ATTR2]] = { nofree norecurse nosync nounwind willreturn }
|
|
; TUNIT: attributes #[[ATTR3]] = { nofree norecurse nosync nounwind willreturn memory(argmem: write) }
|
|
; TUNIT: attributes #[[ATTR4]] = { nofree norecurse nosync nounwind willreturn memory(write) }
|
|
; TUNIT: attributes #[[ATTR5:[0-9]+]] = { speculatable memory(none) }
|
|
; TUNIT: attributes #[[ATTR6]] = { norecurse nosync memory(none) }
|
|
; TUNIT: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
|
|
; TUNIT: attributes #[[ATTR8:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
|
; TUNIT: attributes #[[ATTR9]] = { nofree nosync nounwind willreturn }
|
|
; TUNIT: attributes #[[ATTR10]] = { willreturn }
|
|
; TUNIT: attributes #[[ATTR11]] = { willreturn memory(readwrite) }
|
|
; TUNIT: attributes #[[ATTR12]] = { nosync nounwind }
|
|
;.
|
|
; CGSCC: attributes #[[ATTR0:[0-9]+]] = { nocallback nofree nosync nounwind willreturn }
|
|
; CGSCC: attributes #[[ATTR1]] = { nofree norecurse nosync nounwind willreturn memory(none) }
|
|
; CGSCC: attributes #[[ATTR2]] = { nofree nosync nounwind willreturn memory(none) }
|
|
; CGSCC: attributes #[[ATTR3]] = { nofree nosync nounwind willreturn }
|
|
; CGSCC: attributes #[[ATTR4]] = { nofree norecurse nosync nounwind willreturn memory(argmem: write) }
|
|
; CGSCC: attributes #[[ATTR5]] = { nofree nosync nounwind willreturn memory(argmem: write) }
|
|
; CGSCC: attributes #[[ATTR6]] = { nofree nosync nounwind willreturn memory(write) }
|
|
; CGSCC: attributes #[[ATTR7]] = { nofree norecurse nosync nounwind willreturn }
|
|
; CGSCC: attributes #[[ATTR8:[0-9]+]] = { speculatable memory(none) }
|
|
; CGSCC: attributes #[[ATTR9]] = { norecurse nosync memory(none) }
|
|
; CGSCC: attributes #[[ATTR10]] = { nofree norecurse nosync nounwind willreturn memory(argmem: read) }
|
|
; CGSCC: attributes #[[ATTR11:[0-9]+]] = { nocallback nofree nounwind willreturn memory(argmem: readwrite) }
|
|
; CGSCC: attributes #[[ATTR12]] = { willreturn }
|
|
; CGSCC: attributes #[[ATTR13]] = { nounwind willreturn }
|
|
; CGSCC: attributes #[[ATTR14]] = { willreturn memory(readwrite) }
|
|
;.
|