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