target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128" target triple = "aarch64-unknown-linux-gnu" define void @test(i8 %arg) { %tmp = alloca i8 %cmp1 = icmp ne i8 %arg, 1 %zext = zext i1 %cmp1 to i8 store i8 %zext, i8* %tmp %zext2 = load i8, i8* %tmp %cmp2 = icmp eq i8 %zext2, 3 br i1 %cmp2, label %exit, label %do_call do_call: call void @unknown(i8 %zext2) ret void exit: ret void } declare void @unknown(i8) Running through llc produces: // %bb.0: str x30, [sp, #-16]! // 8-byte Folded Spill .cfi_def_cfa_offset 16 .cfi_offset w30, -16 and w8, w0, #0xff cmp w8, #1 cset w0, ne strb w0, [sp, #12] b.ne .LBB0_2 // %bb.1: // %do_call bl unknown .LBB0_2: // %common.ret ldr x30, [sp], #16 // 8-byte Folded Reload ret Note how the final comparison to #3 has now reuses the result of the comparison to #1. This is caused by the new optimization introduced in https://reviews.llvm.org/D98564. From a cursory reading, this optimization was written under the assumption that CmpValue==1 means that the comparison is against #1, while analyzeCompare() canonicalizes the comparison such that CmpValue==1 indicates a comparison against any non-zero value.
Candidate patch: https://reviews.llvm.org/D108076
Fixed by https://github.com/llvm/llvm-project/commit/81b106584f2baf33e09be2362c35c1bf2f6bfe94. Keeping this open to track release/13.x backport.
Merged: b643ee1b9c1a