[RFC] Pragma pack/align

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 RecordDecls 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:

  1. 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 those pragma align). Hopefully pragma align is not used pervasively on existing platforms, otherwise, it is a deal breaker.
  2. 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

As far as I know, the current implementation of pragma pack in clang is compatible with both MSVC and gcc. “-fapple-pragma-pack” is a compatibility flag for transitioning old code which expected Apple gcc semantics (which was different from the regular gcc rules). If you need -faix-pragma-pack, that’s okay; there isn’t really any better approach. (You can turn it on by default for AIX targets in the clang driver, if you think that’s appropriate?) We can’t change the stack rules for pragma align on Apple targets; it’s very likely to break existing code. -Eli