1 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NOCOMPAT 2 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-apple-darwin10 -fclang-abi-compat=6.0 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 3 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-scei-ps4 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 4 // RUN: %clang_cc1 %s -emit-llvm -o - -triple=x86_64-sie-ps5 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-V6COMPAT 5 6 extern int int_source(); 7 extern void int_sink(int x); 8 9 namespace test0 { 10 struct A { 11 int aField; 12 int bField; 13 }; 14 15 struct B { 16 int onebit : 2; 17 int twobit : 6; 18 int intField; 19 }; 20 21 struct __attribute__((packed, aligned(2))) C : A, B { 22 }; 23 24 // These accesses should have alignment 4 because they're at offset 0 25 // in a reference with an assumed alignment of 4. 26 // CHECK-LABEL: @_ZN5test01aERNS_1BE 27 void a(B &b) { 28 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev() 29 // CHECK: [[B_P:%.*]] = load ptr, ptr 30 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 31 // CHECK: [[OLD_VALUE:%.*]] = load i8, ptr [[B_P]], align 4 32 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 33 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 34 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 35 // CHECK: store i8 [[T2]], ptr [[B_P]], align 4 36 b.onebit = int_source(); 37 38 // CHECK: [[B_P:%.*]] = load ptr, ptr 39 // CHECK: [[VALUE:%.*]] = load i8, ptr [[B_P]], align 4 40 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 41 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 42 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 43 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]]) 44 int_sink(b.onebit); 45 } 46 47 // These accesses should have alignment 2 because they're at offset 8 48 // in a reference/pointer with an assumed alignment of 2. 49 // CHECK-LABEL: @_ZN5test01bERNS_1CE 50 void b(C &c) { 51 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev() 52 // CHECK: [[C_P:%.*]] = load ptr, ptr 53 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 54 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 55 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 2 56 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 4 57 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 58 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 59 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 60 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 2 61 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 4 62 c.onebit = int_source(); 63 64 // CHECK: [[C_P:%.*]] = load ptr, ptr 65 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 66 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 2 67 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 4 68 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 69 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 70 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 71 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]]) 72 int_sink(c.onebit); 73 } 74 75 // CHECK-LABEL: @_ZN5test01cEPNS_1CE 76 void c(C *c) { 77 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev() 78 // CHECK: [[C_P:%.*]] = load ptr, ptr 79 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 80 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 81 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 2 82 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 4 83 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 84 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 85 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 86 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 2 87 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 4 88 c->onebit = int_source(); 89 90 // CHECK: [[C_P:%.*]] = load ptr, ptr 91 // CHECK: [[P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 92 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[P]], align 2 93 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[P]], align 4 94 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 95 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 96 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 97 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]]) 98 int_sink(c->onebit); 99 } 100 101 // These accesses should have alignment 2 because they're at offset 8 102 // in an alignment-2 variable. 103 // CHECK-LABEL: @_ZN5test01dEv 104 void d() { 105 // CHECK-V6COMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 2 106 // CHECK-NOCOMPAT: [[C_P:%.*]] = alloca [[C:%.*]], align 4 107 C c; 108 109 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev() 110 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 111 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 112 // CHECK-V6COMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 2 113 // CHECK-NOCOMPAT: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 4 114 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 115 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 116 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 117 // CHECK-V6COMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 2 118 // CHECK-NOCOMPAT: store i8 [[T2]], ptr [[FIELD_P]], align 4 119 c.onebit = int_source(); 120 121 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 122 // CHECK-V6COMPAT: [[VALUE:%.*]] = load i8, ptr [[T1]], align 2 123 // CHECK-NOCOMPAT: [[VALUE:%.*]] = load i8, ptr [[T1]], align 4 124 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 125 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 126 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 127 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]]) 128 int_sink(c.onebit); 129 } 130 131 // These accesses should have alignment 8 because they're at offset 8 132 // in an alignment-16 variable. 133 // CHECK-LABEL: @_ZN5test01eEv 134 void e() { 135 // CHECK: [[C_P:%.*]] = alloca [[C:%.*]], align 16 136 __attribute__((aligned(16))) C c; 137 138 // CHECK: [[CALL:%.*]] = call noundef i32 @_Z10int_sourcev() 139 // CHECK: [[FIELD_P:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 140 // CHECK: [[TRUNC:%.*]] = trunc i32 [[CALL]] to i8 141 // CHECK: [[OLD_VALUE:%.*]] = load i8, ptr [[FIELD_P]], align 8 142 // CHECK: [[T0:%.*]] = and i8 [[TRUNC]], 3 143 // CHECK: [[T1:%.*]] = and i8 [[OLD_VALUE]], -4 144 // CHECK: [[T2:%.*]] = or i8 [[T1]], [[T0]] 145 // CHECK: store i8 [[T2]], ptr [[FIELD_P]], align 8 146 c.onebit = int_source(); 147 148 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[C_P]], i64 8 149 // CHECK: [[VALUE:%.*]] = load i8, ptr [[T1]], align 8 150 // CHECK: [[T0:%.*]] = shl i8 [[VALUE]], 6 151 // CHECK: [[T1:%.*]] = ashr i8 [[T0]], 6 152 // CHECK: [[T2:%.*]] = sext i8 [[T1]] to i32 153 // CHECK: call void @_Z8int_sinki(i32 noundef [[T2]]) 154 int_sink(c.onebit); 155 } 156 } 157 158 namespace test1 { 159 struct Array { 160 int elts[4]; 161 }; 162 163 struct A { 164 __attribute__((aligned(16))) Array aArray; 165 }; 166 167 struct B : virtual A { 168 void *bPointer; // puts bArray at offset 16 169 Array bArray; 170 }; 171 172 struct C : virtual A { // must be viable as primary base 173 // Non-empty, nv-size not a multiple of 16. 174 void *cPointer1; 175 void *cPointer2; 176 }; 177 178 // Proof of concept that the non-virtual components of B do not have 179 // to be 16-byte-aligned. 180 struct D : C, B {}; 181 182 // For the following tests, we want to assign into a variable whose 183 // alignment is high enough that it will absolutely not be the 184 // constraint on the memcpy alignment. 185 typedef __attribute__((aligned(64))) Array AlignedArray; 186 187 // CHECK-LABEL: @_ZN5test11aERNS_1AE 188 void a(A &a) { 189 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY:%.*]], align 64 190 // CHECK: [[A_P:%.*]] = load ptr, ptr 191 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A:%.*]], ptr [[A_P]], i32 0, i32 0 192 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false) 193 AlignedArray result = a.aArray; 194 } 195 196 // CHECK-LABEL: @_ZN5test11bERNS_1BE 197 void b(B &b) { 198 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 199 // CHECK: [[B_P:%.*]] = load ptr, ptr 200 // CHECK: [[VPTR:%.*]] = load ptr, ptr [[B_P]], align 8 201 // CHECK: [[T0:%.*]] = getelementptr i8, ptr [[VPTR]], i64 -24 202 // CHECK: [[OFFSET:%.*]] = load i64, ptr [[T0]], align 8 203 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[B_P]], i64 [[OFFSET]] 204 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A]], ptr [[T1]], i32 0, i32 0 205 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false) 206 AlignedArray result = b.aArray; 207 } 208 209 // CHECK-LABEL: @_ZN5test11cERNS_1BE 210 void c(B &b) { 211 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 212 // CHECK: [[B_P:%.*]] = load ptr, ptr 213 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2 214 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false) 215 AlignedArray result = b.bArray; 216 } 217 218 // CHECK-LABEL: @_ZN5test11dEPNS_1BE 219 void d(B *b) { 220 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 221 // CHECK: [[B_P:%.*]] = load ptr, ptr 222 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2 223 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false) 224 AlignedArray result = b->bArray; 225 } 226 227 // CHECK-LABEL: @_ZN5test11eEv 228 void e() { 229 // CHECK: [[B_P:%.*]] = alloca [[B:%.*]], align 16 230 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 231 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[B_P]], i32 0, i32 2 232 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false) 233 B b; 234 AlignedArray result = b.bArray; 235 } 236 237 // CHECK-LABEL: @_ZN5test11fEv 238 void f() { 239 // TODO: we should devirtualize this derived-to-base conversion. 240 // CHECK: [[D_P:%.*]] = alloca [[D:%.*]], align 16 241 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 242 // CHECK: [[VPTR:%.*]] = load ptr, ptr [[D_P]], align 16 243 // CHECK: [[T0:%.*]] = getelementptr i8, ptr [[VPTR]], i64 -24 244 // CHECK: [[OFFSET:%.*]] = load i64, ptr [[T0]], align 8 245 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[D_P]], i64 [[OFFSET]] 246 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[A]], ptr [[T1]], i32 0, i32 0 247 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false) 248 D d; 249 AlignedArray result = d.aArray; 250 } 251 252 // CHECK-LABEL: @_ZN5test11gEv 253 void g() { 254 // CHECK: [[D_P:%.*]] = alloca [[D]], align 16 255 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 256 // CHECK: [[T1:%.*]] = getelementptr inbounds i8, ptr [[D_P]], i64 24 257 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B:%.*]], ptr [[T1]], i32 0, i32 2 258 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 8 [[ARRAY_P]], i64 16, i1 false) 259 D d; 260 AlignedArray result = d.bArray; 261 } 262 263 // CHECK-LABEL: @_ZN5test11hEPA_NS_1BE 264 void h(B (*b)[]) { 265 // CHECK: [[RESULT:%.*]] = alloca [[ARRAY]], align 64 266 // CHECK: [[B_P:%.*]] = load ptr, ptr 267 // CHECK: [[ELEMENT_P:%.*]] = getelementptr inbounds [0 x [[B]]], ptr [[B_P]], i64 0 268 // CHECK: [[ARRAY_P:%.*]] = getelementptr inbounds nuw [[B]], ptr [[ELEMENT_P]], i32 0, i32 2 269 // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 64 [[RESULT]], ptr align 16 [[ARRAY_P]], i64 16, i1 false) 270 AlignedArray result = (*b)->bArray; 271 } 272 } 273 274 // CHECK-LABEL: @_Z22incomplete_array_derefPA_i 275 // CHECK: load i32, ptr {{%.*}}, align 4 276 int incomplete_array_deref(int (*p)[]) { return (*p)[2]; } 277