-
Notifications
You must be signed in to change notification settings - Fork 14
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
16 bit multiplication always produces zero result #129
Comments
I've put the debug output from compiling this into a gist: https://gist.github.com/carlos4242/e7bd5c8bba0d7fb94f02ce02f9ed5189. This looks like the bit at fault...
The registers being used look wrong. I'm trying to debug through how it works. In
As I understand it, this tries to see if the multiplication of two i16 numbers is "legal", i.e. if there's a native instruction, which there isn't. (AVR has i8i8 -> i16 but not an i16i16 instruction) Further down I can see...
Which looks like it's getting close to the issue. It's packing the 16 bit registers plus zeros into 4 arguments. The question is how it gets from here to actual register choice and where it goes wrong? (I'll continue investigating when I have time.) |
OK, here's a bit more debug.
At end of AVRTargetLowering--LowerCall.pdf |
OK, I think I've found the root cause. When legalizing the DAG, the code decides based on the types involved, it decides it cannot lower to MC so it expands the call to The code in question is in It creates an array of four i16 parameters to pass to Because AVR is a little endian platform, it creates the arguments as: (i16)multiplicand1, (i16)0, (i16)multiplicand2, (i16) 0 When these are lowered by (i16)multiplicand1 =>R24R25 (i16)0 => R22R23 (i16)multiplicand2 => R20R21 (i16) 0 => R18R19 Which is the wrong order. So between the assumptions made in the ordering of arguments in Fixes I can think of:
I think at this point I can hack something for myself but a better fix will require community feedback. |
This is 'fixed' by avr-rust/llvm#9. But it might arguably not be the best way to fix it? Open to suggestions/advice... |
LABEL AS: has local patch |
Raised https://reviews.llvm.org/D62003 for upstreaming the patch. |
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd, efriedma Reviewed By: efriedma Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361222 91177308-0d34-0410-b5e6-96231b3b80d8
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd, efriedma Reviewed By: efriedma Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003 llvm-svn: 361222
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd, efriedma Reviewed By: efriedma Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@361222 91177308-0d34-0410-b5e6-96231b3b80d8
Fix upstreamed in r361222 Thanks for the patch Carl! |
Cool. :)
Np. Glad to help.
… On 21 May 2019, at 09:15, Dylan McKay ***@***.***> wrote:
Fix upstreamed in r361222
Thanks for the patch Carl!
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or mute the thread.
|
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd, efriedma Reviewed By: efriedma Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003 llvm-svn: 361222
…nvention endianess Summary: The endianess used in the calling convention does not always match the endianess of the target on all architectures, namely AVR. When an argument is too large to be legalised by the architecture and is split for the ABI, a new hook TargetLoweringInfo::shouldSplitFunctionArgumentsAsLittleEndian is queried to find the endianess that function arguments must be laid out in. This approach was recommended by Eli Friedman. Originally reported in avr-rust/rust-legacy-fork#129. Patch by Carl Peto. Reviewers: bogner, t.p.northover, RKSimon, niravd, efriedma Reviewed By: efriedma Subscribers: JDevlieghere, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D62003 llvm-svn: 361222
Another one from the swift team. I'm surprised no one has found this yet.
@llvm.umul.with.overflow.i16(i16 , i16 ) seems to be lowering to invalid assembly, specifically it ends up moving the two 16 bit values into the top two bytes of 32 bit numbers then using __mulsi3 to multiply them together and put the result into a 32 bit number, where it takes the top two bytes. This will always produce zero.
In my opinion if it's using __mulsi3, it should be putting two 16 bit numbers into the bottom two bytes of each input and taking the bottom two bytes of the output, then any non zero value in the top two bytes after multiplication should be interpreted as an overflow and the flag set accordingly.
Here's the llvm ir in a test case as a patch to llvm...
(Note that I haven't yet put in the FileCheck directives because I haven't decided/worked out what the compiler should be doing here yet!)
FYI the original source, with debug statements in was something like:
This produces the following assembly...
From what I know,
__mulsi3
takes the 32 bit value in r18-r21, multiplies it by the 32 bit value in r22-r25 and stores the result in the 32 bit value r22-r25. (I'm not sure how it detects overflow.)It should be multiplying the input value, e.g. 90 by 11 then printing out the result. Instead it always prints 0.
As I read this assembly, it's moving both input values into the top two bytes of 32 bit numbers, which looks broken. Either it should move them to the bottom two bytes or use a different function.
I'd love to investigate this but I'll need to get some pointers from people where this is all happening. I couldn't even find mulsi3 by grepping through llvm source code. No idea how this is made!
The text was updated successfully, but these errors were encountered: