Currently Clang implements pragma pack
mostly in the same way of what Microsoft Windows compiler does: https://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
However, there are platforms where pragma pack
has different syntax/semantics. For example,
https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/compiler_ref/pragma_pack.html
Some differences worth noting:
#pragma pack(number)
with GCC/MSVC would not affect internal stack, meaning if we have
#pragma pack(4)
#pragma pack(pop)
pragma pack(pop)
won’t be able to pop anything, and pragma pack(4)
is still in effect; however, some flavours of the pragma is such that #pragma pack(4)
is the same as #pragma pack(push, 4)
would be with GCC/MSVC.
There seems to be existing code in clang/lib/Parse/ParsePragma.cpp
that touches upon this:
if (Tok.is(tok::numeric_constant)) {
Alignment = Tok;
PP.Lex(Tok);
// In MSVC/gcc, #pragma pack(4) sets the alignment without affecting
// the push/pop stack.
// In Apple gcc, #pragma pack(4) is equivalent to #pragma pack(push, 4)
Action =
PP.getLangOpts().ApplePragmaPack ? Sema::PSK_Push_Set : Sema::PSK_Set;
Basically, the behaviour is tweaked to be the “push” semantic for “Apple”. Is this direct querying for the specific “flavour” of pack
the preferable way of managing semantic differences for pragma pack
? Also, the enumeration type is called PragmaMsStackAction
. If the enumeration is used for more than Microsoft-specific pragmas, doesn’t it make sense to change it to a more generic name, say PragmaStackAction
?
#pragma align
is another pragma I want to mention here. Currently, #pragma align = power
/ #pragma align = natural
are the same, and they set the attribute MaxFieldAlignmentAttr
to be 0
, which later gets overridden by the code in lib/AST/RecordLayoutBuilder.cpp
to be the normal alignment value.
However, align power and natural are different on AIX. Natural alignment is the same alignment rule on other platform, but power alignment have some special alignment rule on AIX. So I think what makes sense here is to keep the existing behavior for existing platforms, and do something different for #pragma align = power
/ #pragma align = natural
for AIX platform.
This is the doc for align(power/natural)
on AIX: https://www.ibm.com/support/knowledgecenter/SSGH2K_13.1.2/com.ibm.xlc131.aix.doc/compiler_ref/opt_align.html
The implementation for those two pragmas I have in mind is very similar to that of pragma align = Mac68k
, which is to attach a new clang::Attr
attribute on RecordDecl
s that are affected by pragma align = power
/natural
(Notice that those clang::Attr
do not have source form and are for internal usage only), and we would query consume those clang::Attr
off the RecordDecl
in lib/AST/RecordLayoutBuilder.cpp
.
Lastly, I want to talk about the interaction model behind the align
and pack
pragmas as they could end up “overriding” each other’s setting.
The existing implementation for pragma align and pragma pack allows pragma pack(pop)
to pop pragma align
settings, and pragma align(reset)
to pop pragma pack
settings. Existing unit test case is here: https://github.com/llvm-mirror/clang/blob/master/test/Sema/pragma-pack-and-options-align.c
However, the stack effect between align
and pack
pragmas I intend to pursue is different and here are some examples:
#pragma align(natural)
#pragma pack(2)
// section 1
Remarks: code in section 1 would have their natural
alignment reduced by pack(2)
.
#pragma pack(2)
#pragma align(natural)
// section 1
Remarks: code in section 1 would have their natural
alignment; the pack(2)
does not apply.
Additional complication comes in with pragma align(reset)
and pragma pack(pop)
. Here’s some examples:
#pragma align(power)
#pragma align(natural)
#pragma pack(2)
#pragma align(reset)
Remarks: pragma align(power)
is in effect. The pragma pack(2)
is removed along with the pragma align(natural)
.
#pragma pack(2)
#pragma align(natural)
#pragma pack(pop)
Remarks: pragma pack(pop)
won’t be able to pop the stack, because pragma align(natural)
sets a baseline, and there is no pragma pack
applied to that baseline.
As you can see from the examples, the model behind pragma align
/pack
is that pragma align
sets a new baseline (sits on top of all preceding pack
pragmas), and pragma align(reset)
unwinds all pack
pragmas sitting on top of a pragma align
baseline.
There are two options I can try to pursue here:
- Implement the new stack effect model for all platforms.
Pros : new mental model behind the stack effect might make more sense for some users.
Cons: but it would break existing user code (if user are actually using thosepragma align
). Hopefullypragma align
is not used pervasively on existing platforms, otherwise, it is a deal breaker. - Implement the new stack effect only on specific platform(AIX), keep existing behavior for existing platforms.
Pros: no existing user code will get break.
Cons: it might be ugly to have different stack effect for different platforms.
I’m leaning towards on option 1 at this time because it’s cleaner solution if people think the new mental model is better, and are okay with the fact that some user code will get compiled differently if they use pragma align
and pragma pack
together already.
Please let me know if there are any concerns or questions about my current proposal and design. Your feedback is appreciated.
Regards,
Jason Liu