Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// RUN: %clang_cc1 -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts %s 2>/dev/null \
|
2011-09-28 03:12:27 +08:00
|
|
|
// RUN: | FileCheck %s
|
|
|
|
|
|
|
|
#pragma pack(push, 8)
|
|
|
|
|
|
|
|
class B {
|
|
|
|
public:
|
|
|
|
virtual void b(){}
|
|
|
|
int b_field;
|
|
|
|
protected:
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
class A : public B {
|
|
|
|
public:
|
|
|
|
int a_field;
|
|
|
|
virtual void a(){}
|
|
|
|
char one;
|
|
|
|
protected:
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
class D {
|
|
|
|
public:
|
|
|
|
virtual void b(){}
|
|
|
|
double a;
|
|
|
|
};
|
|
|
|
|
|
|
|
class C : public virtual A,
|
|
|
|
public D, public B {
|
|
|
|
public:
|
|
|
|
double c1_field;
|
|
|
|
int c2_field;
|
|
|
|
double c3_field;
|
|
|
|
int c4_field;
|
|
|
|
virtual void foo(){}
|
|
|
|
virtual void bar(){}
|
|
|
|
protected:
|
|
|
|
private:
|
|
|
|
};
|
|
|
|
|
|
|
|
struct BaseStruct
|
|
|
|
{
|
|
|
|
BaseStruct(){}
|
|
|
|
double v0;
|
|
|
|
float v1;
|
|
|
|
C fg;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct DerivedStruct : public BaseStruct {
|
|
|
|
int x;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct G
|
|
|
|
{
|
2011-10-18 08:55:28 +08:00
|
|
|
int g_field;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct H : public G,
|
|
|
|
public virtual D
|
|
|
|
{
|
2011-09-28 03:12:27 +08:00
|
|
|
};
|
|
|
|
|
2011-10-22 06:49:56 +08:00
|
|
|
struct I : public virtual D
|
|
|
|
{
|
|
|
|
virtual ~I(){}
|
|
|
|
double q;
|
|
|
|
};
|
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
struct K
|
|
|
|
{
|
|
|
|
int k;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct L
|
|
|
|
{
|
|
|
|
int l;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct M : public virtual K
|
|
|
|
{
|
|
|
|
int m;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct N : public L, public M
|
|
|
|
{
|
|
|
|
virtual void f(){}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct O : public H, public G {
|
|
|
|
virtual void fo(){}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct P : public M, public virtual L {
|
|
|
|
int p;
|
|
|
|
};
|
|
|
|
|
2011-12-01 08:37:01 +08:00
|
|
|
struct R {};
|
2011-11-08 12:01:03 +08:00
|
|
|
|
2012-05-01 16:55:32 +08:00
|
|
|
class IA {
|
|
|
|
public:
|
|
|
|
virtual ~IA(){}
|
|
|
|
virtual void ia() = 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ICh : public virtual IA {
|
|
|
|
public:
|
|
|
|
virtual ~ICh(){}
|
|
|
|
virtual void ia(){}
|
|
|
|
virtual void iCh(){}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct f {
|
|
|
|
virtual int asd() {return -90;}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct s : public virtual f {
|
|
|
|
virtual ~s(){}
|
|
|
|
int r;
|
|
|
|
virtual int asd() {return -9;}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct sd : virtual s, virtual ICh {
|
|
|
|
virtual ~sd(){}
|
|
|
|
int q;
|
|
|
|
char y;
|
|
|
|
virtual int asd() {return -1;}
|
|
|
|
};
|
|
|
|
struct AV {
|
|
|
|
virtual void foo();
|
|
|
|
};
|
|
|
|
struct BV : AV {
|
|
|
|
};
|
|
|
|
struct CV : virtual BV {
|
|
|
|
CV();
|
|
|
|
virtual void foo();
|
|
|
|
};
|
|
|
|
struct DV : BV {
|
|
|
|
};
|
|
|
|
struct EV : CV, DV {
|
|
|
|
};
|
2011-09-28 03:12:27 +08:00
|
|
|
#pragma pack(pop)
|
|
|
|
|
|
|
|
// This needs only for building layouts.
|
|
|
|
// Without this clang doesn`t dump record layouts.
|
|
|
|
int main() {
|
|
|
|
// This avoid "Can't yet mangle constructors!" for MS ABI.
|
|
|
|
C* c;
|
|
|
|
c->foo();
|
|
|
|
DerivedStruct* v;
|
2011-10-18 08:55:28 +08:00
|
|
|
H* g;
|
2011-09-28 03:12:27 +08:00
|
|
|
BaseStruct* u;
|
2011-10-22 06:49:56 +08:00
|
|
|
I* i;
|
2011-11-08 12:01:03 +08:00
|
|
|
N* n;
|
|
|
|
O* o;
|
|
|
|
P* p;
|
2011-12-01 08:37:01 +08:00
|
|
|
R* r;
|
2012-05-01 16:55:32 +08:00
|
|
|
sd *h;
|
|
|
|
EV *j;
|
2011-09-28 03:12:27 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// CHECK: 0 | class D
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 0 | (D vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 8 | double a
|
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=16, align=8
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: nvsize=16, nvalign=8
|
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK: %class.D = type { i32 (...)**, double }
|
2011-10-22 07:03:08 +08:00
|
|
|
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK: 0 | class B
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 0 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 4 | int b_field
|
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=8, align=4
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: nvsize=8, nvalign=4
|
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK: %class.B = type { i32 (...)**, i32 }
|
2011-10-22 07:03:08 +08:00
|
|
|
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK: 0 | class A
|
|
|
|
// CHECK-NEXT: 0 | class B (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 0 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 4 | int b_field
|
|
|
|
// CHECK-NEXT: 8 | int a_field
|
|
|
|
// CHECK-NEXT: 12 | char one
|
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=16, align=4
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: nvsize=16, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | class C
|
|
|
|
// CHECK-NEXT: 0 | class D (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 0 | (D vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 8 | double a
|
|
|
|
// CHECK-NEXT: 16 | class B (base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 16 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 20 | int b_field
|
|
|
|
// CHECK-NEXT: 24 | (C vbtable pointer)
|
|
|
|
// CHECK-NEXT: 32 | double c1_field
|
|
|
|
// CHECK-NEXT: 40 | int c2_field
|
|
|
|
// CHECK-NEXT: 48 | double c3_field
|
|
|
|
// CHECK-NEXT: 56 | int c4_field
|
|
|
|
// CHECK-NEXT: 64 | class A (virtual base)
|
|
|
|
// CHECK-NEXT: 64 | class B (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 64 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 68 | int b_field
|
|
|
|
// CHECK-NEXT: 72 | int a_field
|
|
|
|
// CHECK-NEXT: 76 | char one
|
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=80, align=8
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: nvsize=64, nvalign=8
|
2011-10-22 07:03:08 +08:00
|
|
|
|
|
|
|
// CHECK: %class.A = type { %class.B, i32, i8 }
|
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK: %class.C = type { %class.D, %class.B, i32*, double, i32, double, i32, [4 x i8], %class.A }
|
|
|
|
// CHECK: %class.C.base = type { %class.D, %class.B, i32*, double, i32, double, i32 }
|
2011-10-22 07:03:08 +08:00
|
|
|
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK: 0 | struct BaseStruct
|
|
|
|
// CHECK-NEXT: 0 | double v0
|
|
|
|
// CHECK-NEXT: 8 | float v1
|
|
|
|
// CHECK-NEXT: 16 | class C fg
|
|
|
|
// CHECK-NEXT: 16 | class D (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 16 | (D vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 24 | double a
|
|
|
|
// CHECK-NEXT: 32 | class B (base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 32 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 36 | int b_field
|
|
|
|
// CHECK-NEXT: 40 | (C vbtable pointer)
|
|
|
|
// CHECK-NEXT: 48 | double c1_field
|
|
|
|
// CHECK-NEXT: 56 | int c2_field
|
|
|
|
// CHECK-NEXT: 64 | double c3_field
|
|
|
|
// CHECK-NEXT: 72 | int c4_field
|
|
|
|
// CHECK-NEXT: 80 | class A (virtual base)
|
|
|
|
// CHECK-NEXT: 80 | class B (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 80 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 84 | int b_field
|
|
|
|
// CHECK-NEXT: 88 | int a_field
|
|
|
|
// CHECK-NEXT: 92 | char one
|
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=80, align=8
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: nvsize=64, nvalign=8
|
2011-09-28 03:12:27 +08:00
|
|
|
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK: sizeof=96, align=8
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: nvsize=96, nvalign=8
|
|
|
|
|
2011-10-22 07:03:08 +08:00
|
|
|
// CHECK: %struct.BaseStruct = type { double, float, %class.C }
|
|
|
|
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK: 0 | struct DerivedStruct
|
|
|
|
// CHECK-NEXT: 0 | struct BaseStruct (base)
|
|
|
|
// CHECK-NEXT: 0 | double v0
|
|
|
|
// CHECK-NEXT: 8 | float v1
|
|
|
|
// CHECK-NEXT: 16 | class C fg
|
|
|
|
// CHECK-NEXT: 16 | class D (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 16 | (D vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 24 | double a
|
|
|
|
// CHECK-NEXT: 32 | class B (base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 32 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 36 | int b_field
|
|
|
|
// CHECK-NEXT: 40 | (C vbtable pointer)
|
|
|
|
// CHECK-NEXT: 48 | double c1_field
|
|
|
|
// CHECK-NEXT: 56 | int c2_field
|
|
|
|
// CHECK-NEXT: 64 | double c3_field
|
|
|
|
// CHECK-NEXT: 72 | int c4_field
|
|
|
|
// CHECK-NEXT: 80 | class A (virtual base)
|
|
|
|
// CHECK-NEXT: 80 | class B (primary base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 80 | (B vftable pointer)
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: 84 | int b_field
|
|
|
|
// CHECK-NEXT: 88 | int a_field
|
|
|
|
// CHECK-NEXT: 92 | char one
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=80, align=8
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: nvsize=64, nvalign=8
|
2011-09-28 03:12:27 +08:00
|
|
|
|
|
|
|
// CHECK: 96 | int x
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=104, align=8
|
2011-09-28 03:12:27 +08:00
|
|
|
// CHECK-NEXT: nvsize=104, nvalign=8
|
2011-10-18 08:55:28 +08:00
|
|
|
|
2011-10-22 07:03:08 +08:00
|
|
|
// CHECK: %struct.DerivedStruct = type { %struct.BaseStruct, i32 }
|
|
|
|
|
2011-10-18 08:55:28 +08:00
|
|
|
// CHECK: 0 | struct G
|
|
|
|
// CHECK-NEXT: 0 | int g_field
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2011-10-18 08:55:28 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | struct H
|
|
|
|
// CHECK-NEXT: 0 | struct G (base)
|
|
|
|
// CHECK-NEXT: 0 | int g_field
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 4 | (H vbtable pointer)
|
2011-10-18 08:55:28 +08:00
|
|
|
// CHECK-NEXT: 8 | class D (virtual base)
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK-NEXT: 8 | (D vftable pointer)
|
2011-10-18 08:55:28 +08:00
|
|
|
// CHECK-NEXT: 16 | double a
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=24, align=8
|
2014-01-09 08:48:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=8, nvalign=8
|
2011-10-22 06:49:56 +08:00
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK: %struct.H = type { %struct.G, i32*, %class.D }
|
2011-10-22 07:03:08 +08:00
|
|
|
|
2011-10-22 06:49:56 +08:00
|
|
|
// CHECK: 0 | struct I
|
|
|
|
// CHECK-NEXT: 0 | (I vftable pointer)
|
|
|
|
// CHECK-NEXT: 8 | (I vbtable pointer)
|
|
|
|
// CHECK-NEXT: 16 | double q
|
|
|
|
// CHECK-NEXT: 24 | class D (virtual base)
|
|
|
|
// CHECK-NEXT: 24 | (D vftable pointer)
|
|
|
|
// CHECK-NEXT: 32 | double a
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=40, align=8
|
2011-10-18 08:55:28 +08:00
|
|
|
// CHECK-NEXT: nvsize=24, nvalign=8
|
2011-10-22 07:03:08 +08:00
|
|
|
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK: %struct.I = type { i32 (...)**, [4 x i8], i32*, double, %class.D }
|
|
|
|
// CHECK: %struct.I.base = type { i32 (...)**, [4 x i8], i32*, double }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct L
|
|
|
|
// CHECK-NEXT: 0 | int l
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | struct K
|
|
|
|
// CHECK-NEXT: 0 | int k
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | struct M
|
|
|
|
// CHECK-NEXT: 0 | (M vbtable pointer)
|
|
|
|
// CHECK-NEXT: 4 | int m
|
|
|
|
// CHECK-NEXT: 8 | struct K (virtual base)
|
|
|
|
// CHECK-NEXT: 8 | int k
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=12, align=4
|
2011-11-08 12:01:03 +08:00
|
|
|
|
|
|
|
//CHECK: %struct.M = type { i32*, i32, %struct.K }
|
|
|
|
//CHECK: %struct.M.base = type { i32*, i32 }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct N
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: 0 | (N vftable pointer)
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK-NEXT: 4 | struct L (base)
|
|
|
|
// CHECK-NEXT: 4 | int l
|
|
|
|
// CHECK-NEXT: 8 | struct M (base)
|
|
|
|
// CHECK-NEXT: 8 | (M vbtable pointer)
|
|
|
|
// CHECK-NEXT: 12 | int m
|
|
|
|
// CHECK-NEXT: 16 | struct K (virtual base)
|
|
|
|
// CHECK-NEXT: 16 | int k
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=20, align=4
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK-NEXT: nvsize=16, nvalign=4
|
|
|
|
|
|
|
|
//CHECK: %struct.N = type { i32 (...)**, %struct.L, %struct.M.base, %struct.K }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct O
|
|
|
|
// CHECK-NEXT: 0 | (O vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: 8 | struct H (base)
|
|
|
|
// CHECK-NEXT: 8 | struct G (base)
|
|
|
|
// CHECK-NEXT: 8 | int g_field
|
|
|
|
// CHECK-NEXT: 12 | (H vbtable pointer)
|
|
|
|
// CHECK-NEXT: 16 | struct G (base)
|
|
|
|
// CHECK-NEXT: 16 | int g_field
|
|
|
|
// CHECK-NEXT: 24 | class D (virtual base)
|
|
|
|
// CHECK-NEXT: 24 | (D vftable pointer)
|
|
|
|
// CHECK-NEXT: 32 | double a
|
|
|
|
// CHECK-NEXT: | [sizeof=40, align=8
|
|
|
|
// CHECK-NEXT: | nvsize=24, nvalign=8]
|
|
|
|
|
Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// CHECK: struct.O = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, %class.D }
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK: struct.O.base = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8] }
|
2011-11-08 12:01:03 +08:00
|
|
|
|
|
|
|
|
|
|
|
// CHECK: 0 | struct P
|
|
|
|
// CHECK-NEXT: 0 | struct M (base)
|
|
|
|
// CHECK-NEXT: 0 | (M vbtable pointer)
|
|
|
|
// CHECK-NEXT: 4 | int m
|
|
|
|
// CHECK-NEXT: 8 | int p
|
|
|
|
// CHECK-NEXT: 12 | struct K (virtual base)
|
|
|
|
// CHECK-NEXT: 12 | int k
|
|
|
|
// CHECK-NEXT: 16 | struct L (virtual base)
|
|
|
|
// CHECK-NEXT: 16 | int l
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=20, align=4
|
2011-11-08 12:01:03 +08:00
|
|
|
// CHECK-NEXT: nvsize=12, nvalign=4
|
|
|
|
|
|
|
|
//CHECK: %struct.P = type { %struct.M.base, i32, %struct.K, %struct.L }
|
2011-12-01 08:37:01 +08:00
|
|
|
|
|
|
|
// CHECK: 0 | struct R (empty)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=1, align=1
|
2011-12-01 08:37:01 +08:00
|
|
|
// CHECK-NEXT: nvsize=0, nvalign=1
|
|
|
|
|
|
|
|
//CHECK: %struct.R = type { i8 }
|
2012-05-01 16:55:32 +08:00
|
|
|
|
|
|
|
// CHECK: 0 | struct f
|
|
|
|
// CHECK-NEXT: 0 | (f vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | struct s
|
|
|
|
// CHECK-NEXT: 0 | (s vftable pointer)
|
|
|
|
// CHECK-NEXT: 4 | (s vbtable pointer)
|
|
|
|
// CHECK-NEXT: 8 | int r
|
|
|
|
// CHECK-NEXT: 12 | (vtordisp for vbase f)
|
|
|
|
// CHECK-NEXT: 16 | struct f (virtual base)
|
|
|
|
// CHECK-NEXT: 16 | (f vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=20, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=12, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | class IA
|
|
|
|
// CHECK-NEXT: 0 | (IA vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | class ICh
|
|
|
|
// CHECK-NEXT: 0 | (ICh vftable pointer)
|
|
|
|
// CHECK-NEXT: 4 | (ICh vbtable pointer)
|
|
|
|
// CHECK-NEXT: 8 | (vtordisp for vbase IA)
|
|
|
|
// CHECK-NEXT: 12 | class IA (virtual base)
|
|
|
|
// CHECK-NEXT: 12 | (IA vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=16, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=8, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: 0 | struct sd
|
|
|
|
// CHECK-NEXT: 0 | (sd vbtable pointer)
|
|
|
|
// CHECK-NEXT: 4 | int q
|
|
|
|
// CHECK-NEXT: 8 | char y
|
|
|
|
// CHECK-NEXT: 12 | (vtordisp for vbase f)
|
|
|
|
// CHECK-NEXT: 16 | struct f (virtual base)
|
|
|
|
// CHECK-NEXT: 16 | (f vftable pointer)
|
|
|
|
// CHECK-NEXT: 20 | struct s (virtual base)
|
|
|
|
// CHECK-NEXT: 20 | (s vftable pointer)
|
|
|
|
// CHECK-NEXT: 24 | (s vbtable pointer)
|
|
|
|
// CHECK-NEXT: 28 | int r
|
|
|
|
// CHECK-NEXT: 32 | (vtordisp for vbase IA)
|
|
|
|
// CHECK-NEXT: 36 | class IA (virtual base)
|
|
|
|
// CHECK-NEXT: 36 | (IA vftable pointer)
|
|
|
|
// CHECK-NEXT: 40 | class ICh (virtual base)
|
|
|
|
// CHECK-NEXT: 40 | (ICh vftable pointer)
|
|
|
|
// CHECK-NEXT: 44 | (ICh vbtable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=48, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=12, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: %struct.f = type { i32 (...)** }
|
Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// CHECK: %struct.s = type { i32 (...)**, i32*, i32, i32, %struct.f }
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK: %class.IA = type { i32 (...)** }
|
Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// CHECK: %class.ICh = type { i32 (...)**, i32*, i32, %class.IA }
|
|
|
|
// CHECK: %struct.sd = type { i32*, i32, i8, i32, %struct.f, %struct.s.base, i32, %class.IA, %class.ICh.base }
|
2012-05-01 16:55:32 +08:00
|
|
|
|
|
|
|
// CHECK: 0 | struct AV
|
|
|
|
// CHECK-NEXT: 0 | (AV vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
|
|
|
|
// CHECK: 0 | struct BV
|
|
|
|
// CHECK-NEXT: 0 | struct AV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | (AV vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
|
|
|
|
// CHECK: 0 | struct CV
|
|
|
|
// CHECK-NEXT: 0 | (CV vbtable pointer)
|
|
|
|
// CHECK-NEXT: 4 | (vtordisp for vbase BV)
|
|
|
|
// CHECK-NEXT: 8 | struct BV (virtual base)
|
|
|
|
// CHECK-NEXT: 8 | struct AV (primary base)
|
|
|
|
// CHECK-NEXT: 8 | (AV vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=12, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: %struct.AV = type { i32 (...)** }
|
|
|
|
// CHECK: %struct.BV = type { %struct.AV }
|
Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// CHECK: %struct.CV = type { i32*, i32, %struct.BV }
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK: %struct.CV.base = type { i32* }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct DV
|
|
|
|
// CHECK-NEXT: 0 | struct BV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | struct AV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | (AV vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=4, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
|
|
|
|
// CHECK: %struct.DV = type { %struct.BV }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct EV
|
|
|
|
// CHECK-NEXT: 0 | struct DV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | struct BV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | struct AV (primary base)
|
|
|
|
// CHECK-NEXT: 0 | (AV vftable pointer)
|
2014-02-28 09:03:09 +08:00
|
|
|
// CHECK-NEXT: 4 | struct CV (base)
|
|
|
|
// CHECK-NEXT: 4 | (CV vbtable pointer)
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: 8 | (vtordisp for vbase BV)
|
|
|
|
// CHECK-NEXT: 12 | struct BV (virtual base)
|
|
|
|
// CHECK-NEXT: 12 | struct AV (primary base)
|
|
|
|
// CHECK-NEXT: 12 | (AV vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=16, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=8, nvalign=4
|
|
|
|
|
Complete Rewrite of CGRecordLayoutBuilder
CGRecordLayoutBuilder was aging, complex, multi-pass, and shows signs of
existing before ASTRecordLayoutBuilder. It redundantly performed many
layout operations that are now performed by ASTRecordLayoutBuilder and
asserted that the results were the same. With the addition of support
for the MS-ABI, such as placement of vbptrs, vtordisps, different
bitfield layout and a variety of other features, CGRecordLayoutBuilder
was growing unwieldy in its redundancy.
This patch re-architects CGRecordLayoutBuilder to not perform any
redundant layout but rather, as directly as possible, lower an
ASTRecordLayout to an llvm::type. The new architecture is significantly
smaller and simpler than the CGRecordLayoutBuilder and contains fewer
ABI-specific code paths. It's also one pass.
The architecture of the new system is described in the comments. For the
most part, the new system simply takes all of the fields and bases from
an ASTRecordLayout, sorts them, inserts padding and dumps a record.
Bitfields, unions and primary virtual bases make this process a bit more
complicated. See the inline comments.
In addition, this patch updates a few lit tests due to the fact that the
new system computes more accurate llvm types than CGRecordLayoutBuilder.
Each change is commented individually in the review.
Differential Revision: http://llvm-reviews.chandlerc.com/D2795
llvm-svn: 201907
2014-02-22 07:49:50 +08:00
|
|
|
// CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, i32, %struct.BV }
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK: %struct.EV.base = type { %struct.DV, %struct.CV.base }
|
|
|
|
|
|
|
|
// Overriding a method means that all the vbases containing that
|
2013-10-12 04:19:00 +08:00
|
|
|
// method need a vtordisp. Note: this code will cause an error in cl.exe.
|
2012-05-01 16:55:32 +08:00
|
|
|
namespace test1 {
|
|
|
|
struct A { virtual void foo(); };
|
|
|
|
struct B : A {};
|
2012-05-01 16:59:06 +08:00
|
|
|
struct C : virtual A, virtual B { C(); virtual void foo(); };
|
2012-05-01 16:55:32 +08:00
|
|
|
void test() { C *c; }
|
|
|
|
|
|
|
|
// CHECK: 0 | struct test1::C
|
|
|
|
// CHECK-NEXT: 0 | (C vbtable pointer)
|
|
|
|
// CHECK-NEXT: 4 | (vtordisp for vbase A)
|
|
|
|
// CHECK-NEXT: 8 | struct test1::A (virtual base)
|
|
|
|
// CHECK-NEXT: 8 | (A vftable pointer)
|
|
|
|
// CHECK-NEXT: 12 | (vtordisp for vbase B)
|
|
|
|
// CHECK-NEXT: 16 | struct test1::B (virtual base)
|
|
|
|
// CHECK-NEXT: 16 | struct test1::A (primary base)
|
|
|
|
// CHECK-NEXT: 16 | (A vftable pointer)
|
2013-10-12 04:19:00 +08:00
|
|
|
// CHECK-NEXT: sizeof=20, align=4
|
2012-05-01 16:55:32 +08:00
|
|
|
// CHECK-NEXT: nvsize=4, nvalign=4
|
|
|
|
}
|