This is an archive of the discontinued LLVM Phabricator instance.

Complete Rewrite of CGRecordLayoutBuilder
ClosedPublic

Authored by whunt on Feb 13 2014, 4:37 PM.

Details

Summary

This patch completely replaces CGRecordLayoutBuilder. CGRecordLayoutBuilder was aging, complex, multi-pass, shows signs of existing before ASTRecordLayoutBuilder and was getting hackier as support for MS layout, including vbase placement, vtordisps, ms-bitfields and a variety of other features. By reimplementing it, a significant code reduction was achieved and a significant amount of duplication of functionality between CGRecordLayoutBuilder and ASTRecordLayoutBuilder was removed.

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.

I'm sorry the diff is hard to read due to the way diff works when replacing almost the entire contents of a file.

I had to update a few lit tests due to the fact that the new system compute more accurate llvm types than CGRecordLayoutBuilder. I'll comment on each change individually.

Diff Detail

Event Timeline

whunt added a comment.Feb 13 2014, 4:57 PM

an update will be coming almost immediately.

lib/AST/RecordLayoutBuilder.cpp
2139 ↗(On Diff #7101)

This change will be removed in an update to this patch.

test/CodeGen/2009-06-14-anonymous-union-init.c
1 ↗(On Diff #7101)

The changes to this file are unnecessary and will be removed in an updated patch.

test/CodeGen/PR4611-bitfield-layout.c
3 ↗(On Diff #7101)

i32 is more accurate for unsigned bitfield. There will be fewer bitcasts in IR when referencing these bitfields now.

test/CodeGen/bitfield-2.c
14 ↗(On Diff #7101)

no need to pack I8 array

54 ↗(On Diff #7101)

no need to pack I8 array

112 ↗(On Diff #7101)

vestigial, will be removed in an update

275 ↗(On Diff #7101)

i32 is a more accurate type than [4 x i8]. With the update to i32 the [3 x i8] padding need not be explicit.

test/CodeGen/packed-nest-unpacked.c
63 ↗(On Diff #7101)

no need for bitcast anymore

test/CodeGen/packed-union.c
1 ↗(On Diff #7101)

This change isn't directly related to this patch, but at some point I failed the lit test and in the process of looking at it, I updated it from a grep test to a FileCheck test.

test/CodeGen/pragma-pack-1.c
56 ↗(On Diff #7101)

no need to pack a pointer

61 ↗(On Diff #7101)

no need to pack this struct, explicit padding is no longer needed

test/CodeGen/pragma-pack-2.c
7 ↗(On Diff #7101)

no need to pack this given that s0 is packed

24 ↗(On Diff #7101)

Unnecessary change, I"ll remove it in an update.

test/CodeGen/struct-x86-darwin.c
1 ↗(On Diff #7101)

Update grep test to FileCheck test. Some [2 x i8] -> i16 changes

test/CodeGen/volatile.c
1 ↗(On Diff #7101)

Itanium and MS treat bitfields differently, this test happened to exercise that.

test/CodeGen/x86_32-arguments-darwin.c
115 ↗(On Diff #7101)

Unnecessary, to be removed in an update.

test/CodeGenCXX/bitfield-layout.cpp
15 ↗(On Diff #7101)

more accurate type.

test/CodeGenCXX/class-layout.cpp
42 ↗(On Diff #7101)

We can use the base type here, it's the correct size/alignment.

test/CodeGenCXX/copy-constructor-synthesis.cpp
145 ↗(On Diff #7101)

fewer bitcasts are required in this test

157 ↗(On Diff #7101)

ditto

test/CodeGenCXX/pragma-pack-3.cpp
14 ↗(On Diff #7101)

no need to pack, also checking the derive base type

test/CodeGenCXX/vtable-layout-abi-examples.cpp
1 ↗(On Diff #7101)

Not strictly necessary but makes the test more robust to debug printing and the stderr channel is not used by the lit test.

test/Sema/ms_class_layout.cpp
1 ↗(On Diff #7101)

ditto.

357 ↗(On Diff #7101)

explicit padding isn't needed because the alignment of %class.D implies it.

431 ↗(On Diff #7101)

more accurate type

whunt added inline comments.Feb 13 2014, 4:57 PM
test/Sema/ms_class_layout.cpp
433 ↗(On Diff #7101)

more accurate type.

434 ↗(On Diff #7101)

vtordisps are explicit now, padding isn't required for this layout

460 ↗(On Diff #7101)

another explicit vtordisp

486 ↗(On Diff #7101)

ditto.

majnemer added inline comments.Feb 13 2014, 4:59 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
29 ↗(On Diff #7101)

Please have this line sequenced between Debug.h and raw_ostream.h

34 ↗(On Diff #7101)

This variable seems superfluous.

37 ↗(On Diff #7101)

strait forward

should be

straightforward

40 ↗(On Diff #7101)

Editorial, should this be LLVM type or llvm::Type ?

42 ↗(On Diff #7101)

LLVM *does* support bitfields, just not in struct types.

71 ↗(On Diff #7101)

What's with the question marks here?

78 ↗(On Diff #7101)

This is not in keeping with the LLVM coding standard.

A style-conforming transform could be:
enum InfoKind { VFPtr, VBPtr, Field, Base, VBase, Scissor } Type;

whunt updated this revision to Unknown Object (????).Feb 13 2014, 5:02 PM

Removed all of the unnecessary changes I identified while commenting the first diff.

majnemer added inline comments.Feb 13 2014, 5:04 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
107 ↗(On Diff #7101)

static_cast ?

120 ↗(On Diff #7101)

What about ms-bitfields in Itanium mode?

122 ↗(On Diff #7101)

static_cast ?

whunt added inline comments.Feb 13 2014, 5:12 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
34 ↗(On Diff #7101)

yes... it was there to make my editor not auto-indent while I writing the large block comment.

42 ↗(On Diff #7101)

LLVM supports iN types, but they do not behave like C/C++ bitfields.

71 ↗(On Diff #7101)

personal confusion, I've made it more explicit

78 ↗(On Diff #7101)

Done.

whunt updated this revision to Unknown Object (????).Feb 13 2014, 5:13 PM

Addressing majnemer's first round of comments.

whunt added inline comments.Feb 13 2014, 5:17 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
107 ↗(On Diff #7101)

see future comment.

120 ↗(On Diff #7101)

useMSABI checks both ms-struct and cxxabi

122 ↗(On Diff #7101)

ugh. if I don't use (unsigned) it doesn't throw an error. There's some annoying amount of martialing between 32 and 64 bit ints given what each interface requires. I can use static cast everywhere to be most correct, it's just big and ugly...

majnemer added inline comments.Feb 13 2014, 5:35 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
229 ↗(On Diff #7102)

Can't this be llvm::NextPowerOf2 ?

275 ↗(On Diff #7102)

Out of curiosity, why is this a std::stable_sort ? Union fields?

309 ↗(On Diff #7102)

Parens around the &&

567 ↗(On Diff #7102)

Why use a std::stable_sort instead of a std::sort?

578 ↗(On Diff #7102)

This looks a bit strange, why not just do FieldTypes.size() - 1 ?

majnemer added inline comments.Feb 14 2014, 4:04 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
442 ↗(On Diff #7103)

Any reason we say that the v-table is filled with functions which return i32 and are variadic?

rnk added inline comments.Feb 18 2014, 2:45 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
35 ↗(On Diff #7103)

Is "to a form that can be converted" necessary? Can it just be "... responsible for lowering an ASTRecordLayout to an llvm::StructType"? I know it's responsible for more than that in the case of bitfields, but it seems like a useful simplification.

36 ↗(On Diff #7103)

I would avoid the first person in comments.

38 ↗(On Diff #7103)

I wouldn't say "does not support" because it implies that LLVM might add support later. "does not have" would work.

41 ↗(On Diff #7103)

ditto. We're happy with the current canonical forms of masking, etc.

46 ↗(On Diff #7103)

s/i24 -/i24./

46 ↗(On Diff #7103)

s/e.g./For example,/

51 ↗(On Diff #7103)

I believe Clang is the one that assumes that every field has an underlying LLVM storage type, not LLVM.

54 ↗(On Diff #7103)

Is this always [0 x i8]? Can we just say that here? Otherwise I'm left wondering how to represent a zero-sized storage type in LLVM IR.

55 ↗(On Diff #7103)

This is Clang's behavior not LLVM's, and in the wondrous future it would probably be good to change Clang to use base types pervasively instead of complete types.

66 ↗(On Diff #7103)

Is it useful to say, "Itanium allows nearly empty virtual bases to be primary bases"?

70 ↗(On Diff #7103)

I'd drop the comment about understanding why. I have an explanation.

The "is zero initializable" bit really answers the question, can I put a global of this class type in .bss if I promise to call the constructor on it later? The constructor will set the vftpr and vbptr, but it won't set uninitialized member pointers to -1, which is the representation of null for some member pointers.

211–214 ↗(On Diff #7103)

Rather than building a DenseMap from FieldDecl to bit offset, can you use the existing lookup table based on index wrapped in a helper? Something like:

uint64_t getFieldBitOffset(const FieldDecl *FD) {
  return Layout.getFieldOffset(FD->getFieldIndex());
}

That saves the hash lookup and template instantiation.

242 ↗(On Diff #7103)

This is nitty and feel free to ignore it, but I feel like the steps would be easier to read if the first sentences were converted from passive voice into active commands like:

  1. Place all members (fields and bases) into a list and sort it.
  2. Add a 1-byte capstone member at the offset of Size.
  3. Clip the storage of any trailing bitfields. The capstone is used for ...
244 ↗(On Diff #7103)

Should be "are stored into" or something.

374 ↗(On Diff #7103)

s/memebers/members/

442 ↗(On Diff #7103)

Looks like the old code did that. Changing that along with all the lit tests should be done separately.

460 ↗(On Diff #7103)

s/insize/inside/

479 ↗(On Diff #7103)

Before doing a big search of the inheritance graph, can we do:

if (Context->isNearlyEmpty(Query))
  return false;

... or is that too much Itanium knowledge here?

491 ↗(On Diff #7103)

I'd write Member->Field as MemberInfo::Field, since Field is an enumerator, not a data member.

495 ↗(On Diff #7103)

ditto for ->Base and ->VBase.

506–510 ↗(On Diff #7103)

I see, you need to make sure that a trailing i24 at the end of the nvbase portion of a complete object gets lowered to a [3 x i8].

512 ↗(On Diff #7103)

s/Member->Scissor/MemberInfo::Scissor/

515 ↗(On Diff #7103)

s/Prior->Field/MemberInfo::Field/

545 ↗(On Diff #7103)

The >> here is a C++11-ism, and we're not quite there yet...

563 ↗(On Diff #7103)

ditto on the >>

578 ↗(On Diff #7103)

Why not write FieldTypes.size() - 1 here and below?

1049–1063 ↗(On Diff #7103)

Try to avoid unrelated whitespace changes.

1071 ↗(On Diff #7103)

ditto

whunt added inline comments.Feb 18 2014, 4:02 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
229 ↗(On Diff #7102)

the function here is as follows:
1->min(1, alignment)
2->min(2, alignment)
3->min(1, alignment)
4->min(4, alignment)
5->min(1, alignment)
6->min(2, alignment)
Essentially the function is min(IsolateLowestSetBit(), alignment)

275 ↗(On Diff #7102)

Bitfields and the sentinel. Because the offsets sorted on are CharUnits, multiple bitfields can have the same offset. In fact, all bitfields associated with a given storage member are all given the address of that storage member. The storage member must come first because the bitfields reference it during processing.

309 ↗(On Diff #7102)

Thanks. I hate this warning though... I understand how precedence works =P

567 ↗(On Diff #7102)

see previous message about stable_sort

578 ↗(On Diff #7102)

No idea why I started with the other way, I went ahead and changed it.

whunt added inline comments.Feb 18 2014, 4:46 PM
lib/CodeGen/CGRecordLayoutBuilder.cpp
35 ↗(On Diff #7103)

Sure, technically CodeGenTypes::ComputeRecordLayout constructs the llvm::Type, not CGRecordLowering. Although I don't think this is a terrible interesting distinction.

36 ↗(On Diff #7103)

Done.

38 ↗(On Diff #7103)

I agree, done.

41 ↗(On Diff #7103)

I agree, done.

46 ↗(On Diff #7103)

okay.

46 ↗(On Diff #7103)

done.

51 ↗(On Diff #7103)

Fixed.

54 ↗(On Diff #7103)

No, they're zero size empty structs. I'll make the comment more clear.

55 ↗(On Diff #7103)

Changed. Yep, would be good.

66 ↗(On Diff #7103)

I think so, adjusted.

70 ↗(On Diff #7103)

Yep, dropped, this was a comment aimed at the reviewers actually =)

211–214 ↗(On Diff #7103)

Awesome. I was unaware the FDs knew their index. This makes life easier.

242 ↗(On Diff #7103)

Agreed, active voice is more direct and actually fewer words/characters. These comments were actually annoyingly in mixed voice if you go farther down. Fixed.

374 ↗(On Diff #7103)

done.

442 ↗(On Diff #7103)

No clue, that's the way it's been done. I assume because the v-table functions all take different numbers of arguments.

460 ↗(On Diff #7103)

done.

479 ↗(On Diff #7103)

I think it's quite reasonable to do this. I added a check before the call. Checking inside the call would cause it to be checked over and over again during recursive decent.

491 ↗(On Diff #7103)

Sure, I did it the current way because C++ lets me and it's fewer characters, saving a newline at one point but I agree it's a little weird that it's possible. Fixed everywhere.

506–510 ↗(On Diff #7103)

yes. struct { unsigned a : 24; char b; }; also causes this w/o nvbase-related tail padding.

545 ↗(On Diff #7103)

And this is why we can't have nice things...

578 ↗(On Diff #7103)

I'm not entirely sure why I did it that way. I've changed it.

whunt updated this revision to Unknown Object (????).Feb 18 2014, 4:48 PM

Addressing the latest rounds of feedback from majnemer and rnk.

rnk added a comment.Feb 18 2014, 5:48 PM

Works for me, but we should check with John.

lib/CodeGen/CGRecordLayoutBuilder.cpp
34 ↗(On Diff #7193)

I'd probably drop "The" at the start of the sentence here.

36 ↗(On Diff #7193)

I'd drop the trailing "here"

62 ↗(On Diff #7193)

Should SCISSOR be all caps? The enum is StudlyCaps now.

200 ↗(On Diff #7193)

"end anonymous namespace" is probably more prevalent in Clang

ygao added a comment.Feb 18 2014, 6:03 PM

Not exactly following how determinePacked() works. Some comments in the function body should help?

whunt added inline comments.Feb 19 2014, 11:19 AM
lib/CodeGen/CGRecordLayoutBuilder.cpp
527 ↗(On Diff #7193)

I'll go ahead an add a comment to the code.

If any member falls at an offset that it not a multiple of its alignment, then the entire record must be packed.

531 ↗(On Diff #7193)

If the size of the record (the capstone's offset) is not a multiple of the record's alignment, it must be packed.

ygao added inline comments.Feb 19 2014, 11:27 AM
lib/CodeGen/CGRecordLayoutBuilder.cpp
527 ↗(On Diff #7193)

Sounds good. Thanks!

ygao added a comment.Feb 19 2014, 5:41 PM

A coding style question:

It seems that CGRecordLowering is exposing a lot of its member fields and functions. I wonder whether it makes sense to make some of these member fields private. For example, it seems

std::vector<MemberInfo> Members

does not need to be referenced by outside classes, and could be made private (and hence the definition of MemberInfo). I did not check all the "Input Memoization fields", but I suspect some of them do not need to be exposed either. And some of the member functions as well, such as,

void lowerUnion();

and some other functions used by lower(), probably can be hidden from outside classes as well.

I think this is minor point since CGRecordLowering is only defined and used in this file, and I am not entirely sure about LLVM's coding style on access control. What do the other reviewers think?

ygao added a comment.Feb 20 2014, 2:05 PM

The rest of the patch looks good by me. You might want to check with John if he has any comments.

  • Gao
whunt closed this revision.Feb 21 2014, 3:56 PM

Closed by commit rL201907 (authored by @whunt).

Via Old World