This patch implements the Clang part for no_caller_saved_registers attribute as appear in interrupt and exception handler proposal
Details
Diff Detail
Event Timeline
include/clang/Basic/Attr.td | ||
---|---|---|
1674 | Any particular reason this isn't (also) a C++-style attribute under the clang namespace? | |
include/clang/Basic/AttrDocs.td | ||
2205 | How does this interact with calling convention attributes? For instance, if I have a function that is explicitly marked cdecl and has this attribute, what is the behavior for EAX, ECX, and EDX? Also, why is this an attribute rather than a calling convention? I'm wondering how this works through function pointers, for instance (whether it is intended to work or not). | |
test/SemaCXX/attr-x86-no_caller_saved_registers.cpp | ||
16 | Should also have a sema test that this attribute accepts no arguments. |
include/clang/Basic/Attr.td | ||
---|---|---|
1674 | I am not sure about that, I was just following the way the "interrupt" attribute was defined. | |
include/clang/Basic/AttrDocs.td | ||
2205 | Please, correct me if I am mistaken, but calling convention determine not only what the callee and the caller function saved registers are, but also how we move parameters to the called function, right? The idea behind no_caller_saved_registers attribute, is that it can be combined with any other calling convention, and it only override the callee/caller saved register list, but not the way parameters are passed to the called function. So, using a calling convention for this attribute will not be right. H.J., can you confirm this? |
The example Aaron sent in email is a good one:
void func(int, int, int, int) __attribute__((no_caller_saved_registers, cdecl)); int main() { void (*fp)(int, int, int, int) __attribute__((cdecl)) = func; func(1, 2, 3, 4); fp(1, 2, 3, 4); // Not the same as the above call to func()? }
Clang should at least be giving a warning for this just like it does if you try to mix cdecl and stdcall on IA-32 or if you mix regparm(2) and regparm(3).
The current patch silently accepts the mismatch.
Made "no_caller_saved_registers" part of function prototype.
This will allow Clang to yell a warning when there is a mismatch between function pointer and assigned function value.
Thanks to Erich for implementing this addition change.
include/clang/Basic/Attr.td | ||
---|---|---|
1674 | Yes, though interrupt should be handled in a separate patch since it's a logically separate change. | |
include/clang/Basic/AttrDocs.td | ||
2205 |
Correct.
Okay, that makes sense to me, but we should document how this interacts with calling convention attributes more clearly. Specifically, we should call out that this does not affect the calling convention and give an example of what gets generated for a function that combines a caller-saved calling convention with this attribute. | |
include/clang/CodeGen/CGFunctionInfo.h | ||
479 | This is unfortunate as it will bump the bit-field length to 33 bits, which seems rather wasteful. Are there any bits we can steal to bring this back down to a 32-bit bit-field? |
Response on CGFucntionInfo.
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | I implemented this additional patch, but don't really know a TON about this area, so I have a few ideas but would like to get direction on it if possible. I had the following ideas of where to get a few more bits: CallingConvention/EffectiveCallingConvention/ASTCallingConvention: This structure stores a pre-converted calling convention to the llvm::CallingConv enum (llvm/include/llvm/IR/CallingConv.h). I'll note that the legal values for this go up to 1023 (so 8 bits isn't enough anyway!), though only up to 91 are currently used. HOWEVER, the clang CallingConv (include/clang/Basic/Specifiers.h :233) only has 16 items in it. If we were instead to store THAT and convert upon access (a simple switch statement, already used constructing this value, see ClangCallConvToLLVMCallConv), we could get away with 6 or 7 bits each, saving this 3-6 bits total, yet have way more than enough room for expansion. HasRegParm: This field might be possible to eliminate. According to the GCC RegParm docs (I don't see a clang one?) here (https://gcc.gnu.org/onlinedocs/gcc/x86-Function-Attributes.html), ", the regparm attribute causes the compiler to pass arguments number one to number if they are of integral type in registers EAX, EDX, and ECX instead of on the stack". It seems that 0 for "RegParm" should be illegal, so I wonder if we can treat "RegParm==0" as "HasRegParm==false" and eliminate storing that. In my opinion, the 1st one gives us way more room for the future and corrects a possible future bug. The 2nd is likely a lower touch, though it could possibly change behavior (see discussion here https://www.coreboot.org/pipermail/coreboot/2008-October/040406.html) as regparm(0) is seemingly accepted by both compilers. I DO note that this comment notes that 'regparm 0' is the default behavior, so I'm not sure what change that would do. Either way, I suspect this change should be a separate commit (though I would figure making it a pre-req for this patch would be the right way to go). If you give some guidance as to which you think would be better, I can put a patch together. -Erich |
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | I think that unsigned ASTCallingConvention : 8; can be safely reduced. This tracks a clang::CallingConv value, the maximum of which is 15. So I think the way to do this is to reduce ASTCallingConvention from 8 to 7 bits and then pack yours in as well. |
Response on CGFucntionInfo.
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | Ah! I missed that this was the case. That said, it could likely be reduced to 6 if we really wished (currently 16 items, 6 gives us room for 32). Perhaps something to keep in our pocket for the next time someone needs a bit or two here. I'll update the diff for Amjad if possible. |
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | I'm on the fence about 6 vs 7 and see no harm in reducing it to either value, but have a *very* slight preference for 7 so that the bit-field grouping continues to add up to 32-bits. However, it's your call. |
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | I'd go with 6 and have another bitfield, unsigned UnusedBits : 1; We use this paradigm elsewhere. |
include/clang/CodeGen/CGFunctionInfo.h | ||
---|---|---|
479 | That seems like a solid solution. I'll add it to another diff and give it to Amjad to update this patch. Not sure if he has the ability to (or if it is too late), but I don't have permissions to alter this commit for him. |
For what it is worth, this certainly seems to be misnamed. By nature, if it doesn't preserve at least the stack pointer, there is no way to recover on return, right?
I am not sure I understand what you mean!
When you said "if it does not preserve the stack pointer", did you mean the "caller"?
Maybe it need more clarification on that, but stack pointer should be saved by the caller (via the call instruction), but even in this case the callee must preserve the stack pointer, right? otherwise the return will not work. So, from callee point of view it still cannot assume that any register is a scratch register and it need to preserve it before modifying.
include/clang/Basic/Attr.td | ||
---|---|---|
1674 | How about using GCC Spelling instead of GNU and C++?
// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also // sets KnownToGCC to 1. This spelling should be used for any GCC-compatible // attributes. class GCC<string name> : Spelling<name, "GCC"> { let KnownToGCC = 1; } |
include/clang/Basic/Attr.td | ||
---|---|---|
1674 | The GCC spelling should only be used if the attribute is also supported by GCC, which this one is not. So the spelling should be GNU<"no_caller_saved_registers">, and CXX11<"clang", "no_caller_saved_registers">. |
I see reference to it in this bug against 6.0: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=68661
include/clang/AST/Type.h | ||
---|---|---|
2934 | s/noCallerSavedRegs/NoCallerSavedRegs/g | |
2987 | s/noCallerSavedRegs/NoCallerSavedRegs/g | |
2990–2991 | Remove else, just return | |
lib/Sema/SemaDecl.cpp | ||
2885 | Add a comment with the name of parameter for true argument | |
lib/Sema/SemaDeclAttr.cpp | ||
1693 | attr does follow rules of LLVM Coding standard. Must be Attr | |
1710 | s/attr/Attr/g | |
1710 | s/CheckNoCallerSavedRegsAttr/checkNoCallerSavedRegsAttr/g |
There appears to be two reviews out for this same functionality. You should probably close one of the reviews (but still address the comments from it).
Just out of interested: I can see how __attribute__ ((interrupt)) is useful, but in what situations would you use no_caller_saved_registers?
Actually please answer this question by documenting the attribute in docs/LangRef.rst in the llvm part of the changes.
s/noCallerSavedRegs/NoCallerSavedRegs/g