xref: /llvm-project/llvm/test/CodeGen/BPF/preserve-static-offset/load-unroll-inline.ll (revision 29441e4f5fa5f5c7709f7cf180815ba97f611297)
1; RUN: opt -O2 -mtriple=bpf-pc-linux -S -o - %s | FileCheck %s
2;
3; Check position of bpf-preserve-static-offset pass in the pipeline:
4; - preserve.static.offset call is preserved if address is passed as
5;   a parameter to an inline-able function;
6; - second bpf-preserve-static-offset pass (after inlining) should introduce
7;   getelementptr.and.load call using the preserved marker after loops
8;   unrolling;
9; - readonly and tbaa attributes should allow replacement of
10;   getelementptr.and.load calls by CSE transformation.
11;
12; Source:
13;    #define __ctx __attribute__((preserve_static_offset))
14;
15;    struct foo {
16;      int a;
17;      int b[4];
18;    } __ctx;
19;
20;    extern void consume(int);
21;
22;    static inline void bar(int * restrict p) {
23;        consume(p[1]);
24;    }
25;
26;    void quux(struct foo *p){
27;      unsigned long i = 0;
28;    #pragma clang loop unroll(full)
29;      while (i < 2) {
30;        bar(p->b);
31;        ++i;
32;      }
33;    }
34;
35; Compilation flag:
36;   clang -cc1 -O2 -triple bpf -S -emit-llvm -disable-llvm-passes -o - \
37;       | opt -passes=function(sroa) -S -o -
38
39%struct.foo = type { i32, [4 x i32] }
40
41; Function Attrs: nounwind
42define dso_local void @quux(ptr noundef %p) #0 {
43entry:
44  br label %while.cond
45
46while.cond:                                       ; preds = %while.body, %entry
47  %i.0 = phi i64 [ 0, %entry ], [ %inc, %while.body ]
48  %cmp = icmp ult i64 %i.0, 2
49  br i1 %cmp, label %while.body, label %while.end
50
51while.body:                                       ; preds = %while.cond
52  %0 = call ptr @llvm.preserve.static.offset(ptr %p)
53  %b = getelementptr inbounds %struct.foo, ptr %0, i32 0, i32 1
54  %arraydecay = getelementptr inbounds [4 x i32], ptr %b, i64 0, i64 0
55  call void @bar(ptr noundef %arraydecay)
56  %inc = add i64 %i.0, 1
57  br label %while.cond, !llvm.loop !2
58
59while.end:                                        ; preds = %while.cond
60  ret void
61}
62
63; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
64declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) #1
65
66; Function Attrs: inlinehint nounwind
67define internal void @bar(ptr noalias noundef %p) #2 {
68entry:
69  %arrayidx = getelementptr inbounds i32, ptr %p, i64 1
70  %0 = load i32, ptr %arrayidx, align 4, !tbaa !5
71  call void @consume(i32 noundef %0)
72  ret void
73}
74
75; CHECK:      define dso_local void @quux(ptr noundef readonly captures(none) %[[p:.*]])
76; CHECK:        %[[v1:.*]] = tail call i32 (ptr, i1, i8, i8, i8, i1, ...)
77; CHECK-SAME:     @llvm.bpf.getelementptr.and.load.i32
78; CHECK-SAME:       (ptr readonly elementtype(i8) %[[p]],
79; CHECK-SAME:        i1 false, i8 0, i8 1, i8 2, i1 true, i64 immarg 8)
80; CHECK:        tail call void @consume(i32 noundef %[[v1]])
81; CHECK:        tail call void @consume(i32 noundef %[[v1]])
82
83; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
84declare ptr @llvm.preserve.static.offset(ptr readnone) #3
85
86; Function Attrs: nocallback nofree nosync nounwind willreturn memory(argmem: readwrite)
87declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) #1
88
89declare void @consume(i32 noundef) #4
90
91attributes #0 = { nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
92attributes #1 = { nocallback nofree nosync nounwind willreturn memory(argmem: readwrite) }
93attributes #2 = { inlinehint nounwind "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
94attributes #3 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
95attributes #4 = { "no-trapping-math"="true" "stack-protector-buffer-size"="8" }
96
97!llvm.module.flags = !{!0}
98!llvm.ident = !{!1}
99
100!0 = !{i32 1, !"wchar_size", i32 4}
101!1 = !{!"clang"}
102!2 = distinct !{!2, !3, !4}
103!3 = !{!"llvm.loop.mustprogress"}
104!4 = !{!"llvm.loop.unroll.full"}
105!5 = !{!6, !6, i64 0}
106!6 = !{!"int", !7, i64 0}
107!7 = !{!"omnipotent char", !8, i64 0}
108!8 = !{!"Simple C/C++ TBAA"}
109