There is some simple code that takes the if, transforms it to a switch and then produces duplicate ja (for x86 for example, also confirmed for RISC-V) instructions.
void foo(unsigned short x, int* res) {
if ( (x <= 13) && (x == 9 || x == 10 || x == 13)) {
*res +=5;
}
}
The IR looks fine:
define dso_local void @foo(i16 noundef zeroext %x, ptr nocapture noundef %res) local_unnamed_addr #0 {
entry:
%cmp = icmp ult i16 %x, 14
br i1 %cmp, label %land.lhs.true, label %if.end
land.lhs.true: ; preds = %entry
switch i16 %x, label %if.end [
i16 13, label %if.then
i16 10, label %if.then
i16 9, label %if.then
]
if.then: ; preds = %land.lhs.true, %land.lhs.true, %land.lhs.true
%0 = load i32, ptr %res, align 4, !tbaa !5
%add = add nsw i32 %0, 5
store i32 %add, ptr %res, align 4, !tbaa !5
br label %if.end
if.end: ; preds = %land.lhs.true, %if.then, %entry
ret void
}
And the resulting asm:
.text
.file "test.c"
.globl foo # -- Begin function foo
.p2align 4, 0x90
.type foo,@function
foo: # @foo
.cfi_startproc
# %bb.0: # %entry
cmpw $13, %di
ja .LBB0_4
# %bb.1: # %land.lhs.true
ja .LBB0_4
# %bb.2: # %land.lhs.true
movzwl %di, %eax
movl $9728, %ecx # imm = 0x2600
btl %eax, %ecx
jae .LBB0_4
# %bb.3: # %if.then
addl $5, (%rsi)
.LBB0_4: # %if.end
retq
.Lfunc_end0:
.size foo, .Lfunc_end0-foo
.cfi_endproc
# -- End function
.ident "clang version 17.0.0 (https://github.com/llvm/llvm-project.git 65c0134872c1e298ade176b5c84d86b4a058a85c)"
.section ".note.GNU-stack","",@progbits
You can see the ja .LBB0_4 is a duplicate. Not sure where to fix this exactly, there are a few different places.