mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 04:32:44 +01:00
[Attributor][Tests] Copy & use the ArgumentPromotion tests
This commit is contained in:
parent
fd77171a96
commit
7920401470
@ -0,0 +1,30 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 -S < %s | FileCheck %s
|
||||
|
||||
define internal i32 @deref(i32* %x) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@deref
|
||||
; CHECK-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[X]], align 4
|
||||
; CHECK-NEXT: ret i32 [[TMP2]]
|
||||
;
|
||||
entry:
|
||||
%tmp2 = load i32, i32* %x, align 4
|
||||
ret i32 %tmp2
|
||||
}
|
||||
|
||||
define i32 @f(i32 %x) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f
|
||||
; CHECK-SAME: (i32 [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[X_ADDR:%.*]] = alloca i32
|
||||
; CHECK-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @deref(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[X_ADDR]])
|
||||
; CHECK-NEXT: ret i32 [[TMP1]]
|
||||
;
|
||||
entry:
|
||||
%x_addr = alloca i32
|
||||
store i32 %x, i32* %x_addr, align 4
|
||||
%tmp1 = call i32 @deref( i32* %x_addr ) nounwind
|
||||
ret i32 %tmp1
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 -S < %s | FileCheck %s
|
||||
; PR2498
|
||||
|
||||
; This test tries to convince CHECK about promoting the load from %A + 2,
|
||||
; because there is a load of %A in the entry block
|
||||
define internal i32 @callee(i1 %C, i32* %A) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly dereferenceable(4) [[A:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A_0:%.*]] = load i32, i32* null
|
||||
; CHECK-NEXT: br i1 false, label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: T:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: F:
|
||||
; CHECK-NEXT: [[A_2:%.*]] = getelementptr i32, i32* null, i32 2
|
||||
; CHECK-NEXT: [[R:%.*]] = load i32, i32* [[A_2]]
|
||||
; CHECK-NEXT: ret i32 [[R]]
|
||||
;
|
||||
entry:
|
||||
; Unconditonally load the element at %A
|
||||
%A.0 = load i32, i32* %A
|
||||
br i1 %C, label %T, label %F
|
||||
|
||||
T:
|
||||
ret i32 %A.0
|
||||
|
||||
F:
|
||||
; Load the element at offset two from %A. This should not be promoted!
|
||||
%A.2 = getelementptr i32, i32* %A, i32 2
|
||||
%R = load i32, i32* %A.2
|
||||
ret i32 %R
|
||||
}
|
||||
|
||||
define i32 @foo() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo()
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nofree null)
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
;
|
||||
%X = call i32 @callee(i1 false, i32* null) ; <i32> [#uses=1]
|
||||
ret i32 %X
|
||||
}
|
||||
|
@ -0,0 +1,13 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s
|
||||
|
||||
define internal fastcc i32 @hash(i32* %ts, i32 %mod) nounwind {
|
||||
entry:
|
||||
unreachable
|
||||
}
|
||||
|
||||
define void @encode(i32* %m, i32* %ts, i32* %new) nounwind {
|
||||
entry:
|
||||
%0 = call fastcc i32 @hash( i32* %ts, i32 0 ) nounwind ; <i32> [#uses=0]
|
||||
unreachable
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s
|
||||
|
||||
define internal fastcc i32 @term_SharingList(i32* %Term, i32* %List) nounwind {
|
||||
entry:
|
||||
br i1 false, label %bb, label %bb5
|
||||
|
||||
bb: ; preds = %entry
|
||||
%0 = call fastcc i32 @term_SharingList( i32* null, i32* %List ) nounwind ; <i32> [#uses=0]
|
||||
unreachable
|
||||
|
||||
bb5: ; preds = %entry
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define i32 @term_Sharing(i32* %Term) nounwind {
|
||||
entry:
|
||||
br i1 false, label %bb.i, label %bb14
|
||||
|
||||
bb.i: ; preds = %entry
|
||||
%0 = call fastcc i32 @term_SharingList( i32* null, i32* null ) nounwind ; <i32> [#uses=0]
|
||||
ret i32 1
|
||||
|
||||
bb14: ; preds = %entry
|
||||
ret i32 0
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
; Test that we only promote arguments when the caller/callee have compatible
|
||||
; function attrubtes.
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define internal fastcc void @no_promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@no_promote_avx2
|
||||
; CHECK-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <4 x i64>, <4 x i64>* %arg1
|
||||
store <4 x i64> %tmp, <4 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @no_promote(<4 x i64>* %arg) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@no_promote
|
||||
; CHECK-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(32) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <4 x i64>, align 32
|
||||
%tmp2 = alloca <4 x i64>, align 32
|
||||
%tmp3 = bitcast <4 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @no_promote_avx2(<4 x i64>* %tmp2, <4 x i64>* %tmp)
|
||||
%tmp4 = load <4 x i64>, <4 x i64>* %tmp2, align 32
|
||||
store <4 x i64> %tmp4, <4 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal fastcc void @promote_avx2(<4 x i64>* %arg, <4 x i64>* readonly %arg1) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@promote_avx2
|
||||
; CHECK-SAME: (<4 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(32) [[ARG:%.*]], <4 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(32) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <4 x i64>, <4 x i64>* %arg1
|
||||
store <4 x i64> %tmp, <4 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @promote(<4 x i64>* %arg) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@promote
|
||||
; CHECK-SAME: (<4 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <4 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <4 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <4 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(32) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @promote_avx2(<4 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(32) [[TMP2]], <4 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(32) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <4 x i64>, align 32
|
||||
%tmp2 = alloca <4 x i64>, align 32
|
||||
%tmp3 = bitcast <4 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @promote_avx2(<4 x i64>* %tmp2, <4 x i64>* %tmp)
|
||||
%tmp4 = load <4 x i64>, <4 x i64>* %tmp2, align 32
|
||||
store <4 x i64> %tmp4, <4 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #2
|
||||
|
||||
attributes #0 = { inlinehint norecurse nounwind uwtable "target-features"="+avx2" }
|
||||
attributes #1 = { nounwind uwtable }
|
||||
attributes #2 = { argmemonly nounwind }
|
@ -0,0 +1,2 @@
|
||||
if not 'X86' in config.root.targets:
|
||||
config.unsupported = True
|
@ -0,0 +1,328 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
; Test that we only promote arguments when the caller/callee have compatible
|
||||
; function attrubtes.
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* %arg) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer512
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* %arg) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer512_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* %arg) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal512_prefer512
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should not promote
|
||||
define internal fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %arg) #2 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal256_prefer256_call_avx512_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should not promote
|
||||
define internal fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #2 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* %arg) #1 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx512_legal512_prefer256_call_avx512_legal256_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #3 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* %arg) #4 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx2_legal256_prefer256_call_avx2_legal512_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; This should promote
|
||||
define internal fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* %arg, <8 x i64>* readonly %arg1) #4 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* noalias nocapture nofree nonnull writeonly align 32 dereferenceable(64) [[ARG:%.*]], <8 x i64>* noalias nocapture nofree nonnull readonly align 32 dereferenceable(64) [[ARG1:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = load <8 x i64>, <8 x i64>* %arg1
|
||||
store <8 x i64> %tmp, <8 x i64>* %arg
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* %arg) #3 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@avx2_legal512_prefer256_call_avx2_legal256_prefer256
|
||||
; CHECK-SAME: (<8 x i64>* nocapture writeonly [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = alloca <8 x i64>, align 32
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = bitcast <8 x i64>* [[TMP]] to i8*
|
||||
; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 32 dereferenceable(64) [[TMP3]], i8 0, i64 32, i1 false)
|
||||
; CHECK-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP2]], <8 x i64>* noalias nocapture nofree nonnull align 32 dereferenceable(64) [[TMP]])
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32
|
||||
; CHECK-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca <8 x i64>, align 32
|
||||
%tmp2 = alloca <8 x i64>, align 32
|
||||
%tmp3 = bitcast <8 x i64>* %tmp to i8*
|
||||
call void @llvm.memset.p0i8.i64(i8* align 32 %tmp3, i8 0, i64 32, i1 false)
|
||||
call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* %tmp2, <8 x i64>* %tmp)
|
||||
%tmp4 = load <8 x i64>, <8 x i64>* %tmp2, align 32
|
||||
store <8 x i64> %tmp4, <8 x i64>* %arg, align 2
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function Attrs: argmemonly nounwind
|
||||
declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1) #5
|
||||
|
||||
attributes #0 = { inlinehint norecurse nounwind uwtable "target-features"="+avx512vl" "min-legal-vector-width"="512" "prefer-vector-width"="512" }
|
||||
attributes #1 = { inlinehint norecurse nounwind uwtable "target-features"="+avx512vl" "min-legal-vector-width"="512" "prefer-vector-width"="256" }
|
||||
attributes #2 = { inlinehint norecurse nounwind uwtable "target-features"="+avx512vl" "min-legal-vector-width"="256" "prefer-vector-width"="256" }
|
||||
attributes #3 = { inlinehint norecurse nounwind uwtable "target-features"="+avx2" "min-legal-vector-width"="512" "prefer-vector-width"="256" }
|
||||
attributes #4 = { inlinehint norecurse nounwind uwtable "target-features"="+avx2" "min-legal-vector-width"="256" "prefer-vector-width"="256" }
|
||||
attributes #5 = { argmemonly nounwind }
|
73
test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll
Normal file
73
test/Transforms/Attributor/ArgumentPromotion/X86/thiscall.ll
Normal file
@ -0,0 +1,73 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; In PR41658, argpromotion put an inalloca in a position that per the
|
||||
; calling convention is passed in a register. This test verifies that
|
||||
; we don't do that anymore. It also verifies that the combination of
|
||||
; globalopt and argpromotion is able to optimize the call safely.
|
||||
;
|
||||
; RUN: opt -S -argpromotion %s | FileCheck %s --check-prefix=ARGPROMOTION
|
||||
; RUN: opt -S -globalopt -argpromotion %s | FileCheck %s --check-prefix=GLOBALOPT_ARGPROMOTION
|
||||
|
||||
target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32"
|
||||
target triple = "i386-pc-windows-msvc19.11.0"
|
||||
|
||||
%struct.a = type { i8 }
|
||||
|
||||
define internal x86_thiscallcc void @internalfun(%struct.a* %this, <{ %struct.a }>* inalloca) {
|
||||
; ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca [[TMP0:%.*]])
|
||||
; ARGPROMOTION-NEXT: entry:
|
||||
; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
|
||||
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
|
||||
; ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
|
||||
; ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
|
||||
; ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: entry:
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call void @ext(<{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%a = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %0, i32 0, i32 0
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
%1 = getelementptr inbounds <{ %struct.a }>, <{ %struct.a }>* %argmem, i32 0, i32 0
|
||||
%call = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* %1, %struct.a* dereferenceable(1) %a)
|
||||
call void @ext(<{ %struct.a }>* inalloca %argmem)
|
||||
ret void
|
||||
}
|
||||
|
||||
; This is here to ensure @internalfun is live.
|
||||
define void @exportedfun(%struct.a* %a) {
|
||||
; ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
|
||||
; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]])
|
||||
; ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
|
||||
; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
|
||||
; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]])
|
||||
; ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
|
||||
; ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@exportedfun
|
||||
; GLOBALOPT_ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) local_unnamed_addr
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave()
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call fastcc void @internalfun(<{ [[STRUCT_A]] }>* [[ARGMEM]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]])
|
||||
; GLOBALOPT_ARGPROMOTION-NEXT: ret void
|
||||
;
|
||||
%inalloca.save = tail call i8* @llvm.stacksave()
|
||||
%argmem = alloca inalloca <{ %struct.a }>, align 4
|
||||
call x86_thiscallcc void @internalfun(%struct.a* %a, <{ %struct.a }>* inalloca %argmem)
|
||||
call void @llvm.stackrestore(i8* %inalloca.save)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare x86_thiscallcc %struct.a* @copy_ctor(%struct.a* returned, %struct.a* dereferenceable(1))
|
||||
declare void @ext(<{ %struct.a }>* inalloca)
|
||||
declare i8* @llvm.stacksave()
|
||||
declare void @llvm.stackrestore(i8*)
|
@ -0,0 +1,36 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -disable-output -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s
|
||||
|
||||
%T = type { i32, i32, i32, i32 }
|
||||
@G = constant %T { i32 0, i32 0, i32 17, i32 25 }
|
||||
|
||||
define internal i32 @test(%T* %p) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32 [[P_0_2_VAL:%.*]], i32 [[P_0_3_VAL:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[V:%.*]] = add i32 [[P_0_3_VAL]], [[P_0_2_VAL]]
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
entry:
|
||||
%a.gep = getelementptr %T, %T* %p, i64 0, i32 3
|
||||
%b.gep = getelementptr %T, %T* %p, i64 0, i32 2
|
||||
%a = load i32, i32* %a.gep
|
||||
%b = load i32, i32* %b.gep
|
||||
%v = add i32 %a, %b
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define i32 @caller() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[G_IDX:%.*]] = getelementptr [[T:%.*]], %T* @G, i64 0, i32 2
|
||||
; CHECK-NEXT: [[G_IDX_VAL:%.*]] = load i32, i32* [[G_IDX]]
|
||||
; CHECK-NEXT: [[G_IDX1:%.*]] = getelementptr [[T]], %T* @G, i64 0, i32 3
|
||||
; CHECK-NEXT: [[G_IDX1_VAL:%.*]] = load i32, i32* [[G_IDX1]]
|
||||
; CHECK-NEXT: [[V:%.*]] = call i32 @test(i32 [[G_IDX_VAL]], i32 [[G_IDX1_VAL]])
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
entry:
|
||||
%v = call i32 @test(%T* @G)
|
||||
ret i32 %v
|
||||
}
|
52
test/Transforms/Attributor/ArgumentPromotion/attrs.ll
Normal file
52
test/Transforms/Attributor/ArgumentPromotion/attrs.ll
Normal file
@ -0,0 +1,52 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
|
||||
|
||||
%struct.ss = type { i32, i64 }
|
||||
|
||||
; Don't drop 'byval' on %X here.
|
||||
define internal void @f(%struct.ss* byval %b, i32* byval %X, i32 %i) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f
|
||||
; CHECK-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[B:%.*]], i32* nocapture nofree nonnull writeonly byval dereferenceable(4) [[X:%.*]], i32 [[I:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: store i32 0, i32* [[X]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
|
||||
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
|
||||
%tmp1 = load i32, i32* %tmp, align 4
|
||||
%tmp2 = add i32 %tmp1, 1
|
||||
store i32 %tmp2, i32* %tmp, align 4
|
||||
|
||||
store i32 %i, i32* %X
|
||||
ret void
|
||||
}
|
||||
|
||||
; Also make sure we don't drop the call zeroext attribute.
|
||||
define i32 @test(i32* %X) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32* nocapture nofree readonly [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
|
||||
; CHECK-NEXT: call void @f(%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[S]], i32* nocapture nofree readonly byval [[X]], i32 zeroext 0)
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%S = alloca %struct.ss
|
||||
%tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0
|
||||
store i32 1, i32* %tmp1, align 8
|
||||
%tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i64 2, i64* %tmp4, align 4
|
||||
|
||||
call void @f( %struct.ss* byval %S, i32* byval %X, i32 zeroext 0)
|
||||
|
||||
ret i32 0
|
||||
}
|
45
test/Transforms/Attributor/ArgumentPromotion/basictest.ll
Normal file
45
test/Transforms/Attributor/ArgumentPromotion/basictest.ll
Normal file
@ -0,0 +1,45 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=6 < %s | FileCheck %s
|
||||
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||
|
||||
define internal i32 @test(i32* %X, i32* %Y) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[X:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[Y:%.*]])
|
||||
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[X]], align 4
|
||||
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[Y]], align 4
|
||||
; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
|
||||
; CHECK-NEXT: ret i32 [[C]]
|
||||
;
|
||||
%A = load i32, i32* %X
|
||||
%B = load i32, i32* %Y
|
||||
%C = add i32 %A, %B
|
||||
ret i32 %C
|
||||
}
|
||||
|
||||
define internal i32 @caller(i32* %B) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller
|
||||
; CHECK-SAME: (i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B:%.*]])
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32
|
||||
; CHECK-NEXT: store i32 1, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[C:%.*]] = call i32 @test(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[A]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[B]])
|
||||
; CHECK-NEXT: ret i32 [[C]]
|
||||
;
|
||||
%A = alloca i32
|
||||
store i32 1, i32* %A
|
||||
%C = call i32 @test(i32* %A, i32* %B)
|
||||
ret i32 %C
|
||||
}
|
||||
|
||||
define i32 @callercaller() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callercaller()
|
||||
; CHECK-NEXT: [[B:%.*]] = alloca i32
|
||||
; CHECK-NEXT: store i32 2, i32* [[B]], align 4
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @caller(i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[B]])
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
;
|
||||
%B = alloca i32
|
||||
store i32 2, i32* %B
|
||||
%X = call i32 @caller(i32* %B)
|
||||
ret i32 %X
|
||||
}
|
||||
|
47
test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
Normal file
47
test/Transforms/Attributor/ArgumentPromotion/byval-2.ll
Normal file
@ -0,0 +1,47 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
|
||||
|
||||
%struct.ss = type { i32, i64 }
|
||||
|
||||
define internal void @f(%struct.ss* byval %b, i32* byval %X) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f
|
||||
; CHECK-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[B:%.*]], i32* nocapture nofree nonnull writeonly byval dereferenceable(4) [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: store i32 0, i32* [[X]]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
|
||||
%tmp1 = load i32, i32* %tmp, align 4
|
||||
%tmp2 = add i32 %tmp1, 1
|
||||
store i32 %tmp2, i32* %tmp, align 4
|
||||
|
||||
store i32 0, i32* %X
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @test(i32* %X) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32* nocapture nofree readonly [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
|
||||
; CHECK-NEXT: call void @f(%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[S]], i32* nocapture nofree readonly byval [[X]])
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%S = alloca %struct.ss
|
||||
%tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0
|
||||
store i32 1, i32* %tmp1, align 8
|
||||
%tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i64 2, i64* %tmp4, align 4
|
||||
call void @f( %struct.ss* byval %S, i32* byval %X)
|
||||
ret i32 0
|
||||
}
|
69
test/Transforms/Attributor/ArgumentPromotion/byval.ll
Normal file
69
test/Transforms/Attributor/ArgumentPromotion/byval.ll
Normal file
@ -0,0 +1,69 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||
|
||||
%struct.ss = type { i32, i64 }
|
||||
|
||||
define internal void @f(%struct.ss* byval %b) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f
|
||||
; CHECK-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[B:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
|
||||
%tmp1 = load i32, i32* %tmp, align 4
|
||||
%tmp2 = add i32 %tmp1, 1
|
||||
store i32 %tmp2, i32* %tmp, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define internal void @g(%struct.ss* byval align 32 %b) nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@g
|
||||
; CHECK-SAME: (%struct.ss* noalias nocapture nofree nonnull byval align 32 dereferenceable(12) [[B:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 32
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1
|
||||
; CHECK-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0
|
||||
%tmp1 = load i32, i32* %tmp, align 4
|
||||
%tmp2 = add i32 %tmp1, 1
|
||||
store i32 %tmp2, i32* %tmp, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
define i32 @main() nounwind {
|
||||
; CHECK-LABEL: define {{[^@]+}}@main()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 8
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; CHECK-NEXT: store i64 2, i64* [[TMP4]], align 4
|
||||
; CHECK-NEXT: call void @f(%struct.ss* noalias nocapture nofree nonnull byval align 8 dereferenceable(12) [[S]])
|
||||
; CHECK-NEXT: call void @g(%struct.ss* noalias nocapture nofree nonnull byval align 32 dereferenceable(12) [[S]])
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%S = alloca %struct.ss
|
||||
%tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0
|
||||
store i32 1, i32* %tmp1, align 8
|
||||
%tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i64 2, i64* %tmp4, align 4
|
||||
call void @f(%struct.ss* byval %S) nounwind
|
||||
call void @g(%struct.ss* byval %S) nounwind
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
|
31
test/Transforms/Attributor/ArgumentPromotion/chained.ll
Normal file
31
test/Transforms/Attributor/ArgumentPromotion/chained.ll
Normal file
@ -0,0 +1,31 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
|
||||
|
||||
@G1 = constant i32 0
|
||||
@G2 = constant i32* @G1
|
||||
|
||||
define internal i32 @test(i32** %x) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32** nocapture nofree nonnull readonly align 8 dereferenceable(8) [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[Y:%.*]] = load i32*, i32** @G2, align 8
|
||||
; CHECK-NEXT: [[Z:%.*]] = load i32, i32* [[Y]]
|
||||
; CHECK-NEXT: ret i32 [[Z]]
|
||||
;
|
||||
entry:
|
||||
%y = load i32*, i32** %x
|
||||
%z = load i32, i32* %y
|
||||
ret i32 %z
|
||||
}
|
||||
|
||||
define i32 @caller() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @test(i32** nofree nonnull align 8 dereferenceable(8) @G2)
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
;
|
||||
entry:
|
||||
%x = call i32 @test(i32** @G2)
|
||||
ret i32 %x
|
||||
}
|
||||
|
36
test/Transforms/Attributor/ArgumentPromotion/control-flow.ll
Normal file
36
test/Transforms/Attributor/ArgumentPromotion/control-flow.ll
Normal file
@ -0,0 +1,36 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
; Don't promote around control flow.
|
||||
define internal i32 @callee(i1 %C, i32* %P) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree readnone [[P:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: br i1 true, label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: T:
|
||||
; CHECK-NEXT: ret i32 17
|
||||
; CHECK: F:
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
br i1 %C, label %T, label %F
|
||||
|
||||
T:
|
||||
ret i32 17
|
||||
|
||||
F:
|
||||
%X = load i32, i32* %P
|
||||
ret i32 %X
|
||||
}
|
||||
|
||||
define i32 @foo() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 true, i32* noalias nofree undef)
|
||||
; CHECK-NEXT: ret i32 17
|
||||
;
|
||||
entry:
|
||||
%X = call i32 @callee(i1 true, i32* null)
|
||||
ret i32 %X
|
||||
}
|
||||
|
@ -0,0 +1,38 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=9 < %s | FileCheck %s
|
||||
|
||||
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||
|
||||
define internal i32 @callee(i1 %C, i32* %P) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee
|
||||
; CHECK-SAME: (i1 [[C:%.*]], i32* noalias nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P:%.*]])
|
||||
; CHECK-NEXT: br i1 false, label [[T:%.*]], label [[F:%.*]]
|
||||
; CHECK: T:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: F:
|
||||
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[P]], align 4
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
;
|
||||
br i1 %C, label %T, label %F
|
||||
|
||||
T: ; preds = %0
|
||||
ret i32 17
|
||||
|
||||
F: ; preds = %0
|
||||
%X = load i32, i32* %P ; <i32> [#uses=1]
|
||||
ret i32 %X
|
||||
}
|
||||
|
||||
define i32 @foo() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo()
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i32
|
||||
; CHECK-NEXT: store i32 17, i32* [[A]], align 4
|
||||
; CHECK-NEXT: [[X:%.*]] = call i32 @callee(i1 false, i32* noalias nocapture nofree nonnull align 4 dereferenceable(4) [[A]])
|
||||
; CHECK-NEXT: ret i32 [[X]]
|
||||
;
|
||||
%A = alloca i32 ; <i32*> [#uses=2]
|
||||
store i32 17, i32* %A
|
||||
%X = call i32 @callee( i1 false, i32* %A ) ; <i32> [#uses=1]
|
||||
ret i32 %X
|
||||
}
|
||||
|
102
test/Transforms/Attributor/ArgumentPromotion/crash.ll
Normal file
102
test/Transforms/Attributor/ArgumentPromotion/crash.ll
Normal file
@ -0,0 +1,102 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,ATTRIBUTOR
|
||||
; RUN: opt -S -passes='cgscc(inline),attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s --check-prefixes=CHECK,INLINE_ATTRIBUTOR
|
||||
|
||||
%S = type { %S* }
|
||||
|
||||
; Inlining should nuke the invoke (and any inlined calls) here even with
|
||||
; argument promotion running along with it.
|
||||
define void @zot() personality i32 (...)* @wibble {
|
||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@zot() #0 personality i32 (...)* @wibble
|
||||
; ATTRIBUTOR-NEXT: bb:
|
||||
; ATTRIBUTOR-NEXT: call void @hoge()
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
; ATTRIBUTOR: bb.split:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
; ATTRIBUTOR: bb1.i2c:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
; ATTRIBUTOR: bb1:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
; ATTRIBUTOR: bb2:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
;
|
||||
; INLINE_ATTRIBUTOR-LABEL: define {{[^@]+}}@zot() #0 personality i32 (...)* @wibble
|
||||
; INLINE_ATTRIBUTOR-NEXT: bb:
|
||||
; INLINE_ATTRIBUTOR-NEXT: unreachable
|
||||
; INLINE_ATTRIBUTOR: hoge.exit:
|
||||
; INLINE_ATTRIBUTOR-NEXT: unreachable
|
||||
; INLINE_ATTRIBUTOR: bb1:
|
||||
; INLINE_ATTRIBUTOR-NEXT: unreachable
|
||||
; INLINE_ATTRIBUTOR: bb2:
|
||||
; INLINE_ATTRIBUTOR-NEXT: unreachable
|
||||
;
|
||||
bb:
|
||||
invoke void @hoge()
|
||||
to label %bb1 unwind label %bb2
|
||||
|
||||
bb1:
|
||||
unreachable
|
||||
|
||||
bb2:
|
||||
%tmp = landingpad { i8*, i32 }
|
||||
cleanup
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal void @hoge() {
|
||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@hoge()
|
||||
; ATTRIBUTOR-NEXT: bb:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
; ATTRIBUTOR: bb.split:
|
||||
; ATTRIBUTOR-NEXT: unreachable
|
||||
;
|
||||
bb:
|
||||
%tmp = call fastcc i8* @spam(i1 (i8*)* @eggs)
|
||||
%tmp1 = call fastcc i8* @spam(i1 (i8*)* @barney)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal fastcc i8* @spam(i1 (i8*)* %arg) {
|
||||
bb:
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal i1 @eggs(i8* %arg) {
|
||||
bb:
|
||||
%tmp = call zeroext i1 @barney(i8* %arg)
|
||||
unreachable
|
||||
}
|
||||
|
||||
define internal i1 @barney(i8* %arg) {
|
||||
bb:
|
||||
ret i1 undef
|
||||
}
|
||||
|
||||
define i32 @test_inf_promote_caller(i32 %arg) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test_inf_promote_caller
|
||||
; CHECK-SAME: (i32 [[ARG:%.*]])
|
||||
; CHECK-NEXT: bb:
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: bb.split:
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
bb:
|
||||
%tmp = alloca %S
|
||||
%tmp1 = alloca %S
|
||||
%tmp2 = call i32 @test_inf_promote_callee(%S* %tmp, %S* %tmp1)
|
||||
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define internal i32 @test_inf_promote_callee(%S* %arg, %S* %arg1) {
|
||||
bb:
|
||||
%tmp = getelementptr %S, %S* %arg1, i32 0, i32 0
|
||||
%tmp2 = load %S*, %S** %tmp
|
||||
%tmp3 = getelementptr %S, %S* %arg, i32 0, i32 0
|
||||
%tmp4 = load %S*, %S** %tmp3
|
||||
%tmp5 = call i32 @test_inf_promote_callee(%S* %tmp4, %S* %tmp2)
|
||||
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
declare i32 @wibble(...)
|
52
test/Transforms/Attributor/ArgumentPromotion/dbg.ll
Normal file
52
test/Transforms/Attributor/ArgumentPromotion/dbg.ll
Normal file
@ -0,0 +1,52 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
declare void @sink(i32)
|
||||
|
||||
define internal void @test(i32** %X) !dbg !2 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (i32** nocapture nonnull readonly align 8 dereferenceable(8) [[X:%.*]]) !dbg !3
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32*, i32** [[X]], align 8
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP1]], align 8
|
||||
; CHECK-NEXT: call void @sink(i32 [[TMP2]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%1 = load i32*, i32** %X, align 8
|
||||
%2 = load i32, i32* %1, align 8
|
||||
call void @sink(i32 %2)
|
||||
ret void
|
||||
}
|
||||
|
||||
%struct.pair = type { i32, i32 }
|
||||
|
||||
define internal void @test_byval(%struct.pair* byval %P) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test_byval
|
||||
; CHECK-SAME: (%struct.pair* nocapture nofree readnone byval [[P:%.*]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @caller(i32** %Y, %struct.pair* %P) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller
|
||||
; CHECK-SAME: (i32** nocapture readonly [[Y:%.*]], %struct.pair* nocapture nofree readonly [[P:%.*]])
|
||||
; CHECK-NEXT: call void @test(i32** nocapture readonly [[Y]]), !dbg !4
|
||||
; CHECK-NEXT: call void @test_byval(%struct.pair* nocapture nofree readonly undef), !dbg !5
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
call void @test(i32** %Y), !dbg !1
|
||||
|
||||
call void @test_byval(%struct.pair* %P), !dbg !6
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
!llvm.module.flags = !{!0}
|
||||
!llvm.dbg.cu = !{!3}
|
||||
|
||||
!0 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!1 = !DILocation(line: 8, scope: !2)
|
||||
!2 = distinct !DISubprogram(name: "test", file: !5, line: 3, isLocal: true, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: false, unit: !3, scopeLine: 3, scope: null)
|
||||
!3 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, producer: "clang version 3.5.0 ", isOptimized: false, emissionKind: LineTablesOnly, file: !5)
|
||||
!5 = !DIFile(filename: "test.c", directory: "")
|
||||
!6 = !DILocation(line: 9, scope: !2)
|
74
test/Transforms/Attributor/ArgumentPromotion/fp80.ll
Normal file
74
test/Transforms/Attributor/ArgumentPromotion/fp80.ll
Normal file
@ -0,0 +1,74 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
%union.u = type { x86_fp80 }
|
||||
%struct.s = type { double, i16, i8, [5 x i8] }
|
||||
|
||||
@b = internal global %struct.s { double 3.14, i16 9439, i8 25, [5 x i8] undef }, align 16
|
||||
|
||||
%struct.Foo = type { i32, i64 }
|
||||
@a = internal global %struct.Foo { i32 1, i64 2 }, align 8
|
||||
|
||||
define void @run() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@run()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = call i64 @CaptureAStruct(%struct.Foo* nofree nonnull align 8 dereferenceable(16) @a)
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
tail call i8 @UseLongDoubleUnsafely(%union.u* byval align 16 bitcast (%struct.s* @b to %union.u*))
|
||||
tail call x86_fp80 @UseLongDoubleSafely(%union.u* byval align 16 bitcast (%struct.s* @b to %union.u*))
|
||||
call i64 @AccessPaddingOfStruct(%struct.Foo* @a)
|
||||
call i64 @CaptureAStruct(%struct.Foo* @a)
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal i8 @UseLongDoubleUnsafely(%union.u* byval align 16 %arg) {
|
||||
entry:
|
||||
%bitcast = bitcast %union.u* %arg to %struct.s*
|
||||
%gep = getelementptr inbounds %struct.s, %struct.s* %bitcast, i64 0, i32 2
|
||||
%result = load i8, i8* %gep
|
||||
ret i8 %result
|
||||
}
|
||||
|
||||
define internal x86_fp80 @UseLongDoubleSafely(%union.u* byval align 16 %arg) {
|
||||
%gep = getelementptr inbounds %union.u, %union.u* %arg, i64 0, i32 0
|
||||
%fp80 = load x86_fp80, x86_fp80* %gep
|
||||
ret x86_fp80 %fp80
|
||||
}
|
||||
|
||||
define internal i64 @AccessPaddingOfStruct(%struct.Foo* byval %a) {
|
||||
%p = bitcast %struct.Foo* %a to i64*
|
||||
%v = load i64, i64* %p
|
||||
ret i64 %v
|
||||
}
|
||||
|
||||
define internal i64 @CaptureAStruct(%struct.Foo* byval %a) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@CaptureAStruct
|
||||
; CHECK-SAME: (%struct.Foo* nofree nonnull byval align 8 dereferenceable(16) [[A:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[A_PTR:%.*]] = alloca %struct.Foo*
|
||||
; CHECK-NEXT: br label [[LOOP:%.*]]
|
||||
; CHECK: loop:
|
||||
; CHECK-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ]
|
||||
; CHECK-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]], align 8
|
||||
; CHECK-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0
|
||||
; CHECK-NEXT: br label [[LOOP]]
|
||||
;
|
||||
entry:
|
||||
%a_ptr = alloca %struct.Foo*
|
||||
br label %loop
|
||||
|
||||
loop:
|
||||
%phi = phi %struct.Foo* [ null, %entry ], [ %gep, %loop ]
|
||||
%0 = phi %struct.Foo* [ %a, %entry ], [ %0, %loop ]
|
||||
store %struct.Foo* %phi, %struct.Foo** %a_ptr
|
||||
%gep = getelementptr %struct.Foo, %struct.Foo* %a, i64 0
|
||||
br label %loop
|
||||
}
|
91
test/Transforms/Attributor/ArgumentPromotion/inalloca.ll
Normal file
91
test/Transforms/Attributor/ArgumentPromotion/inalloca.ll
Normal file
@ -0,0 +1,91 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s --check-prefixes=ATTRIBUTOR
|
||||
; RUN: opt -S -passes='globalopt,attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s --check-prefixes=GLOBALOPT_ATTRIBUTOR
|
||||
|
||||
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||
|
||||
%struct.ss = type { i32, i32 }
|
||||
|
||||
; Argpromote + sroa should change this to passing the two integers by value.
|
||||
define internal i32 @f(%struct.ss* inalloca %s) {
|
||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@f
|
||||
; ATTRIBUTOR-SAME: (%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S:%.*]])
|
||||
; ATTRIBUTOR-NEXT: entry:
|
||||
; ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; ATTRIBUTOR-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
|
||||
; ATTRIBUTOR-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
|
||||
; ATTRIBUTOR-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
|
||||
; ATTRIBUTOR-NEXT: ret i32 [[R]]
|
||||
;
|
||||
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@f
|
||||
; GLOBALOPT_ATTRIBUTOR-SAME: (%struct.ss* noalias nocapture nofree nonnull readonly align 4 dereferenceable(8) [[S:%.*]]) unnamed_addr
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[A:%.*]] = load i32, i32* [[F0]], align 4
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[B:%.*]] = load i32, i32* [[F1]], align 4
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[R:%.*]] = add i32 [[A]], [[B]]
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 [[R]]
|
||||
;
|
||||
entry:
|
||||
%f0 = getelementptr %struct.ss, %struct.ss* %s, i32 0, i32 0
|
||||
%f1 = getelementptr %struct.ss, %struct.ss* %s, i32 0, i32 1
|
||||
%a = load i32, i32* %f0, align 4
|
||||
%b = load i32, i32* %f1, align 4
|
||||
%r = add i32 %a, %b
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@main()
|
||||
; ATTRIBUTOR-NEXT: entry:
|
||||
; ATTRIBUTOR-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
|
||||
; ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; ATTRIBUTOR-NEXT: store i32 1, i32* [[F0]], align 4
|
||||
; ATTRIBUTOR-NEXT: store i32 2, i32* [[F1]], align 4
|
||||
; ATTRIBUTOR-NEXT: [[R:%.*]] = call i32 @f(%struct.ss* inalloca noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S]])
|
||||
; ATTRIBUTOR-NEXT: ret i32 [[R]]
|
||||
;
|
||||
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@main() local_unnamed_addr
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[S:%.*]] = alloca inalloca [[STRUCT_SS:%.*]]
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[F1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 1, i32* [[F0]], align 4
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: store i32 2, i32* [[F1]], align 4
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: [[R:%.*]] = call fastcc i32 @f(%struct.ss* noalias nocapture nofree nonnull align 4 dereferenceable(8) [[S]])
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 [[R]]
|
||||
;
|
||||
entry:
|
||||
%S = alloca inalloca %struct.ss
|
||||
%f0 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0
|
||||
%f1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1
|
||||
store i32 1, i32* %f0, align 4
|
||||
store i32 2, i32* %f1, align 4
|
||||
%r = call i32 @f(%struct.ss* inalloca %S)
|
||||
ret i32 %r
|
||||
}
|
||||
|
||||
; Argpromote can't promote %a because of the icmp use.
|
||||
define internal i1 @g(%struct.ss* %a, %struct.ss* inalloca %b) nounwind {
|
||||
entry:
|
||||
%c = icmp eq %struct.ss* %a, %b
|
||||
ret i1 %c
|
||||
}
|
||||
|
||||
define i32 @test() {
|
||||
; ATTRIBUTOR-LABEL: define {{[^@]+}}@test()
|
||||
; ATTRIBUTOR-NEXT: entry:
|
||||
; ATTRIBUTOR-NEXT: ret i32 0
|
||||
;
|
||||
; GLOBALOPT_ATTRIBUTOR-LABEL: define {{[^@]+}}@test() local_unnamed_addr
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: entry:
|
||||
; GLOBALOPT_ATTRIBUTOR-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%S = alloca inalloca %struct.ss
|
||||
%c = call i1 @g(%struct.ss* %S, %struct.ss* inalloca %S)
|
||||
ret i32 0
|
||||
}
|
50
test/Transforms/Attributor/ArgumentPromotion/invalidation.ll
Normal file
50
test/Transforms/Attributor/ArgumentPromotion/invalidation.ll
Normal file
@ -0,0 +1,50 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; Check that when argument promotion changes a function in some parent node of
|
||||
; the call graph, any analyses that happened to be cached for that function are
|
||||
; actually invalidated. We are using `demanded-bits` here because when printed
|
||||
; it will end up caching a value for every instruction, making it easy to
|
||||
; detect the instruction-level changes that will fail here. With improper
|
||||
; invalidation this will crash in the second printer as it tries to reuse
|
||||
; now-invalid demanded bits.
|
||||
;
|
||||
; RUN: opt < %s -passes='function(print<demanded-bits>),attributor,function(print<demanded-bits>)' -S | FileCheck %s
|
||||
|
||||
@G = constant i32 0
|
||||
|
||||
define internal i32 @a(i32* %x) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@a
|
||||
; CHECK-SAME: (i32* [[X:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[V:%.*]] = load i32, i32* [[X]]
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
entry:
|
||||
%v = load i32, i32* %x
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define i32 @b() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@b()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[V:%.*]] = call i32 @a(i32* @G)
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
entry:
|
||||
%v = call i32 @a(i32* @G)
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define i32 @c() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@c()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[V1:%.*]] = call i32 @a(i32* @G)
|
||||
; CHECK-NEXT: [[V2:%.*]] = call i32 @b()
|
||||
; CHECK-NEXT: [[RESULT:%.*]] = add i32 [[V1]], [[V2]]
|
||||
; CHECK-NEXT: ret i32 [[RESULT]]
|
||||
;
|
||||
entry:
|
||||
%v1 = call i32 @a(i32* @G)
|
||||
%v2 = call i32 @b()
|
||||
%result = add i32 %v1, %v2
|
||||
ret i32 %result
|
||||
}
|
70
test/Transforms/Attributor/ArgumentPromotion/musttail.ll
Normal file
70
test/Transforms/Attributor/ArgumentPromotion/musttail.ll
Normal file
@ -0,0 +1,70 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
|
||||
; PR36543
|
||||
|
||||
; Don't promote arguments of musttail callee
|
||||
|
||||
%T = type { i32, i32, i32, i32 }
|
||||
|
||||
define internal i32 @test(%T* %p) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test
|
||||
; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]])
|
||||
; CHECK-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3
|
||||
; CHECK-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2
|
||||
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]]
|
||||
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]]
|
||||
; CHECK-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
%a.gep = getelementptr %T, %T* %p, i64 0, i32 3
|
||||
%b.gep = getelementptr %T, %T* %p, i64 0, i32 2
|
||||
%a = load i32, i32* %a.gep
|
||||
%b = load i32, i32* %b.gep
|
||||
%v = add i32 %a, %b
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
define i32 @caller(%T* %p) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller
|
||||
; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]])
|
||||
; CHECK-NEXT: [[V:%.*]] = musttail call i32 @test(%T* nocapture nofree readonly [[P]])
|
||||
; CHECK-NEXT: ret i32 [[V]]
|
||||
;
|
||||
%v = musttail call i32 @test(%T* %p)
|
||||
ret i32 %v
|
||||
}
|
||||
|
||||
; Don't promote arguments of musttail caller
|
||||
|
||||
define i32 @foo(%T* %p, i32 %v) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo
|
||||
; CHECK-SAME: (%T* nocapture nofree readnone [[P:%.*]], i32 [[V:%.*]])
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
define internal i32 @test2(%T* %p, i32 %p2) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test2
|
||||
; CHECK-SAME: (%T* nocapture nofree readonly [[P:%.*]], i32 [[P2:%.*]])
|
||||
; CHECK-NEXT: [[CA:%.*]] = musttail call i32 @foo(%T* undef, i32 undef)
|
||||
; CHECK-NEXT: ret i32 [[CA]]
|
||||
;
|
||||
%a.gep = getelementptr %T, %T* %p, i64 0, i32 3
|
||||
%b.gep = getelementptr %T, %T* %p, i64 0, i32 2
|
||||
%a = load i32, i32* %a.gep
|
||||
%b = load i32, i32* %b.gep
|
||||
%v = add i32 %a, %b
|
||||
%ca = musttail call i32 @foo(%T* undef, i32 %v)
|
||||
ret i32 %ca
|
||||
}
|
||||
|
||||
define i32 @caller2(%T* %g) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller2
|
||||
; CHECK-SAME: (%T* nocapture nofree readonly [[G:%.*]])
|
||||
; CHECK-NEXT: [[V:%.*]] = call i32 @test2(%T* nocapture nofree readonly undef, i32 undef)
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
%v = call i32 @test2(%T* %g, i32 0)
|
||||
ret i32 %v
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
|
||||
|
||||
; Don't promote paramaters of/arguments to naked functions
|
||||
|
||||
@g = common global i32 0, align 4
|
||||
|
||||
define i32 @bar() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@bar()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call i32 @foo(i32* nonnull align 4 dereferenceable(4) @g)
|
||||
; CHECK-NEXT: ret i32 [[CALL]]
|
||||
;
|
||||
entry:
|
||||
%call = call i32 @foo(i32* @g)
|
||||
ret i32 %call
|
||||
}
|
||||
|
||||
define internal i32 @foo(i32*) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo
|
||||
; CHECK-SAME: (i32* [[TMP0:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: call void asm sideeffect "ldr r0, [r0] \0Abx lr \0A", ""()
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
call void asm sideeffect "ldr r0, [r0] \0Abx lr \0A", ""()
|
||||
unreachable
|
||||
}
|
||||
|
||||
|
||||
attributes #0 = { naked }
|
@ -0,0 +1,38 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
|
||||
|
||||
; ArgumentPromotion should preserve the default function address space
|
||||
; from the data layout.
|
||||
|
||||
target datalayout = "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8"
|
||||
|
||||
@g = common global i32 0, align 4
|
||||
|
||||
define i32 @bar() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@bar() addrspace(1)
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[CALL:%.*]] = call addrspace(1) i32 @foo(i32* nofree nonnull align 4 dereferenceable(4) undef)
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK: entry.split:
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
|
||||
entry:
|
||||
%call = call i32 @foo(i32* @g)
|
||||
ret i32 %call
|
||||
}
|
||||
|
||||
define internal i32 @foo(i32*) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo
|
||||
; CHECK-SAME: (i32* nocapture nofree nonnull readnone align 4 dereferenceable(4) [[TMP0:%.*]]) addrspace(1)
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: call addrspace(0) void asm sideeffect "ldr r0, [r0] \0Abx lr \0A", ""()
|
||||
; CHECK-NEXT: unreachable
|
||||
;
|
||||
entry:
|
||||
%retval = alloca i32, align 4
|
||||
call void asm sideeffect "ldr r0, [r0] \0Abx lr \0A", ""()
|
||||
unreachable
|
||||
}
|
||||
|
45
test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
Normal file
45
test/Transforms/Attributor/ArgumentPromotion/pr27568.ll
Normal file
@ -0,0 +1,45 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
||||
define internal void @callee(i8*) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee
|
||||
; CHECK-SAME: (i8* noalias nocapture nofree readnone [[TMP0:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: call void @thunk()
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
call void @thunk()
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @test1() personality i32 (...)* @__CxxFrameHandler3 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@test1() personality i32 (...)* @__CxxFrameHandler3
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: invoke void @thunk()
|
||||
; CHECK-NEXT: to label [[OUT:%.*]] unwind label [[CPAD:%.*]]
|
||||
; CHECK: out:
|
||||
; CHECK-NEXT: ret void
|
||||
; CHECK: cpad:
|
||||
; CHECK-NEXT: [[PAD:%.*]] = cleanuppad within none []
|
||||
; CHECK-NEXT: call void @callee(i8* noalias nofree undef) [ "funclet"(token [[PAD]]) ]
|
||||
; CHECK-NEXT: cleanupret from [[PAD]] unwind to caller
|
||||
;
|
||||
entry:
|
||||
invoke void @thunk()
|
||||
to label %out unwind label %cpad
|
||||
|
||||
out:
|
||||
ret void
|
||||
|
||||
cpad:
|
||||
%pad = cleanuppad within none []
|
||||
call void @callee(i8* null) [ "funclet"(token %pad) ]
|
||||
cleanupret from %pad unwind to caller
|
||||
}
|
||||
|
||||
|
||||
declare void @thunk()
|
||||
|
||||
declare i32 @__CxxFrameHandler3(...)
|
1945
test/Transforms/Attributor/ArgumentPromotion/pr3085.ll
Normal file
1945
test/Transforms/Attributor/ArgumentPromotion/pr3085.ll
Normal file
File diff suppressed because it is too large
Load Diff
35
test/Transforms/Attributor/ArgumentPromotion/pr32917.ll
Normal file
35
test/Transforms/Attributor/ArgumentPromotion/pr32917.ll
Normal file
@ -0,0 +1,35 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s
|
||||
; PR 32917
|
||||
|
||||
@b = common local_unnamed_addr global i32 0, align 4
|
||||
@a = common local_unnamed_addr global i32 0, align 4
|
||||
|
||||
define i32 @fn2() local_unnamed_addr {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn2() local_unnamed_addr
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @b, align 4
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = sext i32 [[TMP1]] to i64
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = inttoptr i64 [[TMP2]] to i32*
|
||||
; CHECK-NEXT: call fastcc void @fn1(i32* nofree [[TMP3]])
|
||||
; CHECK-NEXT: ret i32 undef
|
||||
;
|
||||
%1 = load i32, i32* @b, align 4
|
||||
%2 = sext i32 %1 to i64
|
||||
%3 = inttoptr i64 %2 to i32*
|
||||
call fastcc void @fn1(i32* %3)
|
||||
ret i32 undef
|
||||
}
|
||||
|
||||
define internal fastcc void @fn1(i32* nocapture readonly) unnamed_addr {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn1
|
||||
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 [[TMP0:%.*]]) unnamed_addr
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, i32* [[TMP0]], i64 -1
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = load i32, i32* [[TMP2]], align 4
|
||||
; CHECK-NEXT: store i32 [[TMP3]], i32* @a, align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%2 = getelementptr inbounds i32, i32* %0, i64 -1
|
||||
%3 = load i32, i32* %2, align 4
|
||||
store i32 %3, i32* @a, align 4
|
||||
ret void
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
|
||||
|
||||
; Fix for PR33641. ArgumentPromotion removed the argument to bar but left the call to
|
||||
; dbg.value which still used the removed argument.
|
||||
|
||||
; The %p argument should be removed, and the use of it in dbg.value should be
|
||||
; changed to undef.
|
||||
|
||||
%p_t = type i16*
|
||||
%fun_t = type void (%p_t)*
|
||||
|
||||
define void @foo() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@foo()
|
||||
; CHECK-NEXT: [[TMP:%.*]] = alloca void (i16*)*
|
||||
; CHECK-NEXT: store void (i16*)* @bar, void (i16*)** [[TMP]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%tmp = alloca %fun_t
|
||||
store %fun_t @bar, %fun_t* %tmp
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @bar(%p_t %p) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@bar
|
||||
; CHECK-SAME: (i16* nocapture nofree readnone [[P:%.*]])
|
||||
; CHECK-NEXT: call void @llvm.dbg.value(metadata i16* [[P]], metadata !3, metadata !DIExpression()) #3, !dbg !5
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
call void @llvm.dbg.value(metadata %p_t %p, metadata !4, metadata !5), !dbg !6
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.dbg.value(metadata, metadata, metadata)
|
||||
|
||||
!llvm.dbg.cu = !{!0}
|
||||
!llvm.module.flags = !{!2}
|
||||
|
||||
!0 = distinct !DICompileUnit(language: DW_LANG_C, file: !1)
|
||||
!1 = !DIFile(filename: "test.c", directory: "")
|
||||
!2 = !{i32 2, !"Debug Info Version", i32 3}
|
||||
!3 = distinct !DISubprogram(name: "bar", unit: !0)
|
||||
!4 = !DILocalVariable(name: "p", scope: !3)
|
||||
!5 = !DIExpression()
|
||||
!6 = !DILocation(line: 1, column: 1, scope: !3)
|
34
test/Transforms/Attributor/ArgumentPromotion/profile.ll
Normal file
34
test/Transforms/Attributor/ArgumentPromotion/profile.ll
Normal file
@ -0,0 +1,34 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
|
||||
|
||||
; Checks if !prof metadata is corret in deadargelim.
|
||||
|
||||
define void @caller() #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@caller()
|
||||
; CHECK-NEXT: [[X:%.*]] = alloca i32
|
||||
; CHECK-NEXT: store i32 42, i32* [[X]], align 4
|
||||
; CHECK-NEXT: call void @promote_i32_ptr(i32* noalias nocapture nonnull align 4 dereferenceable(4) [[X]]), !prof !0
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%x = alloca i32
|
||||
store i32 42, i32* %x
|
||||
call void @promote_i32_ptr(i32* %x), !prof !0
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @promote_i32_ptr(i32* %xp) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@promote_i32_ptr
|
||||
; CHECK-SAME: (i32* noalias nocapture nonnull readonly align 4 dereferenceable(4) [[XP:%.*]])
|
||||
; CHECK-NEXT: [[X:%.*]] = load i32, i32* [[XP]], align 4
|
||||
; CHECK-NEXT: call void @use_i32(i32 [[X]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%x = load i32, i32* %xp
|
||||
call void @use_i32(i32 %x)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @use_i32(i32)
|
||||
|
||||
!0 = !{!"branch_weights", i32 30}
|
65
test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll
Normal file
65
test/Transforms/Attributor/ArgumentPromotion/reserve-tbaa.ll
Normal file
@ -0,0 +1,65 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
; PR17906
|
||||
; When we promote two arguments in a single function with different types,
|
||||
; before the fix, we used the same tag for the newly-created two loads.
|
||||
; This testing case makes sure that we correctly transfer the tbaa tags from the
|
||||
; original loads to the newly-created loads when promoting pointer arguments.
|
||||
|
||||
@a = global i32* null, align 8
|
||||
@e = global i32** @a, align 8
|
||||
@g = global i32 0, align 4
|
||||
@c = global i64 0, align 8
|
||||
@d = global i8 0, align 1
|
||||
|
||||
define internal fastcc void @fn(i32* nocapture readonly %p1, i64* nocapture readonly %p2) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@fn
|
||||
; CHECK-SAME: (i32* nocapture nofree nonnull readonly align 4 dereferenceable(4) [[P1:%.*]], i64* nocapture nofree nonnull readonly align 8 dereferenceable(8) [[P2:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i64, i64* @c, align 8, !tbaa !0
|
||||
; CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32, i32* @g, align 4, !tbaa !4
|
||||
; CHECK-NEXT: [[CONV1:%.*]] = trunc i32 [[TMP1]] to i8
|
||||
; CHECK-NEXT: store i8 [[CONV1]], i8* @d, align 1, !tbaa !6
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
%0 = load i64, i64* %p2, align 8, !tbaa !1
|
||||
%conv = trunc i64 %0 to i32
|
||||
%1 = load i32, i32* %p1, align 4, !tbaa !5
|
||||
%conv1 = trunc i32 %1 to i8
|
||||
store i8 %conv1, i8* @d, align 1, !tbaa !7
|
||||
ret void
|
||||
}
|
||||
|
||||
define i32 @main() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@main()
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = load i32**, i32*** @e, align 8, !tbaa !7
|
||||
; CHECK-NEXT: store i32* @g, i32** [[TMP0]], align 8, !tbaa !7
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = load i32*, i32** @a, align 8, !tbaa !7
|
||||
; CHECK-NEXT: store i32 1, i32* [[TMP1]], align 4, !tbaa !4
|
||||
; CHECK-NEXT: call fastcc void @fn(i32* nofree nonnull align 4 dereferenceable(4) @g, i64* nofree nonnull align 8 dereferenceable(8) undef)
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
%0 = load i32**, i32*** @e, align 8, !tbaa !8
|
||||
store i32* @g, i32** %0, align 8, !tbaa !8
|
||||
%1 = load i32*, i32** @a, align 8, !tbaa !8
|
||||
store i32 1, i32* %1, align 4, !tbaa !5
|
||||
call fastcc void @fn(i32* @g, i64* @c)
|
||||
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
!1 = !{!2, !2, i64 0}
|
||||
!2 = !{!"long", !3, i64 0}
|
||||
!3 = !{!"omnipotent char", !4, i64 0}
|
||||
!4 = !{!"Simple C/C++ TBAA"}
|
||||
!5 = !{!6, !6, i64 0}
|
||||
!6 = !{!"int", !3, i64 0}
|
||||
!7 = !{!3, !3, i64 0}
|
||||
!8 = !{!9, !9, i64 0}
|
||||
!9 = !{!"any pointer", !3, i64 0}
|
||||
|
39
test/Transforms/Attributor/ArgumentPromotion/sret.ll
Normal file
39
test/Transforms/Attributor/ArgumentPromotion/sret.ll
Normal file
@ -0,0 +1,39 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s
|
||||
|
||||
target datalayout = "e-m:w-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-pc-windows-msvc"
|
||||
|
||||
define internal void @add({i32, i32}* %this, i32* sret %r) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@add
|
||||
; CHECK-SAME: ({ i32, i32 }* noalias nocapture nofree nonnull readonly align 8 dereferenceable(8) [[THIS:%.*]], i32* noalias nocapture nofree nonnull sret writeonly align 4 dereferenceable(4) [[R:%.*]])
|
||||
; CHECK-NEXT: [[AP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 0
|
||||
; CHECK-NEXT: [[BP:%.*]] = getelementptr { i32, i32 }, { i32, i32 }* [[THIS]], i32 0, i32 1
|
||||
; CHECK-NEXT: [[A:%.*]] = load i32, i32* [[AP]], align 8
|
||||
; CHECK-NEXT: [[B:%.*]] = load i32, i32* [[BP]]
|
||||
; CHECK-NEXT: [[AB:%.*]] = add i32 [[A]], [[B]]
|
||||
; CHECK-NEXT: store i32 [[AB]], i32* [[R]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%ap = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 0
|
||||
%bp = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 1
|
||||
%a = load i32, i32* %ap
|
||||
%b = load i32, i32* %bp
|
||||
%ab = add i32 %a, %b
|
||||
store i32 %ab, i32* %r
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @f() {
|
||||
; CHECK-LABEL: define {{[^@]+}}@f()
|
||||
; CHECK-NEXT: [[R:%.*]] = alloca i32
|
||||
; CHECK-NEXT: [[PAIR:%.*]] = alloca { i32, i32 }
|
||||
; CHECK-NEXT: call void @add({ i32, i32 }* noalias nocapture nofree nonnull align 8 dereferenceable(8) [[PAIR]], i32* noalias nocapture nofree nonnull sret align 4 dereferenceable(4) [[R]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%r = alloca i32
|
||||
%pair = alloca {i32, i32}
|
||||
|
||||
call void @add({i32, i32}* %pair, i32* sret %r)
|
||||
ret void
|
||||
}
|
29
test/Transforms/Attributor/ArgumentPromotion/tail.ll
Normal file
29
test/Transforms/Attributor/ArgumentPromotion/tail.ll
Normal file
@ -0,0 +1,29 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s
|
||||
; PR14710
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
|
||||
%pair = type { i32, i32 }
|
||||
|
||||
declare i8* @foo(%pair*)
|
||||
|
||||
define internal void @bar(%pair* byval %Data) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@bar
|
||||
; CHECK-SAME: (%pair* byval [[DATA:%.*]])
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = tail call i8* @foo(%pair* [[DATA]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
tail call i8* @foo(%pair* %Data)
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @zed(%pair* byval %Data) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@zed
|
||||
; CHECK-SAME: (%pair* nocapture readonly byval [[DATA:%.*]])
|
||||
; CHECK-NEXT: call void @bar(%pair* nocapture readonly byval [[DATA]])
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
call void @bar(%pair* byval %Data)
|
||||
ret void
|
||||
}
|
38
test/Transforms/Attributor/ArgumentPromotion/variadic.ll
Normal file
38
test/Transforms/Attributor/ArgumentPromotion/variadic.ll
Normal file
@ -0,0 +1,38 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes
|
||||
; RUN: opt -S -passes='attributor' -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=1 < %s | FileCheck %s
|
||||
|
||||
; Unused arguments from variadic functions cannot be eliminated as that changes
|
||||
; their classiciation according to the SysV amd64 ABI. Clang and other frontends
|
||||
; bake in the classification when they use things like byval, as in this test.
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
%struct.tt0 = type { i64, i64 }
|
||||
%struct.__va_list_tag = type { i32, i32, i8*, i8* }
|
||||
|
||||
@t45 = internal global %struct.tt0 { i64 1335139741, i64 438042995 }, align 8
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define i32 @main(i32 %argc, i8** nocapture readnone %argv) #0 {
|
||||
; CHECK-LABEL: define {{[^@]+}}@main
|
||||
; CHECK-SAME: (i32 [[ARGC:%.*]], i8** nocapture nofree readnone [[ARGV:%.*]])
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* byval align 8 @t45)
|
||||
; CHECK-NEXT: ret i32 0
|
||||
;
|
||||
entry:
|
||||
tail call void (i8*, i8*, i8*, i8*, i8*, ...) @callee_t0f(i8* undef, i8* undef, i8* undef, i8* undef, i8* undef, %struct.tt0* byval align 8 @t45)
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind uwtable
|
||||
define internal void @callee_t0f(i8* nocapture readnone %tp13, i8* nocapture readnone %tp14, i8* nocapture readnone %tp15, i8* nocapture readnone %tp16, i8* nocapture readnone %tp17, ...) {
|
||||
; CHECK-LABEL: define {{[^@]+}}@callee_t0f
|
||||
; CHECK-SAME: (i8* nocapture nofree nonnull readnone [[TP13:%.*]], i8* nocapture nofree nonnull readnone [[TP14:%.*]], i8* nocapture nofree nonnull readnone [[TP15:%.*]], i8* nocapture nofree nonnull readnone [[TP16:%.*]], i8* nocapture nofree nonnull readnone [[TP17:%.*]], ...)
|
||||
; CHECK-NEXT: entry:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
ret void
|
||||
}
|
Loading…
Reference in New Issue
Block a user