1 // NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
2 // REQUIRES: asserts
3 // RUN: %cheri128_purecap_cc1 -cheri-bounds=subobject-safe -O2 -emit-llvm %s -o -  | %cheri_FileCheck %s
4 // -Rcheri-subobject-bounds -verify | %cheri_FileCheck %s
5 // RUNs: %cheri_purecap_cc1 -cheri-bounds=subobject-safe  -O0 -emit-llvm %s -o /dev/null \
6 // RUNs:    -w -mllvm -debug-only="cheri-bounds" -mllvm -stats 2>&1 | FileCheck %s -check-prefix DBG -implicit-check-not cheri-bounds
7 // DBG:  3 cheri-bounds - Number of & operators checked for tightening bounds
8 // DBG:  4 cheri-bounds - Number of array-to-pointer-decays checked for tightening bounds
9 // DBG: 36 cheri-bounds - Number of [] operators checked for tightening bounds
10 // DBG:  1 cheri-bounds - Number of & operators where remaining allocation size was used
11 // DBG:  1 cheri-bounds - Number of array-to-pointer-decays where remaining allocation size was used
12 // DBG:  5 cheri-bounds - Number of [] operators where remaining allocation size was used
13 // DBG:  2 cheri-bounds - Number of & operators where bounds were tightened
14 // DBG:  3 cheri-bounds - Number of array-to-pointer-decays where bounds were tightened
15 // DBG: 22 cheri-bounds - Number of [] operators where bounds were tightened
16 // REQUIRES: asserts
17 
18 void use_buf(void *);
19 
20 typedef struct {
21   long x;
22   int buf[10];
23   char c;
24 } struct_with_array;
25 
26 // NOTE: bounds must be set before the GEP:
27 // CHECK-LABEL: define {{[^@]+}}@test_struct_with_array1
28 // CHECK-SAME: (%struct.struct_with_array addrspace(200)* readonly [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #0
29 // CHECK-NEXT:  entry:
30 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_WITH_ARRAY:%.*]], [[STRUCT_STRUCT_WITH_ARRAY]] addrspace(200)* [[S]], i64 0, i32 1
31 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [10 x i32] addrspace(200)* [[BUF]] to i8 addrspace(200)*
32 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 40)
33 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to [10 x i32] addrspace(200)*
34 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], [10 x i32] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX]]
35 // CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32 addrspace(200)* [[ARRAYIDX]], align 4, !tbaa !2
36 // CHECK-NEXT:    ret i32 [[TMP2]]
37 //
test_struct_with_array1(struct_with_array * s,long index)38 int test_struct_with_array1(struct_with_array *s, long index) {
39   // should set bounds to 10
40   return s->buf[index]; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'int [10]') to 40 bytes}}
41 }
42 
43 // CHECK-LABEL: define {{[^@]+}}@test_struct_with_array2
44 // CHECK-SAME: (%struct.struct_with_array addrspace(200)* noalias nocapture sret align 8 [[AGG_RESULT:%.*]], [[STRUCT_STRUCT_WITH_ARRAY:%.*]] addrspace(200)* nocapture readonly [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #2
45 // CHECK-NEXT:  entry:
46 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_WITH_ARRAY]], [[STRUCT_STRUCT_WITH_ARRAY]] addrspace(200)* [[S]], i64 [[INDEX]]
47 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[STRUCT_STRUCT_WITH_ARRAY]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
48 // CHECK-NEXT:    [[TMP1:%.*]] = bitcast [[STRUCT_STRUCT_WITH_ARRAY]] addrspace(200)* [[ARRAYIDX]] to i8 addrspace(200)*
49 // CHECK-NEXT:    tail call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* nonnull align 8 dereferenceable(56) [[TMP0]], i8 addrspace(200)* nonnull align 8 dereferenceable(56) [[TMP1]], i64 56, i1 false), !tbaa.struct !6
50 // CHECK-NEXT:    ret void
51 //
test_struct_with_array2(struct_with_array * s,long index)52 struct_with_array test_struct_with_array2(struct_with_array *s, long index) {
53   // can't set bounds here, have to trust the caller's bounds
54   return s[index]; // expected-remark{{not setting bounds for array subscript on 'struct_with_array * __capability' (array subscript on non-array type)}}
55 }
56 
57 typedef struct {
58   long x;
59   int *buf;
60   char c;
61 } struct_with_ptr;
62 
63 // CHECK-LABEL: define {{[^@]+}}@test_struct_with_ptr1
64 // CHECK-SAME: (%struct.struct_with_ptr addrspace(200)* nocapture readonly [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #4
65 // CHECK-NEXT:  entry:
66 // CHECK-NEXT:    [[BUF:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_WITH_PTR:%.*]], [[STRUCT_STRUCT_WITH_PTR]] addrspace(200)* [[S]], i64 0, i32 1
67 // CHECK-NEXT:    [[TMP0:%.*]] = load i32 addrspace(200)*, i32 addrspace(200)* addrspace(200)* [[BUF]], align 16, !tbaa !10
68 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32 addrspace(200)* [[TMP0]], i64 [[INDEX]]
69 // CHECK-NEXT:    [[TMP1:%.*]] = load i32, i32 addrspace(200)* [[ARRAYIDX]], align 4, !tbaa !2
70 // CHECK-NEXT:    ret i32 [[TMP1]]
71 //
test_struct_with_ptr1(struct_with_ptr * s,long index)72 int test_struct_with_ptr1(struct_with_ptr *s, long index) {
73   return s->buf[index]; // expected-remark{{not setting bounds for array subscript on 'int * __capability' (array subscript on non-array type)}}
74 }
75 
76 // CHECK-LABEL: define {{[^@]+}}@test_struct_with_ptr2
77 // CHECK-SAME: (%struct.struct_with_ptr addrspace(200)* noalias nocapture sret align [[#CAP_SIZE]] [[AGG_RESULT:%.*]], [[STRUCT_STRUCT_WITH_PTR:%.*]] addrspace(200)* nocapture readonly [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #2
78 // CHECK-NEXT:  entry:
79 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_WITH_PTR]], [[STRUCT_STRUCT_WITH_PTR]] addrspace(200)* [[S]], i64 [[INDEX]]
80 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[STRUCT_STRUCT_WITH_PTR]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
81 // CHECK-NEXT:    [[TMP1:%.*]] = bitcast [[STRUCT_STRUCT_WITH_PTR]] addrspace(200)* [[ARRAYIDX]] to i8 addrspace(200)*
82 // CHECK-NEXT:    tail call void @llvm.memcpy.p200i8.p200i8.i64(i8 addrspace(200)* nonnull align 16 dereferenceable(48) [[TMP0]], i8 addrspace(200)* nonnull align 16 dereferenceable(48) [[TMP1]], i64 48, i1 false), !tbaa.struct !13
83 // CHECK-NEXT:    ret void
84 //
test_struct_with_ptr2(struct_with_ptr * s,long index)85 struct_with_ptr test_struct_with_ptr2(struct_with_ptr *s, long index) {
86   return s[index]; // expected-remark{{not setting bounds for array subscript on 'struct_with_ptr * __capability' (array subscript on non-array type)}}
87 }
88 
89 typedef struct {
90   int x;
91   char buf[];
92 } struct_vla;
93 // CHECK-LABEL: define {{[^@]+}}@test_vla_a
94 // CHECK-SAME: (%struct.struct_vla addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
95 // CHECK-NEXT:  entry:
96 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_VLA:%.*]], [[STRUCT_STRUCT_VLA]] addrspace(200)* [[S]], i64 0, i32 1, i64 0
97 // CHECK-NEXT:    [[CUR_OFFSET:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
98 // CHECK-NEXT:    [[CUR_LEN:%.*]] = tail call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
99 // CHECK-NEXT:    [[REMAINING_BYTES:%.*]] = sub i64 [[CUR_LEN]], [[CUR_OFFSET]]
100 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 [[REMAINING_BYTES]])
101 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
102 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
103 // CHECK-NEXT:    ret i32 0
104 //
test_vla_a(struct_vla * s,long index)105 int test_vla_a(struct_vla *s, long index) {
106   // can't set bounds here, have to trust the caller's bounds
107   s->buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char []') to remaining bytes (member is potential variable length array)}}
108   return 0;
109 }
110 // CHECK-LABEL: define {{[^@]+}}@test_vla_b
111 // CHECK-SAME: (i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
112 // CHECK-NEXT:  entry:
113 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca [[STRUCT_STRUCT_VLA:%.*]], align 4, addrspace(200)
114 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_VLA]], [[STRUCT_STRUCT_VLA]] addrspace(200)* [[RETVAL]], i64 0, i32 1, i64 0
115 // CHECK-NEXT:    [[CUR_OFFSET:%.*]] = call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
116 // CHECK-NEXT:    [[CUR_LEN:%.*]] = call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
117 // CHECK-NEXT:    [[REMAINING_BYTES:%.*]] = sub i64 [[CUR_LEN]], [[CUR_OFFSET]]
118 // CHECK-NEXT:    [[TMP1:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 [[REMAINING_BYTES]])
119 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
120 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
121 // CHECK-NEXT:    [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_VLA]], [[STRUCT_STRUCT_VLA]] addrspace(200)* [[RETVAL]], i64 0, i32 0
122 // CHECK-NEXT:    [[DOTFCA_0_LOAD:%.*]] = load i32, i32 addrspace(200)* [[DOTFCA_0_GEP]], align 4
123 // CHECK-NEXT:    [[DOTFCA_0_INSERT:%.*]] = insertvalue { i32 } undef, i32 [[DOTFCA_0_LOAD]], 0
124 // CHECK-NEXT:    ret { i32 } [[DOTFCA_0_INSERT]]
125 //
test_vla_b(long index)126 struct_vla test_vla_b(long index) {
127   struct_vla s2;
128   s2.buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char []') to remaining bytes (member is potential variable length array)}}
129   return s2;           // prevent s2 from being optimzed out
130 }
131 
132 typedef struct {
133   int x;
134   char buf[0];
135 } struct_fake_vla1;
136 // CHECK-LABEL: define {{[^@]+}}@test_fake_vla1
137 // CHECK-SAME: (%struct.struct_fake_vla1 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
138 // CHECK-NEXT:  entry:
139 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_FAKE_VLA1:%.*]], [[STRUCT_STRUCT_FAKE_VLA1]] addrspace(200)* [[S]], i64 0, i32 1, i64 0
140 // CHECK-NEXT:    [[CUR_OFFSET:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
141 // CHECK-NEXT:    [[CUR_LEN:%.*]] = tail call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
142 // CHECK-NEXT:    [[REMAINING_BYTES:%.*]] = sub i64 [[CUR_LEN]], [[CUR_OFFSET]]
143 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 [[REMAINING_BYTES]])
144 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
145 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
146 // CHECK-NEXT:    ret i32 0
147 //
test_fake_vla1(struct_fake_vla1 * s,long index)148 int test_fake_vla1(struct_fake_vla1 *s, long index) {
149   // can't set bounds here, have to trust the caller's bounds
150   s->buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [0]') to remaining bytes (member is potential variable length array)}}
151   return 0;
152 }
153 
154 typedef struct {
155   int x;
156   char buf[1];
157 } struct_fake_vla2;
158 // CHECK-LABEL: define {{[^@]+}}@test_fake_vla2
159 // CHECK-SAME: (%struct.struct_fake_vla2 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
160 // CHECK-NEXT:  entry:
161 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_STRUCT_FAKE_VLA2:%.*]], [[STRUCT_STRUCT_FAKE_VLA2]] addrspace(200)* [[S]], i64 0, i32 1, i64 0
162 // CHECK-NEXT:    [[CUR_OFFSET:%.*]] = tail call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
163 // CHECK-NEXT:    [[CUR_LEN:%.*]] = tail call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* nonnull [[TMP0]])
164 // CHECK-NEXT:    [[REMAINING_BYTES:%.*]] = sub i64 [[CUR_LEN]], [[CUR_OFFSET]]
165 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 [[REMAINING_BYTES]])
166 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
167 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
168 // CHECK-NEXT:    ret i32 0
169 //
test_fake_vla2(struct_fake_vla2 * s,long index)170 int test_fake_vla2(struct_fake_vla2 *s, long index) {
171   // can't set bounds here, have to trust the caller's bounds
172   s->buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [1]') to remaining bytes (member is potential variable length array)}}
173   return 0;
174 }
175 
176 // CHECK-LABEL: define {{[^@]+}}@test_vla_c
177 // CHECK-SAME: (i32 signext [[LEN:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #2
178 // CHECK-NEXT:  entry:
179 // CHECK-NEXT:    [[TMP0:%.*]] = zext i32 [[LEN]] to i64
180 // CHECK-NEXT:    [[VLA:%.*]] = alloca i32, i64 [[TMP0]], align 4, addrspace(200)
181 // CHECK-NEXT:    [[TMP1:%.*]] = bitcast i32 addrspace(200)* [[VLA]] to i8 addrspace(200)*
182 // CHECK-NEXT:    [[CUR_OFFSET:%.*]] = call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* nonnull [[TMP1]])
183 // CHECK-NEXT:    [[CUR_LEN:%.*]] = call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* nonnull [[TMP1]])
184 // CHECK-NEXT:    [[REMAINING_BYTES:%.*]] = sub i64 [[CUR_LEN]], [[CUR_OFFSET]]
185 // CHECK-NEXT:    [[TMP2:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP1]], i64 [[REMAINING_BYTES]])
186 // CHECK-NEXT:    call void @use_buf(i8 addrspace(200)* [[TMP2]]) #10
187 // CHECK-NEXT:    [[CUR_OFFSET4:%.*]] = call i64 @llvm.cheri.cap.offset.get.i64(i8 addrspace(200)* [[TMP2]])
188 // CHECK-NEXT:    [[CUR_LEN5:%.*]] = call i64 @llvm.cheri.cap.length.get.i64(i8 addrspace(200)* [[TMP2]])
189 // CHECK-NEXT:    [[REMAINING_BYTES6:%.*]] = sub i64 [[CUR_LEN5]], [[CUR_OFFSET4]]
190 // CHECK-NEXT:    [[TMP3:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP2]], i64 [[REMAINING_BYTES6]])
191 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP3]] to i32 addrspace(200)*
192 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, i32 addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 [[INDEX]]
193 // CHECK-NEXT:    [[TMP4:%.*]] = load i32, i32 addrspace(200)* [[ARRAYIDX]], align 4, !tbaa !2
194 // CHECK-NEXT:    ret i32 [[TMP4]]
195 //
test_vla_c(int len,long index)196 int test_vla_c(int len, long index) {
197   int buf[len];
198   use_buf(&buf);     // expected-remark{{setting bounds for pointer to 'int [len]' to remaining bytes (variable length array type)}}
199   return buf[index]; // expected-remark{{setting bounds for array decay on 'int [len]' to remaining bytes (array decay on variable size type)}}
200   // expected-remark@-1{{setting bounds for array subscript on 'int [len]' to remaining bytes (array subscript on variable size type)}}
201   // TODO: should avoid setting bounds for array decay inside array subscript (or just optimize away the redundant csetbounds)
202 }
203 
204 typedef signed char v4i8 __attribute__ ((vector_size(4)));
205 v4i8 global_vector = {1, 2, 3, 4};
206 typedef int ext_vector_size_int32_8 __attribute__((ext_vector_type(8)));
207 
208 // No bounds on vector indexing:
209 // CHECK-LABEL: define {{[^@]+}}@test_vector
210 // CHECK-SAME: (i32 inreg [[V4_COERCE:%.*]], i192 [[TMP0:%.*]], i64 inreg [[V8_COERCE0:%.*]], i64 inreg [[V8_COERCE1:%.*]], i64 inreg [[V8_COERCE2:%.*]], i64 inreg [[V8_COERCE3:%.*]]) local_unnamed_addr addrspace(200) #7
211 // CHECK-NEXT:  entry:
212 // CHECK-NEXT:    [[TMP1:%.*]] = bitcast i32 [[V4_COERCE]] to <4 x i8>
213 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[V8_COERCE3]] to <2 x i32>
214 // CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <4 x i8> [[TMP1]], i32 3
215 // CHECK-NEXT:    [[VECEXT3:%.*]] = extractelement <2 x i32> [[TMP2]], i32 1
216 // CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[VECEXT]] to i32
217 // CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[VECEXT3]], [[CONV]]
218 // CHECK-NEXT:    ret i32 [[ADD]]
219 //
test_vector(v4i8 v4,ext_vector_size_int32_8 v8)220 int test_vector(v4i8 v4, ext_vector_size_int32_8 v8) {
221   char c = v4[3];
222   int i = v8[7];
223   return c + i;
224 }
225 
226 // Even with an arbitraty index (backend should guarantee that it is never out of bounds)
227 // CHECK-LABEL: define {{[^@]+}}@test_vector2
228 // CHECK-SAME: (i64 signext [[INDEX:%.*]], i32 inreg [[V4_COERCE:%.*]], i128 [[TMP0:%.*]], i64 inreg [[V8_COERCE0:%.*]], i64 inreg [[V8_COERCE1:%.*]], i64 inreg [[V8_COERCE2:%.*]], i64 inreg [[V8_COERCE3:%.*]]) local_unnamed_addr addrspace(200) #7
229 // CHECK-NEXT:  entry:
230 // CHECK-NEXT:    [[TMP1:%.*]] = bitcast i32 [[V4_COERCE]] to <4 x i8>
231 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast i64 [[V8_COERCE0]] to <2 x i32>
232 // CHECK-NEXT:    [[V8_0_VEC_EXPAND:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> undef, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
233 // CHECK-NEXT:    [[TMP3:%.*]] = bitcast i64 [[V8_COERCE1]] to <2 x i32>
234 // CHECK-NEXT:    [[V8_8_VEC_EXPAND:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> undef, <8 x i32> <i32 undef, i32 undef, i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef>
235 // CHECK-NEXT:    [[V8_8_VECBLEND:%.*]] = shufflevector <8 x i32> [[V8_0_VEC_EXPAND]], <8 x i32> [[V8_8_VEC_EXPAND]], <8 x i32> <i32 0, i32 1, i32 10, i32 11, i32 undef, i32 undef, i32 undef, i32 undef>
236 // CHECK-NEXT:    [[TMP4:%.*]] = bitcast i64 [[V8_COERCE2]] to <2 x i32>
237 // CHECK-NEXT:    [[V8_16_VEC_EXPAND:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> undef, <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 0, i32 1, i32 undef, i32 undef>
238 // CHECK-NEXT:    [[V8_16_VECBLEND:%.*]] = shufflevector <8 x i32> [[V8_8_VECBLEND]], <8 x i32> [[V8_16_VEC_EXPAND]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 undef, i32 undef>
239 // CHECK-NEXT:    [[TMP5:%.*]] = bitcast i64 [[V8_COERCE3]] to <2 x i32>
240 // CHECK-NEXT:    [[V8_24_VEC_EXPAND:%.*]] = shufflevector <2 x i32> [[TMP5]], <2 x i32> undef, <8 x i32> <i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 0, i32 1>
241 // CHECK-NEXT:    [[V8_24_VECBLEND:%.*]] = shufflevector <8 x i32> [[V8_16_VECBLEND]], <8 x i32> [[V8_24_VEC_EXPAND]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 14, i32 15>
242 // CHECK-NEXT:    [[VECEXT:%.*]] = extractelement <4 x i8> [[TMP1]], i64 [[INDEX]]
243 // CHECK-NEXT:    [[VECEXT3:%.*]] = extractelement <8 x i32> [[V8_24_VECBLEND]], i64 [[INDEX]]
244 // CHECK-NEXT:    [[CONV:%.*]] = sext i8 [[VECEXT]] to i32
245 // CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[VECEXT3]], [[CONV]]
246 // CHECK-NEXT:    ret i32 [[ADD]]
247 //
test_vector2(long index,v4i8 v4,ext_vector_size_int32_8 v8)248 int test_vector2(long index, v4i8 v4, ext_vector_size_int32_8 v8) {
249   char c = v4[index];
250   int i = v8[index];
251   return c + i;
252 }
253 
254 // CHECK-LABEL: define {{[^@]+}}@test_ptr_to_array1
255 // CHECK-SAME: ([10 x i32] addrspace(200)* readonly [[ARRAY:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #0
256 // CHECK-NEXT:  entry:
257 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [10 x i32] addrspace(200)* [[ARRAY]] to i8 addrspace(200)*
258 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 40)
259 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to [10 x i32] addrspace(200)*
260 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], [10 x i32] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX]]
261 // CHECK-NEXT:    [[TMP2:%.*]] = load i32, i32 addrspace(200)* [[ARRAYIDX]], align 4, !tbaa !2
262 // CHECK-NEXT:    ret i32 [[TMP2]]
263 //
test_ptr_to_array1(int (* array)[10],long index)264 int test_ptr_to_array1(int (*array)[10], long index) {
265   return (*array)[index]; // expected-remark{{setting sub-object bounds for array subscript on 'int [10]' to 40 bytes}}
266 }
267 // CHECK-LABEL: define {{[^@]+}}@test_ptr_to_array2
268 // CHECK-SAME: ([10 x i32] addrspace(200)* readnone [[ARRAY:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #8
269 // CHECK-NEXT:  entry:
270 // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i32], [10 x i32] addrspace(200)* [[ARRAY]], i64 [[INDEX]], i64 0
271 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast i32 addrspace(200)* [[ARRAYDECAY]] to i8 addrspace(200)*
272 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 40)
273 // CHECK-NEXT:    [[DECAY_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to i32 addrspace(200)*
274 // CHECK-NEXT:    ret i32 addrspace(200)* [[DECAY_WITH_BOUNDS]]
275 //
test_ptr_to_array2(int (* array)[10],long index)276 int* test_ptr_to_array2(int (*array)[10], long index) {
277   return array[index]; // expected-remark{{not setting bounds for array subscript on 'int (* __capability)[10]' (array subscript on non-array type)}}
278   // expected-remark@-1{{setting sub-object bounds for array decay on 'int [10]' to 40 bytes}}
279   // TODO: should avoid setting bounds for array decay inside array subscript (or just optimize away the redundant csetbounds)
280 }
281 // CHECK-LABEL: define {{[^@]+}}@test_ptr_to_array3
282 // CHECK-SAME: ([10 x [5 x i32]] addrspace(200)* readnone [[ARRAY:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #8
283 // CHECK-NEXT:  entry:
284 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [10 x [5 x i32]] addrspace(200)* [[ARRAY]] to i8 addrspace(200)*
285 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 200)
286 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to [10 x [5 x i32]] addrspace(200)*
287 // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x [5 x i32]], [10 x [5 x i32]] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX]], i64 0
288 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast i32 addrspace(200)* [[ARRAYDECAY]] to i8 addrspace(200)*
289 // CHECK-NEXT:    [[TMP3:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP2]], i64 20)
290 // CHECK-NEXT:    [[DECAY_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP3]] to i32 addrspace(200)*
291 // CHECK-NEXT:    ret i32 addrspace(200)* [[DECAY_WITH_BOUNDS]]
292 //
test_ptr_to_array3(int (* array)[10][5],long index)293 int* test_ptr_to_array3(int (*array)[10][5], long index) {
294   return (*array)[index]; // expected-remark{{setting sub-object bounds for array subscript on 'int [10][5]' to 200 bytes}}
295   // expected-remark@-1{{setting sub-object bounds for array decay on 'int [5]' to 20 bytes}}
296   // TODO: should avoid setting bounds for array decay inside array subscript (or just optimize away the redundant csetbounds)
297 }
298 // CHECK-LABEL: define {{[^@]+}}@test_ptr_to_array4
299 // CHECK-SAME: ([10 x [5 x i32]] addrspace(200)* readnone [[ARRAY:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #8
300 // CHECK-NEXT:  entry:
301 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [5 x i32]], [10 x [5 x i32]] addrspace(200)* [[ARRAY]], i64 [[INDEX]]
302 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [10 x [5 x i32]] addrspace(200)* [[ARRAYIDX]] to i8 addrspace(200)*
303 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 200)
304 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to [10 x [5 x i32]] addrspace(200)*
305 // CHECK-NEXT:    [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x [5 x i32]], [10 x [5 x i32]] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX]], i64 0
306 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast i32 addrspace(200)* [[ARRAYDECAY]] to i8 addrspace(200)*
307 // CHECK-NEXT:    [[TMP3:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP2]], i64 20)
308 // CHECK-NEXT:    [[DECAY_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP3]] to i32 addrspace(200)*
309 // CHECK-NEXT:    ret i32 addrspace(200)* [[DECAY_WITH_BOUNDS]]
310 //
test_ptr_to_array4(int (* array)[10][5],long index)311 int* test_ptr_to_array4(int (*array)[10][5], long index) {
312   return array[index][index];
313   // expected-remark@-1{{not setting bounds for array subscript on 'int (* __capability)[10][5]' (array subscript on non-array type)}}
314   // expected-remark@-2{{setting sub-object bounds for array subscript on 'int [10][5]' to 200 bytes}}
315   // expected-remark@-3{{setting sub-object bounds for array decay on 'int [5]' to 20 bytes}}
316   // TODO: should avoid setting bounds for array decay inside array subscript (or just optimize away the redundant csetbounds)
317 }
318 // CHECK-LABEL: define {{[^@]+}}@test_ptr_to_array5
319 // CHECK-SAME: ([10 x [5 x i32]] addrspace(200)* readonly [[ARRAY:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #0
320 // CHECK-NEXT:  entry:
321 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [10 x [5 x i32]] addrspace(200)* [[ARRAY]] to i8 addrspace(200)*
322 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 200)
323 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP1]] to [10 x [5 x i32]] addrspace(200)*
324 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [5 x i32]], [10 x [5 x i32]] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX]]
325 // CHECK-NEXT:    [[TMP2:%.*]] = bitcast [5 x i32] addrspace(200)* [[ARRAYIDX]] to i8 addrspace(200)*
326 // CHECK-NEXT:    [[TMP3:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP2]], i64 20)
327 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS1:%.*]] = bitcast i8 addrspace(200)* [[TMP3]] to [5 x i32] addrspace(200)*
328 // CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds [5 x i32], [5 x i32] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS1]], i64 0, i64 [[INDEX]]
329 // CHECK-NEXT:    [[TMP4:%.*]] = load i32, i32 addrspace(200)* [[ARRAYIDX2]], align 4, !tbaa !2
330 // CHECK-NEXT:    ret i32 [[TMP4]]
331 //
test_ptr_to_array5(int (* array)[10][5],long index)332 int test_ptr_to_array5(int (*array)[10][5], long index) {
333   return (*array)[index][index];
334   // expected-remark@-1{{setting sub-object bounds for array subscript on 'int [10][5]' to 200 bytes}}
335   // expected-remark@-2{{setting sub-object bounds for array subscript on 'int [5]' to 20 bytes}}
336 }
337 
338 // TODO: C++ array references
339 // Some tests derived from BODiagsuite (but modified to handle a few more complicated cases):
340 
341 // Overflow into next struct member
342 typedef struct {
343   char buf[10];
344   int int_field;
345 } my_struct21;
346 
347 // CHECK-LABEL: define {{[^@]+}}@test21a
348 // CHECK-SAME: (%struct.my_struct21 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
349 // CHECK-NEXT:  entry:
350 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT21:%.*]], [[STRUCT_MY_STRUCT21]] addrspace(200)* [[S]], i64 0, i32 0, i64 0
351 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
352 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
353 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
354 // CHECK-NEXT:    ret i32 0
355 //
test21a(my_struct21 * s,long index)356 int test21a(my_struct21 *s, long index) {
357   s->buf[index] = 'A';  // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
358   return 0;
359 }
360 // CHECK-LABEL: define {{[^@]+}}@test21b
361 // CHECK-SAME: (%struct.my_struct21 addrspace(200)* nocapture readnone [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
362 // CHECK-NEXT:  entry:
363 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca { i64, i64 }, align 8, addrspace(200)
364 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast { i64, i64 } addrspace(200)* [[RETVAL]] to i8 addrspace(200)*
365 // CHECK-NEXT:    [[TMP1:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 10)
366 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
367 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
368 // CHECK-NEXT:    [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(200)* [[RETVAL]], i64 0, i32 0
369 // CHECK-NEXT:    [[DOTFCA_0_LOAD:%.*]] = load i64, i64 addrspace(200)* [[DOTFCA_0_GEP]], align 8
370 // CHECK-NEXT:    [[DOTFCA_0_INSERT:%.*]] = insertvalue { i64, i64 } undef, i64 [[DOTFCA_0_LOAD]], 0
371 // CHECK-NEXT:    [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(200)* [[RETVAL]], i64 0, i32 1
372 // CHECK-NEXT:    [[DOTFCA_1_LOAD:%.*]] = load i64, i64 addrspace(200)* [[DOTFCA_1_GEP]], align 8
373 // CHECK-NEXT:    [[DOTFCA_1_INSERT:%.*]] = insertvalue { i64, i64 } [[DOTFCA_0_INSERT]], i64 [[DOTFCA_1_LOAD]], 1
374 // CHECK-NEXT:    ret { i64, i64 } [[DOTFCA_1_INSERT]]
375 //
test21b(my_struct21 * s,long index)376 my_struct21 test21b(my_struct21 *s, long index) {
377   my_struct21 s2;
378   s2.buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
379   return s2; // prevent s2 from being optimzed out
380 }
381 
382 // CHECK-LABEL: define {{[^@]+}}@test21c
383 // CHECK-SAME: (%struct.my_struct21 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
384 // CHECK-NEXT:  entry:
385 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT21:%.*]], [[STRUCT_MY_STRUCT21]] addrspace(200)* [[S]], i64 0, i32 0, i64 0
386 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
387 // CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
388 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX1]], align 1, !tbaa !9
389 // CHECK-NEXT:    ret i32 0
390 //
test21c(my_struct21 * s,long index)391 int test21c(my_struct21 *s, long index) {
392   // Should not set bounds on s here, but should do for buf
393   s[0].buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
394   // expected-remark@-1{{not setting bounds for array subscript on 'my_struct21 * __capability' (array subscript on non-array type)}}
395   return 0;
396 }
397 
398 // CHECK-LABEL: define {{[^@]+}}@test21d
399 // CHECK-SAME: (%struct.my_struct21 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
400 // CHECK-NEXT:  entry:
401 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT21:%.*]], [[STRUCT_MY_STRUCT21]] addrspace(200)* [[S]], i64 0, i32 0, i64 0
402 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
403 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
404 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
405 // CHECK-NEXT:    ret i32 0
406 //
test21d(my_struct21 * s,long index)407 int test21d(my_struct21 *s, long index) {
408   // Should not set bounds on s here, but should do for buf
409   (*s).buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
410   return 0;
411 }
412 
413 // Overflow into padding
414 typedef struct {
415   int int_field;
416   char buf[10];
417 } my_struct22;
418 // CHECK-LABEL: define {{[^@]+}}@test22a
419 // CHECK-SAME: (%struct.my_struct22 addrspace(200)* [[S:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
420 // CHECK-NEXT:  entry:
421 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT22:%.*]], [[STRUCT_MY_STRUCT22]] addrspace(200)* [[S]], i64 0, i32 1, i64 0
422 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 10)
423 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
424 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
425 // CHECK-NEXT:    ret i32 0
426 //
test22a(my_struct22 * s,long index)427 int test22a(my_struct22 *s, long index) {
428   s->buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
429   return 0;
430 }
431 // CHECK-LABEL: define {{[^@]+}}@test22b
432 // CHECK-SAME: (i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
433 // CHECK-NEXT:  entry:
434 // CHECK-NEXT:    [[RETVAL:%.*]] = alloca { i64, i64 }, align 8, addrspace(200)
435 // CHECK-NEXT:    [[TMPCAST:%.*]] = bitcast { i64, i64 } addrspace(200)* [[RETVAL]] to [[STRUCT_MY_STRUCT22:%.*]] addrspace(200)*
436 // CHECK-NEXT:    [[TMP0:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT22]], [[STRUCT_MY_STRUCT22]] addrspace(200)* [[TMPCAST]], i64 0, i32 1, i64 0
437 // CHECK-NEXT:    [[TMP1:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[TMP0]], i64 10)
438 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
439 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
440 // CHECK-NEXT:    [[DOTFCA_0_GEP:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(200)* [[RETVAL]], i64 0, i32 0
441 // CHECK-NEXT:    [[DOTFCA_0_LOAD:%.*]] = load i64, i64 addrspace(200)* [[DOTFCA_0_GEP]], align 8
442 // CHECK-NEXT:    [[DOTFCA_0_INSERT:%.*]] = insertvalue { i64, i64 } undef, i64 [[DOTFCA_0_LOAD]], 0
443 // CHECK-NEXT:    [[DOTFCA_1_GEP:%.*]] = getelementptr inbounds { i64, i64 }, { i64, i64 } addrspace(200)* [[RETVAL]], i64 0, i32 1
444 // CHECK-NEXT:    [[DOTFCA_1_LOAD:%.*]] = load i64, i64 addrspace(200)* [[DOTFCA_1_GEP]], align 8
445 // CHECK-NEXT:    [[DOTFCA_1_INSERT:%.*]] = insertvalue { i64, i64 } [[DOTFCA_0_INSERT]], i64 [[DOTFCA_1_LOAD]], 1
446 // CHECK-NEXT:    ret { i64, i64 } [[DOTFCA_1_INSERT]]
447 //
test22b(long index)448 my_struct22 test22b(long index) {
449   my_struct22 s2;
450   s2.buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
451   return s2; // prevent s2 from being optimzed out
452 }
453 
454 // Overflow in union member
455 typedef union {
456   char buf[10];
457   long otherbuf[10];
458 } my_union25;
459 
460 // CHECK-LABEL: define {{[^@]+}}@test25a
461 // CHECK-SAME: (%union.my_union25 addrspace(200)* [[U:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
462 // CHECK-NEXT:  entry:
463 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[UNION_MY_UNION25:%.*]] addrspace(200)* [[U]] to i8 addrspace(200)*
464 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
465 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
466 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
467 // CHECK-NEXT:    ret i32 0
468 //
test25a(my_union25 * u,long index)469 int test25a(my_union25 *u, long index) {
470   u->buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
471   return 0;
472 }
473 // CHECK-LABEL: define {{[^@]+}}@test25b
474 // CHECK-SAME: (%union.my_union25 addrspace(200)* noalias sret align 8 [[AGG_RESULT:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
475 // CHECK-NEXT:  entry:
476 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[UNION_MY_UNION25:%.*]] addrspace(200)* [[AGG_RESULT]] to i8 addrspace(200)*
477 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
478 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
479 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
480 // CHECK-NEXT:    ret void
481 //
test25b(long index)482 my_union25 test25b(long index) {
483   my_union25 u2;
484   u2.buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
485   return u2; // prevent u2 from being optimzed out
486 }
487 // CHECK-LABEL: define {{[^@]+}}@test25c
488 // CHECK-SAME: (%union.my_union25 addrspace(200)* [[U:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
489 // CHECK-NEXT:  entry:
490 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[UNION_MY_UNION25:%.*]] addrspace(200)* [[U]] to i8 addrspace(200)*
491 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
492 // CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
493 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX1]], align 1, !tbaa !9
494 // CHECK-NEXT:    ret i32 0
495 //
test25c(my_union25 * u,long index)496 int test25c(my_union25 *u, long index) {
497   // Should not set bounds on u here, but should do for buf
498   u[0].buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
499   // expected-remark@-1{{not setting bounds for array subscript on 'my_union25 * __capability' (array subscript on non-array type)}}
500   return 0;
501 }
502 // CHECK-LABEL: define {{[^@]+}}@test25d
503 // CHECK-SAME: (%union.my_union25 addrspace(200)* [[U:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #5
504 // CHECK-NEXT:  entry:
505 // CHECK-NEXT:    [[TMP0:%.*]] = bitcast [[UNION_MY_UNION25:%.*]] addrspace(200)* [[U]] to i8 addrspace(200)*
506 // CHECK-NEXT:    [[TMP1:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP0]], i64 10)
507 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
508 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX]], align 1, !tbaa !9
509 // CHECK-NEXT:    ret i32 0
510 //
test25d(my_union25 * u,long index)511 int test25d(my_union25 *u, long index) {
512   // Should not set bounds on u here, but should do for buf
513   (*u).buf[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf' (array subscript on 'char [10]') to 10 bytes}}
514   return 0;
515 }
516 
517 // simple multidimensional array overflow
518 typedef struct {
519   char buf1[10];
520   char buf2[10];
521 } my_struct28;
522 
523 // CHECK-LABEL: define {{[^@]+}}@test28a
524 // CHECK-SAME: (i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #2
525 // CHECK-NEXT:  entry:
526 // CHECK-NEXT:    [[ARRAY23:%.*]] = alloca [100 x i8], align 1, addrspace(200)
527 // CHECK-NEXT:    [[ARRAY23_SUB:%.*]] = getelementptr inbounds [100 x i8], [100 x i8] addrspace(200)* [[ARRAY23]], i64 0, i64 0
528 // CHECK-NEXT:    call void @llvm.lifetime.start.p200i8(i64 100, i8 addrspace(200)* nonnull [[ARRAY23_SUB]]) #10
529 // CHECK-NEXT:    [[TMP0:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[ARRAY23_SUB]], i64 100)
530 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i8], [100 x i8] addrspace(200)* [[ARRAY23]], i64 0, i64 80
531 // CHECK-NEXT:    [[TMP1:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[ARRAYIDX]], i64 10)
532 // CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP1]], i64 [[INDEX]]
533 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX2]], align 1, !tbaa !9
534 // CHECK-NEXT:    call void @use_buf(i8 addrspace(200)* [[TMP0]]) #10
535 // CHECK-NEXT:    call void @llvm.lifetime.end.p200i8(i64 100, i8 addrspace(200)* nonnull [[ARRAY23_SUB]]) #10
536 // CHECK-NEXT:    ret i32 0
537 //
test28a(long index)538 int test28a(long index) {
539   my_struct28 array2[5];
540   array2[4].buf1[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf1' (array subscript on 'char [10]') to 10 bytes}}
541   // expected-remark@-1{{setting bounds for array subscript on 'my_struct28 [5]' to 100 bytes}}
542   use_buf(&array2); // prevent array from being optimized away
543   // expected-remark@-1{{setting bounds for pointer to 'my_struct28 [5]' to 100 bytes}}
544   return 0;
545 }
546 
547 // CHECK-LABEL: define {{[^@]+}}@test28b
548 // CHECK-SAME: (%struct.my_struct28 addrspace(200)* addrspace(200)* nocapture readonly [[ARRAY1:%.*]], i64 signext [[INDEX:%.*]]) local_unnamed_addr addrspace(200) #9
549 // CHECK-NEXT:  entry:
550 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT28:%.*]] addrspace(200)*, [[STRUCT_MY_STRUCT28]] addrspace(200)* addrspace(200)* [[ARRAY1]], i64 4
551 // CHECK-NEXT:    [[TMP0:%.*]] = load [[STRUCT_MY_STRUCT28]] addrspace(200)*, [[STRUCT_MY_STRUCT28]] addrspace(200)* addrspace(200)* [[ARRAYIDX]], align 16, !tbaa !14
552 // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT28]], [[STRUCT_MY_STRUCT28]] addrspace(200)* [[TMP0]], i64 0, i32 0, i64 0
553 // CHECK-NEXT:    [[TMP2:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP1]], i64 10)
554 // CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP2]], i64 [[INDEX]]
555 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX1]], align 1, !tbaa !9
556 // CHECK-NEXT:    ret i32 0
557 //
test28b(my_struct28 ** array1,long index)558 int test28b(my_struct28 **array1, long index) {
559   array1[4]->buf1[index] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf1' (array subscript on 'char [10]') to 10 bytes}}
560   // expected-remark@-1{{not setting bounds for array subscript on 'my_struct28 * __capability * __capability' (array subscript on non-array type)}}
561   return 0;
562 }
563 
564 // CHECK-LABEL: define {{[^@]+}}@test28c
565 // CHECK-SAME: (i64 signext [[INDEX1:%.*]], i64 signext [[INDEX2:%.*]]) local_unnamed_addr addrspace(200) #2
566 // CHECK-NEXT:  entry:
567 // CHECK-NEXT:    [[ARRAY23:%.*]] = alloca [100 x i8], align 1, addrspace(200)
568 // CHECK-NEXT:    [[ARRAY23_SUB:%.*]] = getelementptr inbounds [100 x i8], [100 x i8] addrspace(200)* [[ARRAY23]], i64 0, i64 0
569 // CHECK-NEXT:    call void @llvm.lifetime.start.p200i8(i64 100, i8 addrspace(200)* nonnull [[ARRAY23_SUB]]) #10
570 // CHECK-NEXT:    [[TMP0:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* nonnull [[ARRAY23_SUB]], i64 100)
571 // CHECK-NEXT:    [[SUBSCRIPT_WITH_BOUNDS:%.*]] = bitcast i8 addrspace(200)* [[TMP0]] to [5 x %struct.my_struct28] addrspace(200)*
572 // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [5 x %struct.my_struct28], [5 x %struct.my_struct28] addrspace(200)* [[SUBSCRIPT_WITH_BOUNDS]], i64 0, i64 [[INDEX1]], i32 0, i64 0
573 // CHECK-NEXT:    [[TMP2:%.*]] = call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP1]], i64 10)
574 // CHECK-NEXT:    [[ARRAYIDX2:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP2]], i64 [[INDEX2]]
575 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX2]], align 1, !tbaa !9
576 // CHECK-NEXT:    call void @use_buf(i8 addrspace(200)* [[TMP0]]) #10
577 // CHECK-NEXT:    call void @llvm.lifetime.end.p200i8(i64 100, i8 addrspace(200)* nonnull [[ARRAY23_SUB]]) #10
578 // CHECK-NEXT:    ret i32 0
579 //
test28c(long index1,long index2)580 int test28c(long index1, long index2) {
581   my_struct28 array2[5];
582   array2[index1].buf1[index2] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf1' (array subscript on 'char [10]') to 10 bytes}}
583   // expected-remark@-1{{setting bounds for array subscript on 'my_struct28 [5]' to 100 bytes}}
584   use_buf(&array2); // prevent array from being optimized away
585   // expected-remark@-1{{setting bounds for pointer to 'my_struct28 [5]' to 100 bytes}}
586   return 0;
587 }
588 
589 // CHECK-LABEL: define {{[^@]+}}@test28d
590 // CHECK-SAME: (%struct.my_struct28 addrspace(200)* addrspace(200)* nocapture readonly [[ARRAY1:%.*]], i64 signext [[INDEX1:%.*]], i64 signext [[INDEX2:%.*]]) local_unnamed_addr addrspace(200) #9
591 // CHECK-NEXT:  entry:
592 // CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT28:%.*]] addrspace(200)*, [[STRUCT_MY_STRUCT28]] addrspace(200)* addrspace(200)* [[ARRAY1]], i64 [[INDEX1]]
593 // CHECK-NEXT:    [[TMP0:%.*]] = load [[STRUCT_MY_STRUCT28]] addrspace(200)*, [[STRUCT_MY_STRUCT28]] addrspace(200)* addrspace(200)* [[ARRAYIDX]], align 16, !tbaa !14
594 // CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_MY_STRUCT28]], [[STRUCT_MY_STRUCT28]] addrspace(200)* [[TMP0]], i64 0, i32 0, i64 0
595 // CHECK-NEXT:    [[TMP2:%.*]] = tail call i8 addrspace(200)* @llvm.cheri.cap.bounds.set.i64(i8 addrspace(200)* [[TMP1]], i64 10)
596 // CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i8, i8 addrspace(200)* [[TMP2]], i64 [[INDEX2]]
597 // CHECK-NEXT:    store i8 65, i8 addrspace(200)* [[ARRAYIDX1]], align 1, !tbaa !9
598 // CHECK-NEXT:    ret i32 0
599 //
test28d(my_struct28 ** array1,long index1,long index2)600 int test28d(my_struct28 **array1, long index1, long index2) {
601   array1[index1]->buf1[index2] = 'A'; // expected-remark{{setting sub-object bounds for field 'buf1' (array subscript on 'char [10]') to 10 bytes}}
602   // expected-remark@-1{{not setting bounds for array subscript on 'my_struct28 * __capability * __capability' (array subscript on non-array type)}}
603   return 0;
604 }
605