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



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@201907 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Warren Hunt 2014-02-21 23:49:50 +00:00
parent 9298d56cfb
commit 21db05d136
15 changed files with 607 additions and 1005 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple i386-unknown-unknown %s -emit-llvm -o - | FileCheck %s
//
// CHECK: struct.object_entry = type { [4 x i8] }
// CHECK: struct.object_entry = type { i32 }
struct object_entry {
unsigned int type:3, pack_id:16, depth:13;

View File

@ -11,7 +11,7 @@
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: RecordDecl{{.*}}s0
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%struct.s0 = type <{ [3 x i8] }>
// CHECK-RECORD: LLVMType:%struct.s0 = type { [3 x i8] }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:24 IsSigned:1 StorageSize:24 StorageAlignment:1>
@ -51,7 +51,7 @@ unsigned long long test_0() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: RecordDecl{{.*}}s1
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%struct.s1 = type <{ [3 x i8] }>
// CHECK-RECORD: LLVMType:%struct.s1 = type { [3 x i8] }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:10 IsSigned:1 StorageSize:24 StorageAlignment:1>
@ -99,7 +99,7 @@ unsigned long long test_1() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: RecordDecl{{.*}}u2
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%union.u2 = type <{ i8 }>
// CHECK-RECORD: LLVMType:%union.u2 = type { i8 }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:3 IsSigned:0 StorageSize:8 StorageAlignment:1>
@ -271,7 +271,7 @@ _Bool test_6() {
// CHECK-RECORD: *** Dumping IRgen Record Layout
// CHECK-RECORD: Record: RecordDecl{{.*}}s7
// CHECK-RECORD: Layout: <CGRecordLayout
// CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, [3 x i8], [4 x i8], [12 x i8] }
// CHECK-RECORD: LLVMType:%struct.s7 = type { i32, i32, i32, i8, i32, [12 x i8] }
// CHECK-RECORD: IsZeroInitializable:1
// CHECK-RECORD: BitFields:[
// CHECK-RECORD: <CGBitFieldInfo Offset:0 Size:5 IsSigned:1 StorageSize:8 StorageAlignment:4>

View File

@ -60,6 +60,6 @@ struct YBitfield gbitfield;
unsigned test7() {
// CHECK: @test7
// CHECK: load i32* bitcast (%struct.XBitfield* getelementptr inbounds (%struct.YBitfield* @gbitfield, i32 0, i32 1) to i32*), align 4
// CHECK: load i32* getelementptr inbounds (%struct.YBitfield* @gbitfield, i32 0, i32 1, i32 0), align 4
return gbitfield.y.b2;
}

View File

@ -1,11 +1,11 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o %t
// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm %s -o - | FileCheck %s
typedef struct _attrs {
unsigned file_attributes;
unsigned char filename_length;
} __attribute__((__packed__)) attrs;
// RUN: grep "union._attr_union = type <{ i32, i8 }>" %t
// CHECK: %union._attr_union = type <{ i32, i8 }>
typedef union _attr_union {
attrs file_attrs;
unsigned owner_id;

View File

@ -53,12 +53,12 @@ struct S4
int e;
} s4;
// CHECK: [[struct_ref:%[a-zA-Z0-9_.]+]] = type <{ [[struct_ref]]* }>
// CHECK: [[struct_ref:%[a-zA-Z0-9_.]+]] = type { [[struct_ref]]* }
// CHECK: [[struct_S:%[a-zA-Z0-9_.]+]] = type { [3 x i8], [[struct_T:%[a-zA-Z0-9_.]+]], [[struct_T2:%[a-zA-Z0-9_.]+]] }
// CHECK: [[struct_T]] = type <{ i8, i32 }>
// CHECK: [[struct_T2]] = type { i8, i32 }
// CHECK: %struct.S3 = type <{ [3 x i8], i8, %struct.T3, [2 x i8], %struct.T32 }>
// CHECK: %struct.S3 = type { [3 x i8], i8, %struct.T3, %struct.T32 }
// CHECK: %struct.T3 = type <{ i8, i8, i32 }>
// CHECK: %struct.T32 = type { i8, i32 }
// CHECK: %struct.S4 = type { [3 x i8], %struct.T4, i32 }

View File

@ -4,7 +4,7 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin9 %s -emit-llvm -o - | FileCheck -check-prefix CHECK-X64 %s
// CHECK-X64: %struct.s0 = type <{ i64, i64, i32, [12 x i32] }>
// CHECK-X64: %struct.s1 = type <{ [15 x i32], %struct.s0 }>
// CHECK-X64: %struct.s1 = type { [15 x i32], %struct.s0 }
// rdar://problem/7095436
#pragma pack(4)
@ -20,4 +20,3 @@ struct s1 {
int a[15];
struct s0 b;
} b;

View File

@ -1,13 +1,13 @@
// RUN: %clang_cc1 < %s -emit-llvm > %t1 -triple=i686-apple-darwin9
// RUN: grep "STest1 = type { i32, \[4 x i16\], double }" %t1
// RUN: grep "STest2 = type { i16, i16, i32, i32 }" %t1
// RUN: grep "STest3 = type { i8, i16, i32 }" %t1
// RUN: grep "STestB1 = type { i8, i8 }" %t1
// RUN: grep "STestB2 = type { i8, i8, i8 }" %t1
// RUN: grep "STestB3 = type { i8, i8 }" %t1
// RUN: grep "STestB4 = type { i8, i8, i8, i8 }" %t1
// RUN: grep "STestB5 = type { i8, i8, \[2 x i8\], i8, i8 }" %t1
// RUN: grep "STestB6 = type { i8, i8, \[2 x i8\] }" %t1
// RUN: %clang_cc1 %s -emit-llvm -triple=i686-apple-darwin9 -o - | FileCheck %s
// CHECK: STest1 = type { i32, [4 x i16], double }
// CHECK: STest2 = type { i16, i16, i32, i32 }
// CHECK: STest3 = type { i8, i16, i32 }
// CHECK: STestB1 = type { i8, i8 }
// CHECK: STestB2 = type { i8, i8, i8 }
// CHECK: STestB3 = type { i8, i8 }
// CHECK: STestB4 = type { i8, i8, i8, i8 }
// CHECK: STestB5 = type { i8, i16, i8 }
// CHECK: STestB6 = type { i8, i8, i16 }
// Test struct layout for x86-darwin target
struct STest1 {int x; short y[4]; double z; } st1;

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -emit-llvm < %s | FileCheck %s
// RUN: %clang_cc1 -triple=%itanium_abi_triple -emit-llvm < %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-IT
// RUN: %clang_cc1 -triple=%ms_abi_triple -emit-llvm < %s | FileCheck %s -check-prefix CHECK -check-prefix CHECK-MS
int S;
volatile int vS;
@ -83,10 +84,12 @@ int main() {
// CHECK: load volatile i32* getelementptr {{.*}} @vF3
// CHECK: store i32 {{.*}}, i32* [[I]]
i=BF.x;
// CHECK: load i8* getelementptr {{.*}} @BF
// CHECK-IT: load i8* getelementptr {{.*}} @BF
// CHECK-MS: load i32* getelementptr {{.*}} @BF
// CHECK: store i32 {{.*}}, i32* [[I]]
i=vBF.x;
// CHECK: load volatile i8* getelementptr {{.*}} @vBF
// CHECK-IT: load volatile i8* getelementptr {{.*}} @vBF
// CHECK-MS: load volatile i32* getelementptr {{.*}} @vBF
// CHECK: store i32 {{.*}}, i32* [[I]]
i=V[3];
// CHECK: load <4 x i32>* @V
@ -154,12 +157,16 @@ int main() {
// CHECK: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vF3
BF.x=i;
// CHECK: load i32* [[I]]
// CHECK: load i8* getelementptr {{.*}} @BF
// CHECK: store i8 {{.*}}, i8* getelementptr {{.*}} @BF
// CHECK-IT: load i8* getelementptr {{.*}} @BF
// CHECK-MS: load i32* getelementptr {{.*}} @BF
// CHECK-IT: store i8 {{.*}}, i8* getelementptr {{.*}} @BF
// CHECK-MS: store i32 {{.*}}, i32* getelementptr {{.*}} @BF
vBF.x=i;
// CHECK: load i32* [[I]]
// CHECK: load volatile i8* getelementptr {{.*}} @vBF
// CHECK: store volatile i8 {{.*}}, i8* getelementptr {{.*}} @vBF
// CHECK-IT: load volatile i8* getelementptr {{.*}} @vBF
// CHECK-MS: load volatile i32* getelementptr {{.*}} @vBF
// CHECK-IT: store volatile i8 {{.*}}, i8* getelementptr {{.*}} @vBF
// CHECK-MS: store volatile i32 {{.*}}, i32* getelementptr {{.*}} @vBF
V[3]=i;
// CHECK: load i32* [[I]]
// CHECK: load <4 x i32>* @V

View File

@ -12,7 +12,7 @@ union Test2 {
int : 6;
} t2;
// CHECK-LP64: %union.Test3 = type { [2 x i8] }
// CHECK-LP64: %union.Test3 = type { i16 }
union Test3 {
int : 9;
} t3;

View File

@ -39,7 +39,7 @@ namespace Test5 {
char a;
};
// CHECK: %"struct.Test5::B" = type { [9 x i8], i8, i8, [5 x i8] }
// CHECK: %"struct.Test5::B" = type { %"struct.Test5::A.base", i8, i8, [5 x i8] }
struct B : A {
char b : 1;
char c;

View File

@ -139,12 +139,10 @@ void f(B b1) {
// CHECK: define linkonce_odr [[A:%.*]]* @_ZN12rdar138169401AaSERKS0_(
// CHECK: [[THIS:%.*]] = load [[A]]**
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16*
// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]**
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1
// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16*
// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8*
// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8*
// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T0]] to i8*
// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T2]] to i8*
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false)
// CHECK-NEXT: ret [[A]]* [[THIS]]
@ -153,12 +151,10 @@ void f(B b1) {
// CHECK-NEXT: [[T0:%.*]] = bitcast [[A]]* [[THIS]] to i8***
// CHECK-NEXT: store i8** getelementptr inbounds ([4 x i8*]* @_ZTVN12rdar138169401AE, i64 0, i64 2), i8*** [[T0]]
// CHECK-NEXT: [[T0:%.*]] = getelementptr inbounds [[A]]* [[THIS]], i32 0, i32 1
// CHECK-NEXT: [[T1:%.*]] = bitcast [2 x i8]* [[T0]] to i16*
// CHECK-NEXT: [[OTHER:%.*]] = load [[A]]**
// CHECK-NEXT: [[T2:%.*]] = getelementptr inbounds [[A]]* [[OTHER]], i32 0, i32 1
// CHECK-NEXT: [[T3:%.*]] = bitcast [2 x i8]* [[T2]] to i16*
// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T1]] to i8*
// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T3]] to i8*
// CHECK-NEXT: [[T4:%.*]] = bitcast i16* [[T0]] to i8*
// CHECK-NEXT: [[T5:%.*]] = bitcast i16* [[T2]] to i8*
// CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* [[T4]], i8* [[T5]], i64 8, i32 8, i1 false)
// CHECK-NEXT: ret void

View File

@ -11,7 +11,8 @@ struct Derived_1 : virtual Base
#pragma pack(1)
struct Derived_2 : Derived_1 {
// CHECK: %struct.Derived_2 = type <{ [5 x i8], %struct.Base }>
// CHECK: %struct.Derived_2 = type { %struct.Derived_1.base, %struct.Base }
// CHECK: %struct.Derived_1.base = type <{ i32 (...)**, i8 }>
};
Derived_2 x;

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>&1
// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm-only -fdump-vtable-layouts > %t 2>/dev/null
// RUN: FileCheck --check-prefix=CHECK-1 %s < %t
// RUN: FileCheck --check-prefix=CHECK-2 %s < %t
// RUN: FileCheck --check-prefix=CHECK-3 %s < %t

View File

@ -1,4 +1,4 @@
// RUN: %clang_cc1 -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts %s 2>&1 \
// RUN: %clang_cc1 -emit-llvm-only -triple i686-pc-win32 -fdump-record-layouts %s 2>/dev/null \
// RUN: | FileCheck %s
#pragma pack(push, 8)
@ -354,7 +354,7 @@ int main() {
// CHECK-NEXT: | [sizeof=40, align=8
// CHECK-NEXT: | nvsize=24, nvalign=8]
// CHECK: struct.O = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8], %class.D }
// CHECK: struct.O = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, %class.D }
// CHECK: struct.O.base = type { i32 (...)**, [4 x i8], %struct.H.base, %struct.G, [4 x i8] }
@ -428,10 +428,10 @@ int main() {
// CHECK-NEXT: nvsize=12, nvalign=4
// CHECK: %struct.f = type { i32 (...)** }
// CHECK: %struct.s = type { i32 (...)**, i32*, i32, [4 x i8], %struct.f }
// CHECK: %struct.s = type { i32 (...)**, i32*, i32, i32, %struct.f }
// CHECK: %class.IA = type { i32 (...)** }
// CHECK: %class.ICh = type { i32 (...)**, i32*, [4 x i8], %class.IA }
// CHECK: %struct.sd = type { i32*, i32, i8, [7 x i8], %struct.f, %struct.s.base, [4 x i8], %class.IA, %class.ICh.base }
// 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 }
// CHECK: 0 | struct AV
// CHECK-NEXT: 0 | (AV vftable pointer)
@ -457,7 +457,7 @@ int main() {
// CHECK: %struct.AV = type { i32 (...)** }
// CHECK: %struct.BV = type { %struct.AV }
// CHECK: %struct.CV = type { i32*, [4 x i8], %struct.BV }
// CHECK: %struct.CV = type { i32*, i32, %struct.BV }
// CHECK: %struct.CV.base = type { i32* }
// CHECK: 0 | struct DV
@ -483,7 +483,7 @@ int main() {
// CHECK-NEXT: sizeof=16, align=4
// CHECK-NEXT: nvsize=8, nvalign=4
// CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, [4 x i8], %struct.BV }
// CHECK: %struct.EV = type { %struct.DV, %struct.CV.base, i32, %struct.BV }
// CHECK: %struct.EV.base = type { %struct.DV, %struct.CV.base }
// Overriding a method means that all the vbases containing that