`f64::round` produces Illegal Instruction on `arm-unknown-linux-gnueabihf`

Hi,

I'm using cross to compile a program for a Raspberry Pi Zero W (arm-unknown-linux-gnueabihf).

The program crashes with an “Illegal Instruction” error however, when I try rounding an f64.

fn main() {
  let v: f64 = 0.0;
  println!("works: {:?}", v);
  println!("fails: {:?}", (v * 10.0).round());
}

The weird thing is, this doesn't fail:

fn main() {
  let v: f64 = 0.0;
  println!("works: {:?}", v.round());
  println!("works: {:?}", (v * 10.0).round());
}

Neither does this:

fn main() {
  let v: f64 = 0.0;
  println!("works: {:?}", v);
  println!("works: {:?}", (v * 1.0).round());
}

I have no idea what is going on, any help is appreciated.

Note: I have also tried compiling with arm-unknown-linux-gnueabi, which shows the same behaviour, except instead of crashing with an “Illegal Instruction” it produces NaN.

If you haven't already, I'd suggest creating an issue on the rust issue tracker.

It sounds like arm-unknown-linux-gnuabihf may not be the right target to use for your platform. Or maybe the target definition itself is incorrect, so rustc tells LLVM to generate the wrong instructions.

1 Like

This sounds right to me.

@reitermarkus The last part of your triple, hf, indicates the ARM target supports hardware floats.

It sounds like your Raspberry PI W doesn't supports hardware floats, and thus hardware instructions operating on floats fail. I'm guessing the code that works only works because the compiler decided to perform the rounding operations at compile time, rather than runtime, and that optimization can be pretty fickle.

I would recommend setting your target to arm-unknown-linux-gnueabi instead. Note the lack of hf on the end means that hardware floating point operations ("Hard Float" operations) won't be generated, and software emulation of floating point ops will be done instead.

1 Like

The people are correct here.
According to https://en.wikipedia.org/wiki/Raspberry_Pi#Specifications the Zero has no NEON FPU, therefore gnueabihf is the wrong target. (I also can't find anything FPU related in the datasheet).

On the Raspberry Pi, gcc -dumpmachine returns arm-linux-gnueabihf, does that not mean it supports them?

As I said in the note above, this produces NaN instead, so this

fn main() {
  let v: f64 = 0.0;
  println!("works: {:?}", v);
  println!("fails: {:?}", (v * 10.0).round());
}

will actually output

works: 0.0
fails: NaN
1 Like

I opened an issue here: https://github.com/rust-lang/rust/issues/63098

Seems to be a nightly bug, since it works on stable.

1 Like

I wasn't using the latest nightly because of clippy, this seems to be fixed. Thanks all for your help!

1 Like