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