Rafael Espíndola
2012-Oct-19 15:17 UTC
[LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
Functions with __attribute__((fastcall)) pop their arguments and take up to two arguments in ecx and edx. Currently we represent them by just setting the x86_fastcallcc calling convention. The problem is that the ABI has some strange conventions on when a register is used or not. For example: void __attribute__((fastcall)) foo1(int y); will take 'y' in ecx, but struct S1 { int x; }; void __attribute__((fastcall)) foo2(struct S1 y); will use the stack. Even more surprising is that void __attribute__((fastcall)) foo8(struct S1 a, int b); will take 'a' in the stack but 'b' in *edx*. That is, the first argument consumed ecx but didn't use it. The implement this the IL needs to be able to represent that * an argument will go on registers * a register was consumed but unused A way to do this is to make clang produce byval for anything that goes on the stack, but that produces worse code as the caller now has to use an alloca instead of a simple value. Another option (which I implemented in a patch just sent to llvm-commits) is use the inreg attribute which we already use for the regparm C attribute. The above requirements are handled by putting inreg in the arguments that should go in register and creating a inreg padding argument when a register should be consumed but not used. The above examples would be irgened to: declare x86_fastcallcc void @foo1(i32 inreg declare x86_fastcallcc void @foo2(i32 inreg /*dummy*/ , i32) declare x86_fastcallcc void @foo8(i32 inreg /*dummy*/, i32, i32 inreg) As Eli pointed out on llvm-commits, this would change the meaning of existing x86_fastcallcc IL files, but given that they are only produced for fastcall C functions and those are fairly broken without this fix, I assume that is OK. Cheers, Rafael
Chandler Carruth
2012-Oct-19 15:40 UTC
[LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
Personally, I'd love to see a setup where instead of LLVM implementing each calling convention and ABI hack, we provide a means of actually describing this. Specifically, I'd love to see a design for how to specify in the IR which register(s) (if any register(s)) a particular value should be placed into. Don't get me wrong, I don't have any good ideas about how to do this, I'm just hoping someone does. End result might allow something like: declare void @foo(double inreg <eax,edx> %x) On Fri, Oct 19, 2012 at 8:17 AM, Rafael Espíndola < rafael.espindola at gmail.com> wrote:> Functions with __attribute__((fastcall)) pop their arguments and take > up to two arguments in ecx and edx. Currently we represent them by > just setting the x86_fastcallcc calling convention. The problem is > that the ABI has some strange conventions on when a register is used > or not. For example: > > void __attribute__((fastcall)) foo1(int y); > > will take 'y' in ecx, but > > struct S1 { > int x; > }; > void __attribute__((fastcall)) foo2(struct S1 y); > > will use the stack. Even more surprising is that > > void __attribute__((fastcall)) foo8(struct S1 a, int b); > > will take 'a' in the stack but 'b' in *edx*. That is, the first > argument consumed ecx but didn't use it. The implement this the IL > needs to be able to represent that > * an argument will go on registers > * a register was consumed but unused > > A way to do this is to make clang produce byval for anything that goes > on the stack, but that produces worse code as the caller now has to > use an alloca instead of a simple value. > > Another option (which I implemented in a patch just sent to > llvm-commits) is use the inreg attribute which we already use for the > regparm C attribute. The above requirements are handled by putting > inreg in the arguments that should go in register and creating a inreg > padding argument when a register should be consumed but not used. > > The above examples would be irgened to: > > declare x86_fastcallcc void @foo1(i32 inreg > > declare x86_fastcallcc void @foo2(i32 inreg /*dummy*/ , i32) > > declare x86_fastcallcc void @foo8(i32 inreg /*dummy*/, i32, i32 inreg) > > As Eli pointed out on llvm-commits, this would change the meaning of > existing x86_fastcallcc IL files, but given that they are only > produced for fastcall C functions and those are fairly broken without > this fix, I assume that is OK. > > Cheers, > Rafael > _______________________________________________ > LLVM Developers mailing list > LLVMdev at cs.uiuc.edu http://llvm.cs.uiuc.edu > http://lists.cs.uiuc.edu/mailman/listinfo/llvmdev >-------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20121019/c587325e/attachment.html>
Renato Golin
2012-Oct-19 15:58 UTC
[LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
On 19 October 2012 16:40, Chandler Carruth <chandlerc at google.com> wrote:> Don't get me wrong, I don't have any good ideas about how to do this, I'm > just hoping someone does. End result might allow something like: > > declare void @foo(double inreg <eax,edx> %x)Hi Chandler, We were discussing about this on the Cambridge LLVM Social a while ago, and we felt that there were far too much target dependent stuff in the procedure call standards as it is. Our approach would be to have a PCS layer, either in the front-end or as a pass, that would know about both language and target to be able to construct calls as the target is expecting (ABI-wise). David Chisnall proposed a PCSBuilder (similar to IRBuilder, for building function calls), where you just pass the basic info (return type, arguments, flags, name) and it builds the function for you, mangling names, changing parameters and assigning things to registers when the ABI is less than helpful, possibly having an inreg syntax like you describe. My idea was to make it a pass, so you could delay the PCS mess up to a later stage, when possibly you'd already have more information about the target, but that's not necessarily true and might open the can of worms that is having a multi-layered IR. For simplicity, we might consider David's approach first, and move the code later, if the idea of a multi-layered IR gets on. Would that make sense in Clang? It should be a matter of code movement more than new code, and would provide a common place for more front-ends to use. Duncan, Would that make sense in dragonegg? -- cheers, --renato http://systemcall.org/
Krzysztof Parzyszek
2012-Oct-19 16:07 UTC
[LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
On 10/19/2012 10:40 AM, Chandler Carruth wrote:> > Don't get me wrong, I don't have any good ideas about how to do this, > I'm just hoping someone does. End result might allow something like: > > declare void @foo(double inreg <eax,edx> %x) >Could we have some sort of metadata input for the front-end, where "fastcall" would be explicitly defined, together with the required targets that implement it? This way users could provide their own calling convention definitions, and use them in a similar fashion to fastcall, i.e. __attribute__((my_convention)). The bitcode could only specify which calling convention is being used, and each target lowering would need to translate it properly. -Krzysztof -- Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, hosted by The Linux Foundation
Rafael Espíndola
2012-Oct-19 16:27 UTC
[LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
> Don't get me wrong, I don't have any good ideas about how to do this, I'm > just hoping someone does. End result might allow something like: > > declare void @foo(double inreg <eax,edx> %x)Not sure I would go all the way to specifying registers in the IL (although I liked it at some point). What I like most right now is something along the lines of http://llvm.org/pr12193. That makes it explicit if something is on the stack or in registers and that information is correct for both the caller and callee. What is left for codegen is counting the register arguments and computing stack offsets. Implementing that requires way more time than I have right now, but I think this proposal is a small step in the right direction as it makes clang the one responsible for marking an argument as memory or register. Cheers, Rafael
Maybe Matching Threads
- [LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
- [LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
- [LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
- [LLVMdev] How to represent __attribute__((fastcall)) functions in the IL
- [LLVMdev] How to represent __attribute__((fastcall)) functions in the IL