• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; RUN: opt < %s -inline -S | FileCheck %s
2; RUN: opt < %s -passes='cgscc(inline)' -S | FileCheck %s
3
4; The verifier does catch problems with inlining of byval arguments that has a
5; different address space compared to the alloca. But running instcombine
6; after inline used to trigger asserts unless we disallow such inlining.
7; RUN: opt < %s -inline -instcombine -disable-output 2>/dev/null
8
9target datalayout = "p:32:32-p1:64:64-p2:16:16-n16:32:64"
10
11; Inlining a byval struct should cause an explicit copy into an alloca.
12
13	%struct.ss = type { i32, i64 }
14@.str = internal constant [10 x i8] c"%d, %lld\0A\00"		; <[10 x i8]*> [#uses=1]
15
16define internal void @f(%struct.ss* byval(%struct.ss)  %b) nounwind  {
17entry:
18	%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0		; <i32*> [#uses=2]
19	%tmp1 = load i32, i32* %tmp, align 4		; <i32> [#uses=1]
20	%tmp2 = add i32 %tmp1, 1		; <i32> [#uses=1]
21	store i32 %tmp2, i32* %tmp, align 4
22	ret void
23}
24
25declare i32 @printf(i8*, ...) nounwind
26
27define i32 @test1() nounwind  {
28entry:
29	%S = alloca %struct.ss		; <%struct.ss*> [#uses=4]
30	%tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0		; <i32*> [#uses=1]
31	store i32 1, i32* %tmp1, align 8
32	%tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1		; <i64*> [#uses=1]
33	store i64 2, i64* %tmp4, align 4
34	call void @f(%struct.ss* byval(%struct.ss) %S) nounwind
35	ret i32 0
36; CHECK: @test1()
37; CHECK: %S1 = alloca %struct.ss
38; CHECK: %S = alloca %struct.ss
39; CHECK: call void @llvm.memcpy
40; CHECK: ret i32 0
41}
42
43; Inlining a byval struct should NOT cause an explicit copy
44; into an alloca if the function is readonly
45
46define internal i32 @f2(%struct.ss* byval(%struct.ss)  %b) nounwind readonly {
47entry:
48	%tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0		; <i32*> [#uses=2]
49	%tmp1 = load i32, i32* %tmp, align 4		; <i32> [#uses=1]
50	%tmp2 = add i32 %tmp1, 1		; <i32> [#uses=1]
51	ret i32 %tmp2
52}
53
54define i32 @test2() nounwind  {
55entry:
56	%S = alloca %struct.ss		; <%struct.ss*> [#uses=4]
57	%tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0		; <i32*> [#uses=1]
58	store i32 1, i32* %tmp1, align 8
59	%tmp4 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 1		; <i64*> [#uses=1]
60	store i64 2, i64* %tmp4, align 4
61	%X = call i32 @f2(%struct.ss* byval(%struct.ss) %S) nounwind
62	ret i32 %X
63; CHECK: @test2()
64; CHECK: %S = alloca %struct.ss
65; CHECK-NOT: call void @llvm.memcpy
66; CHECK: ret i32
67}
68
69
70; Inlining a byval with an explicit alignment needs to use *at least* that
71; alignment on the generated alloca.
72; PR8769
73declare void @g3(%struct.ss* %p)
74
75define internal void @f3(%struct.ss* byval(%struct.ss) align 64 %b) nounwind {
76   call void @g3(%struct.ss* %b)  ;; Could make alignment assumptions!
77   ret void
78}
79
80define void @test3() nounwind  {
81entry:
82	%S = alloca %struct.ss, align 1  ;; May not be aligned.
83	call void @f3(%struct.ss* byval(%struct.ss) align 64 %S) nounwind
84	ret void
85; CHECK: @test3()
86; CHECK: %S1 = alloca %struct.ss, align 64
87; CHECK: %S = alloca %struct.ss
88; CHECK: call void @llvm.memcpy
89; CHECK: call void @g3(%struct.ss* %S1)
90; CHECK: ret void
91}
92
93
94; Inlining a byval struct should NOT cause an explicit copy
95; into an alloca if the function is readonly, but should increase an alloca's
96; alignment to satisfy an explicit alignment request.
97
98define internal i32 @f4(%struct.ss* byval(%struct.ss) align 64 %b) nounwind readonly {
99        call void @g3(%struct.ss* %b)
100	ret i32 4
101}
102
103define i32 @test4() nounwind  {
104entry:
105	%S = alloca %struct.ss, align 2		; <%struct.ss*> [#uses=4]
106	%X = call i32 @f4(%struct.ss* byval(%struct.ss) align 64 %S) nounwind
107	ret i32 %X
108; CHECK: @test4()
109; CHECK: %S = alloca %struct.ss, align 64
110; CHECK-NOT: call void @llvm.memcpy
111; CHECK: call void @g3
112; CHECK: ret i32 4
113}
114
115%struct.S0 = type { i32 }
116
117@b = global %struct.S0 { i32 1 }, align 4
118@a = common global i32 0, align 4
119
120define internal void @f5(%struct.S0* byval(%struct.S0) nocapture readonly align 4 %p) {
121entry:
122	store i32 0, i32* getelementptr inbounds (%struct.S0, %struct.S0* @b, i64 0, i32 0), align 4
123	%f2 = getelementptr inbounds %struct.S0, %struct.S0* %p, i64 0, i32 0
124	%0 = load i32, i32* %f2, align 4
125	store i32 %0, i32* @a, align 4
126	ret void
127}
128
129define i32 @test5() {
130entry:
131	tail call void @f5(%struct.S0* byval(%struct.S0) align 4 @b)
132	%0 = load i32, i32* @a, align 4
133	ret i32 %0
134; CHECK: @test5()
135; CHECK: store i32 0, i32* getelementptr inbounds (%struct.S0, %struct.S0* @b, i64 0, i32 0), align 4
136; CHECK-NOT: load i32, i32* getelementptr inbounds (%struct.S0, %struct.S0* @b, i64 0, i32 0), align 4
137}
138
139; Inlining a byval struct that is in a different address space compared to the
140; alloca address space is at the moment not expected. That would need
141; adjustments inside the inlined function since the address space attribute of
142; the inlined argument changes.
143
144%struct.S1 = type { i32 }
145
146@d = addrspace(1) global %struct.S1 { i32 1 }, align 4
147@c = common addrspace(1) global i32 0, align 4
148
149define internal void @f5_as1(%struct.S1 addrspace(1)* byval(%struct.S1) nocapture readonly align 4 %p) {
150entry:
151	store i32 0, i32 addrspace(1)* getelementptr inbounds (%struct.S1, %struct.S1 addrspace(1)* @d, i64 0, i32 0), align 4
152	%f2 = getelementptr inbounds %struct.S1, %struct.S1 addrspace(1)* %p, i64 0, i32 0
153	%0 = load i32, i32 addrspace(1)* %f2, align 4
154	store i32 %0, i32 addrspace(1)* @c, align 4
155	ret void
156}
157
158define i32 @test5_as1() {
159entry:
160	tail call void @f5_as1(%struct.S1 addrspace(1)* byval(%struct.S1) align 4 @d)
161	%0 = load i32, i32 addrspace(1)* @c, align 4
162	ret i32 %0
163; CHECK: @test5_as1()
164; CHECK: call void @f5_as1
165}
166