-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[WIP] ABI Lowering Library #140112
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
[WIP] ABI Lowering Library #140112
Conversation
✅ With the latest revision this PR passed the C/C++ code formatter. |
43855e6
to
114cab7
Compare
4410289
to
2832642
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thing still missing here is handling for C++ structs with base classes.
329556a
to
0f045da
Compare
ABIFunctionInfoArgInfo(Type *T, ABIArgInfo A) : ABIType(T), ArgInfo(A) {} | ||
}; | ||
|
||
class ABIFunctionInfo final |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having both FunctionABIInfo and ABIFunctionInfo is pretty confusing... do these need to be separate?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
um, I've renamed it for the time being - if I feel it doesn't serve a purpose in a few days I'll put it somewhere else
268c470
to
690068f
Compare
llvm/lib/ABI/ABITypeMapper.cpp
Outdated
StructType * | ||
ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields, | ||
uint32_t NumFields, TypeSize Size, | ||
Align Alignment, bool IsUnion) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... this is tricky. I'm not entirely sure what to do here. For the purpose of mapping ABIArgInfo, we should never encounter unions. For the struct case, things are tricky. Mostly, I believe we just want LLVM structs as a means of holding multiple values. E.g. a StructType for Direct arguments will normally get unpacked into individual arguments. In this case, we really don't want any kind of padding fillers in it. I think the only case that cares about that is CoerceAndExpand, which has two struct types, one just with the elements (which will be passed as separate arguments) and one that has the actual layout (with correct alignment etc).
This kind of makes me wonder whether it would make sense to start by storing llvm types in ABIArgInfo to match what clang currently does. abi::Type is conceptually nicer, but also not quite the right representation for everything (e.g. because it can't really represent the "struct without layout" case well).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should never encounter unions
Oh yeah! My bad...
Also I'm assuming both times you referred to ABIArgInfo
you were talking about abi::ABIArgInfo
and not codegen::ABIArgInfo
(should probably name that something slightly different sorry).
Given that assumption - I really don't think we need to bring llvm::Type
into the library as the struct without layout case can be added to the ABI typesystem itself (add another type of abi::StructPacking
or decide whether we need padding while converting). But agreed a lot of cleanup to be done here, I'll keep it in mind while writing the x86 target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also I'm assuming both times you referred to
ABIArgInfo
you were talking aboutabi::ABIArgInfo
and notcodegen::ABIArgInfo
(should probably name that something slightly different sorry).
Yeah, I mean abi::ABIArgInfo. Btw, I wonder whether we should call these abi::ArgInfo
etc, given that we already have abi in the namespace name...
Given that assumption - I really don't think we need to bring
llvm::Type
into the library as the struct without layout case can be added to the ABI typesystem itself (add another type ofabi::StructPacking
or decide whether we need padding while converting). But agreed a lot of cleanup to be done here, I'll keep it in mind while writing the x86 target.
Yeah, this is an option. I was mostly thinking about using llvm::Type as the path of least resistance to clang integration...
ABIFunctionInfoArgInfo(Type *T, ABIArgInfo A) : ABIType(T), ArgInfo(A) {} | ||
}; | ||
|
||
class ABIFunctionInfo final |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
um, I've renamed it for the time being - if I feel it doesn't serve a purpose in a few days I'll put it somewhere else
llvm/lib/ABI/ABITypeMapper.cpp
Outdated
StructType * | ||
ABITypeMapper::createStructFromFields(ArrayRef<abi::FieldInfo> Fields, | ||
uint32_t NumFields, TypeSize Size, | ||
Align Alignment, bool IsUnion) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we should never encounter unions
Oh yeah! My bad...
Also I'm assuming both times you referred to ABIArgInfo
you were talking about abi::ABIArgInfo
and not codegen::ABIArgInfo
(should probably name that something slightly different sorry).
Given that assumption - I really don't think we need to bring llvm::Type
into the library as the struct without layout case can be added to the ABI typesystem itself (add another type of abi::StructPacking
or decide whether we need padding while converting). But agreed a lot of cleanup to be done here, I'll keep it in mind while writing the x86 target.
e91424c
to
a48eefc
Compare
}; | ||
|
||
private: | ||
TypeBuilder &TB; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A note for the future: We probably need to do something to avoid leaking memory from these temporary types. We can probably checkpoint the type arena before computing ABIArgInfo and then restore the checkpoint once it's no longer needed.
llvm/lib/ABI/Targets/X86.cpp
Outdated
} | ||
|
||
if (!SeenNamedMember) { | ||
SeenNamedMember = isNamedMember(Field); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm... do we really need this named member logic? Looking at CGRecordLowering::lowerUnion()
, it seems like the named members are only relevant in the !isZeroInitializable
case, but you don't actually handle that and instead always override with the type of a named member.
What happens if you just drop this named member logic and only keep the alignment/size based logic below?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I didn't think ABI rules would care about ZeroInit, so it prefers named members and upgrades to a better type if it has better align/size. I think without it there was some ABI mismatch from clang.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I'm asking is that I'd like to minimize the amount of "weird stuff" that the frontend has to pass in when creating types.
I think as implemented this logic is pretty weird and doesn't make a lot of sense -- I think it will only make a difference in the specific case where you first have an unnamed field with a "better" type, then a named field (with which we override) and then all fields (named or unnamed) with "worse" types. But not for example if we first have a named field and then a better type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, none of the tests fail if I drop the SeenNamedMember
check, so I guess its fine :)
|
||
class ABITypeMapper { | ||
public: | ||
explicit ABITypeMapper(LLVMContext &Ctx, const DataLayout &DataLayout) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just as a general note, in C++ ctors it's okay to use the same name for the ctor arg and the member. So something like DL(DL)
works and is idiomatic.
if (!FieldType) | ||
continue; | ||
|
||
if (Field.IsBitField && Field.BitFieldWidth > 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this code, I doubt it does something correct for bit fields. Bit field layout is complicated.
For what kind of structs does ABITypeMapper actually get used? Does it only ever get used on "coerced structs" in practice, or also other ones?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, ABITypeMapper is used on everything.
Yeah was worried about Bitfield packing, but it didn't cause any blaring issues, so I assumed LLVM took care of it
b949795
to
565bf3b
Compare
90500f7
to
7097478
Compare
This PR details the implementation details of the proposed ABI lowering library.