1; RUN: opt --bpf-ir-peephole -mtriple=bpf-pc-linux -S %s | FileCheck %s
2; Source:
3;   #define AA 40
4;   struct t {
5;     char a[20];
6;   };
7;   void foo(void *);
8;
9;   int test1() {
10;     const int a = 8;
11;     char tmp[AA + sizeof(struct t) + a];
12;     foo(tmp);
13;     return 0;
14;   }
15;
16;   int test2(int b) {
17;     const int a = 8;
18;     char tmp[a + b];
19;     foo(tmp);
20;     return 0;
21;   }
22; Compilation flag:
23;   clang -target bpf -O2 -S -emit-llvm t.c -Xclang -disable-llvm-passes
24
25source_filename = "t.c"
26target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
27target triple = "bpf"
28
29; Function Attrs: nounwind
30define dso_local i32 @test1() #0 {
31entry:
32  %a = alloca i32, align 4
33  %saved_stack = alloca i8*, align 8
34  %0 = bitcast i32* %a to i8*
35  call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #4
36  store i32 8, i32* %a, align 4, !tbaa !3
37  %1 = call i8* @llvm.stacksave()
38  store i8* %1, i8** %saved_stack, align 8
39  %vla = alloca i8, i64 68, align 1
40  call void @foo(i8* %vla)
41  %2 = load i8*, i8** %saved_stack, align 8
42  call void @llvm.stackrestore(i8* %2)
43  %3 = bitcast i32* %a to i8*
44  call void @llvm.lifetime.end.p0i8(i64 4, i8* %3) #4
45  ret i32 0
46}
47
48; CHECK:       define dso_local i32 @test1
49; CHECK-NOT:   %[[#]] = call i8* @llvm.stacksave()
50; CHECK-NOT:   store i8* %[[#]], i8** %saved_stack, align 8
51; CHECK-NOT:   %[[#]] = load i8*, i8** %saved_stack, align 8
52; CHECK-NOT:   call void @llvm.stackrestore(i8* %[[#]])
53
54; Function Attrs: argmemonly nofree nosync nounwind willreturn
55declare void @llvm.lifetime.start.p0i8(i64 immarg, i8* nocapture) #1
56
57; Function Attrs: nofree nosync nounwind willreturn
58declare i8* @llvm.stacksave() #2
59
60declare dso_local void @foo(i8*) #3
61
62; Function Attrs: nofree nosync nounwind willreturn
63declare void @llvm.stackrestore(i8*) #2
64
65; Function Attrs: argmemonly nofree nosync nounwind willreturn
66declare void @llvm.lifetime.end.p0i8(i64 immarg, i8* nocapture) #1
67
68; Function Attrs: nounwind
69define dso_local i32 @test2(i32 %b) #0 {
70entry:
71  %b.addr = alloca i32, align 4
72  %a = alloca i32, align 4
73  %saved_stack = alloca i8*, align 8
74  %__vla_expr0 = alloca i64, align 8
75  store i32 %b, i32* %b.addr, align 4, !tbaa !3
76  %0 = bitcast i32* %a to i8*
77  call void @llvm.lifetime.start.p0i8(i64 4, i8* %0) #4
78  store i32 8, i32* %a, align 4, !tbaa !3
79  %1 = load i32, i32* %b.addr, align 4, !tbaa !3
80  %add = add nsw i32 8, %1
81  %2 = zext i32 %add to i64
82  %3 = call i8* @llvm.stacksave()
83  store i8* %3, i8** %saved_stack, align 8
84  %vla = alloca i8, i64 %2, align 1
85  store i64 %2, i64* %__vla_expr0, align 8
86  call void @foo(i8* %vla)
87  %4 = load i8*, i8** %saved_stack, align 8
88  call void @llvm.stackrestore(i8* %4)
89  %5 = bitcast i32* %a to i8*
90  call void @llvm.lifetime.end.p0i8(i64 4, i8* %5) #4
91  ret i32 0
92}
93
94; CHECK:       define dso_local i32 @test2
95; CHECK-NOT:   %[[#]] = call i8* @llvm.stacksave()
96; CHECK-NOT:   store i8* %[[#]], i8** %saved_stack, align 8
97; CHECK-NOT:   %[[#]] = load i8*, i8** %saved_stack, align 8
98; CHECK-NOT:   call void @llvm.stackrestore(i8* %[[#]])
99
100attributes #0 = { nounwind "frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
101attributes #1 = { argmemonly nofree nosync nounwind willreturn }
102attributes #2 = { nofree nosync nounwind willreturn }
103attributes #3 = { "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
104attributes #4 = { nounwind }
105
106!llvm.module.flags = !{!0, !1}
107!llvm.ident = !{!2}
108
109!0 = !{i32 1, !"wchar_size", i32 4}
110!1 = !{i32 7, !"frame-pointer", i32 2}
111!2 = !{!"clang version 14.0.0 (https://github.com/llvm/llvm-project.git 64c5d5c671fb5b5f25c464652a4eec2cf743af0d)"}
112!3 = !{!4, !4, i64 0}
113!4 = !{!"int", !5, i64 0}
114!5 = !{!"omnipotent char", !6, i64 0}
115!6 = !{!"Simple C/C++ TBAA"}
116