Originally reported at: https://github.com/rust-lang/rust/issues/57631 Test case: define void @test(i32 %x, i1* %p) { %y = and i32 %x, 1 %c = icmp eq i32 %y, 1 store i1 %c, i1* %p br i1 %c, label %foo, label %foo foo: ret void } Running this through llc -march=mipsel -mcpu=mips32 -relocation-model=pic -O0 gives: # %bb.0: move $1, $4 andi $4, $4, 1 sb $4, 0($5) bgtz $1, $BB0_1 nop # %bb.1: # %foo jr $ra nop While the sb is correct, the bgtz argument is the unmasked function argument. The cause is very similar to https://bugs.llvm.org/show_bug.cgi?id=40172. In https://github.com/llvm-mirror/llvm/blob/00f59269287658489eda6279e52ae058dc686c96/lib/Target/Mips/MipsFastISel.cpp#L955 an icmp result stored in an i32 virtual register is assumed to have only value 0 or 1, while in reality only the low-bit of the register has a well-defined value. In https://github.com/llvm-mirror/llvm/commit/7b129940425f14653692ae13dc7a33d551413444 a variant of this issue affecting i1 icmps was fixed. However, the issue is more general than that and can occur with arbitrary icmps if they come from a SelectionDAG fallback and happen to be combined in just the right way. I believe the correct way to handle this is to fastEmitZExtFromI1() the branch condition (even though this will regress FastISel code quality).
https://reviews.llvm.org/D58576
Fixed by https://reviews.llvm.org/rL354808.