Invalid instruction generated on armV4

I’m tying to run a rust application on armv4 architecture (arm720tdmi).
Rust is using llvm to generate native code.
Some programs are running well on the target but for more complex applications I receive a Illegal instruction :

gdb disassembling the core dump file gives :

   0x401e41dc <+0>:	push	{r11, lr}
   0x401e41e0 <+4>:	mov	r11, sp
   0x401e41e4 <+8>:	sub	sp, sp, #8
   0x401e41e8 <+12>:	ldr	r0, [r0]
   0x401e41ec <+16>:	str	r0, [sp, #4]
   0x401e41f0 <+20>:	mov	r0, r1
   0x401e41f4 <+24>:	ldr	r1, [sp, #4]
=> 0x401e41f8 <+28>:	blx	r1
   0x401e41fc <+32>:	and	r0, r0, #1
   0x401e4200 <+36>:	and	r0, r0, #1
   0x401e4204 <+40>:	mov	sp, r11
   0x401e4208 <+44>:	pop	{r11, lr}
   0x401e420c <+48>:	bx	lr

blx instruction is available from ARM architecture v5 and above…

After lot of investigations I found where llvm is generating this instruction :
https://github.com/rust-lang/llvm/blob/168f91ce5cbf8933e47f339911f0f46a48714852/lib/Target/ARM/ARMFastISel.cpp#L2395
UseReg variable is true causing ARMSelectCallOp function to set a BLX instruction that is not supported on armv4 :frowning:

Could you help me to solve this ?

Many thanks

Frédéric.

What LLVM version are you using?

There were some bugs around switching ARM/Thumb mode on ARMv4 fixed in 3.6.

I’m using rust head version that currently use llvm 3.7 …

Thanks.

Frédéric.

Yes, I saw that, tracking the GitHub repo relatively closely.

I also thought about that v4 bug on the same area from 3.6, but this
seems to be a new one.

I think the best thing to do now is to create a bugzilla entry with as
much information as you can. If possible, try to reduce to a piece of
IR that reproduces the failure with standard tools. If not, the more
you can provide the better, so at least we can help you debug the
problem.

cheers,
--renato

I’m using rust head version that currently use llvm 3.7 …

Yes, I saw that, tracking the GitHub repo relatively closely.

I also thought about that v4 bug on the same area from 3.6, but this
seems to be a new one.

I think the best thing to do now is to create a bugzilla entry with as
much information as you can. If possible, try to reduce to a piece of
IR that reproduces the failure with standard tools. If not, the more
you can provide the better, so at least we can help you debug the
problem.

I wish I had set up a v4/v4t buildbot :frowning:

Jon

I wish ARM would make up their minds which methods of changing the PC switch ARM/Thumb modes and which don’t!

Thanks renato I will try to do this but it is quite difficult for me, I don’t known a lot about llvm project, not more than wikipedia definition :wink:
I had a look on ARMFatsISel source file history. In 2012 a change concerning “support for non-global callee” has removed a guard condition in SelectCall method.
<<https://github.com/llvm-mirror/llvm/commit/1c8fccbc12e6348c8003aff9b89078324257fc4e>>

// Only handle global variable Callees.
const GlobalValue *GV = dyn_cast(Callee);
if (!GV)
return false;

I restored this peace of code in my local llvm source code, rebuild rust and … no more blx instruction generated, all my run programs seems to run correctly !
I’m sure it is not a solution but it could help to solve/understand the issue.

Have a nice we.

Frédéric.

I think you've found the bug!

That line you just added back moves the lowering of the call away from
that code, but right now, it's following down and reaching the piece
of code:

+ if (!GV){
+ CallOpc = isThumb2 ? ARM::tBLXr : ARM::BLX;
+ CalleeReg = getRegForValue(Callee);
+ if (CalleeReg == 0) return false;
+ }

With the problem here being:

+ CallOpc = isThumb2 ? ARM::tBLXr : ARM::BLX;

If your variable is not global, and you're not in Thumb2 mode, it
selects ARM's BLX. This conditional is incomplete, as it should also
be enquiring about ARMv4 and using BX plus adding something akin "mov
lr, pc" before.

If keeping the patch helps you, then please keep it local until this
is properly fixed.

For now, I have created a bug
(https://llvm.org/bugs/show_bug.cgi?id=24858) and added Jonathan and
Tim, both folks that worked with ARMv4 and have a better knowledge of
FastISel than I do.

It'd be hard for me to test this, as I don't have access to a v4T
anymore and QEMU doesn't seem to emulate anything before v5. :frowning: Maybe
someone else could have a look at it earlier than I can get my hands
in one.

cheers,
--renato