Description
Since I'm playing with this, I figured I'd document some of what I've been seeing.
I've merged rust/rust@1447ce78fbd65a629f228ec8731a5cddc076a15c into the avr-support
branch. This entailed a few rounds of merge conflict resolution, as well as updating compiler-rt and the LLVM fork as well. The compiler seems to build, but I've hit some issues with compiling libcore:
./x86_64-apple-darwin/stage1/bin/rustc -C opt-level=2 -Z no-landing-pads --target avr-atmel-none -g ../src/libcore/lib.rs --out-dir libcore-avr/
Specifically, LLVM hit a few assertions when SelectionDAG::computeKnownBits
calls APInt::trunc
, APInt::sext
, and APInt::zext
because it's trying to convert a 16-bit number to a 16-bit number. These functions all expect to convert to a different size, and there are methods like zextOrSelf
that allow the same size. I hacked around that by returning *this
in all three methods (what could go wrong, right?).
The next attempt failed at an LLVM issue:
LLVM ERROR: Cannot select: t35: i8 = mulhs t2, t4
t2: i8,ch = CopyFromReg t0, Register:i8 %vreg27
t1: i8 = Register %vreg27
t4: i8,ch = CopyFromReg t0, Register:i8 %vreg25
t3: i8 = Register %vreg25
In function: _ZN3num14from_str_radix20h7837196669301488416E
Which I don't have the LLVM understanding to parse yet :-)
I'm going to try some other directions to see if I can get an executable.
Activity
dylanmckay commentedon Jan 17, 2016
After optimisation, LLVM converts the IR program into a Directed Acyclic Graph (DAG), where the nodes are the instructions, with subnodes being their operands, and so on.
The instruction sequence:
Becomes
Or how it is written in LLVM,
(add (sub i32 1, i32 5), (mul i32 7, i32 8))
.It then tries to match this DAG to the patterns specified in
AVRInstrInfo.td
. If a match is not found, the nodes are "expanded" (example: into two 16 bit add instructions) or "custom lowered" using a hook. It keeps doing this, until a match is found. We then have our mapping from IR instructions to AVR instructions.This error is simply saying that after instruction selection, LLVM was not able to find a match for the DAG
Where
Which can be read as
COPYFROMREG
is one of the node types specified in this file. There are node types for every IR instruction, and then more machine specific operations (like multiply two numbers and return a product with twice the precision, which is the behaviour of AVR'smul
instructions). It would be the expansion process which converted themul
instruction intoUMUL_LOHI
, and then expanding that intomulhs ...
because there were no matches.Basically this error is because
clang
generates an instruction sequence which we haven't yet defined a pattern (or a custom lowering hook) formulhs COPYFROMREG %vreg27, COPYFROMREG %vreg25
. This is simply a bug in the fact AVR-LLVM hasn't implemented this code path yet.dylanmckay commentedon Jan 17, 2016
We want to match
UMUL_LOHI
inside the pattern for the AVRmul
instruction here, and the only pattern defined for that instruction is commented out, which will be the source of our problem.The fix should be to change the
smullohi
node ID toumul_lohi
. I don't believe thesmullohi
node exists any longer, which is probably why it is commented out. It was probably renamed toumul_lohi
at some point.Of course that fixes the unsigned integer situation, the same pattern needs to be added to the signed multiplication instruction
muls
, but withsmul_lohi
instead.I'll commit it now. Note that I also have an unpushed branch of LLVM trunk. It sounds like you're also working on that - shall I push it?
shepmaster commentedon Jan 17, 2016
Thanks for the great explanation. While I have an OK understanding of general compiler workings, I don't have much concrete experience. Being pointed to specific files helps me see where / how some of the changes could be made. I don't want to have to just report issues; I'd like to at least try to help fix them too 😉 .
I do have a local merged branch, but I don't see any problem in continuing to merge in new stuff you push.
My hope is that I can help weed out some more cases like this as you are in the process of getting things merged into LLVM proper.
shepmaster commentedon Jan 17, 2016
I don't know what I'm doing yet, but I can see some patterns and deviations from those patterns...
Why is
MULRdRr
aFRdRr
, but all the other*MUL*
areFMUL2RdRr
orFFMULRdRr
? Likewise, why are onlyMULRdRr
andMULSRdRr
inside theusesCustomInserter
block?shepmaster commentedon Jan 17, 2016
And one more: why do
smullohi
andumullohi
get special entries inTargetSelectionDAG
, but signed x unsigned and the fractional ones don't?shepmaster commentedon Jan 17, 2016
Ok,
mul
,muls
andmulsu
all support differing sets of registers.mul
supports all of them, the others have hard-coded values in those places of the opcode so that explains the difference there.dylanmckay commentedon Jan 17, 2016
LLVM places pretty much all of its target descriptions inside TableGen files, a DSL which compiles down to C files with the
.inc
extension. Conveniently it supports inheritance.FRdRr
is the format of most instructions which take two 8 bit GPRs.MULRdRr
is one of these.For whatever reason, the Atmel engineers gave the other multiplication instructions a slightly different encoding (there are several cases of this sadly) so we need to work around it.
In case you want to have a look, here is the instruction set manual.
shepmaster commentedon Jan 17, 2016
Yeah, I was looking at the datasheet to start with, which has an abbreviated view of the instructions and doesn't make note of the restrictions on source registers. I've since found the same detailed reference you posted. :-)
dylanmckay commentedon Jan 17, 2016
From memory, they always place their product in the registers
r1:r0
.r1
is expected to be zero (the calling convention I think) so the custom inserter clears it after the product has been copied out.The other multiplication instructions allow you to specify the output register I believe.wrong, see belowshepmaster commentedon Jan 17, 2016
If I'm reading the docs correctly, I think all 6
*mul*
instructions place the results inr1:r0
.dylanmckay commentedon Jan 17, 2016
Ah, you're right. It's probably missing because we don't currently generate the other instructions yet (no patterns), it still should be though.
shepmaster commentedon Jan 17, 2016
Which probably explains why only
smullohi
andumullohi
are inTargetSelectionDAG
— the others can't be generated!dylanmckay commentedon Jan 17, 2016
Yeah
TargetSelectionDAG
nodes are pretty much added whenever someone needs one.shepmaster commentedon Jan 17, 2016
Just to make sure, you haven't yet pushed this, correct? If you have, I'm not sure where — I'm checking the branch list to see when it pops up.
dylanmckay commentedon Jan 17, 2016
No, I haven't pushed this. I'm hitting an assertion error which I'm working
on.
On 17 Jan 2016 16:34, "Jake Goulding" notifications@github.com wrote:
5 remaining items
dylanmckay commentedon Jan 18, 2016
llc -march=avr -mcpu=atmega328p -filetype=obj <in> -o <out>
should work. Note that you can also pass-filetype=asm
to view AVR assembly.bugpoint
sometimes works really well, but sometimes it does pretty much nothing. If you set up a bash script to simply call out tollc
, you can pass it into bugpoint and it'll keep minimizing, while ensuring the code it creates still generates the same error.shepmaster commentedon Jan 18, 2016
Well,
bugpoint
seems to have reduced to a different error:So that probably means I'm using it incorrectly.
dylanmckay commentedon Jan 18, 2016
I just remembered that bugpoint doesn't actually check the output of the
script it runs, just whether it passed or failed. You're likely using it
correctly, and now have found two bugs ;)
On Tue, Jan 19, 2016 at 10:13 AM, Jake Goulding notifications@github.com
wrote:
shepmaster commentedon Jan 18, 2016
Yup. I was letting it fail on any failure, not just the one I wanted. Now I've got a handle on it and submitted. I guess I should try to find the other failure too.
shepmaster commentedon Jan 18, 2016
Done.
shepmaster commentedon Jan 18, 2016
And I went ahead and opened another issue for the original multiplication issue.
dylanmckay commentedon Jan 19, 2016
I've just updated LLVM to master (it requires updating LLVM,
clang
, andcompiler-rt
) and ensuring they all work together.I left a
avr-rust
branch onavr-llvm/llvm
which points to theavr-support
branch you were using previously, although the specific commit is likely stored in your.gitmodules
file so it shouldn't be a problem.dylanmckay commentedon Jan 19, 2016
@shepmaster can you give me the IR for the original multiplication (preferrable bugpoint'ed, but no worries) issue of this thread? If you look at
test/CodeGen/AVR/mul.ll
(which passes), we currently do support multiplication, so there must be another underlying issue.shepmaster commentedon Jan 19, 2016
Yup, not a problem. I merged
avr-support
andavr-rust-support
locally to get the newest stuff, plus some hacks of my own. Whenever there's progress I should be able to do the same again. Or did you want me to try updating and see if errors had changed?Good point. I've updated that issue.
shepmaster commentedon Jan 19, 2016
I went ahead and updated. While compiling LLVM seemed to succeed, I am getting issues with the Rust wrapper around LLVM. So that should be exciting to try and fix:
I expect I'll have to dig though the LLVM changes to see what needs to be modified.
dylanmckay commentedon Sep 25, 2016
Closing due to this being super stale
Auto merge of rust-lang#37573 - ruuda:faster-cursor, r=alexcrichton