Issue 180892
Summary [Miscompilation] Silent elimination of control flow due to undef in branch condition
Labels new issue
Assignees
Reporter selim0h
    I have observed a case where the LLVM optimizer silently eliminates a critical branch condition when it involves an undef value. Instead of preserving the check or freezing the undefined value, the compiler assumes the condition is always false and removes the entire protected code block.

**Environment:**
LLVM version: 18.0.0 (Commit: 024718313b52) 
Target: x86_64-unknown-linux-gnu

**Reproduction Steps:**

1. Create repro.ll:

```
target triple = "x86_64-unknown-linux-gnu"
@.str = private unnamed_addr constant [3 x i8] c"ok\00", align 1

define i32 @test_func(i32 %a) {
entry:
  %add = add nsw i32 undef, 10
  %cmp = icmp sgt i32 %add, %a
  br i1 %cmp, label %if.then, label %if.end

if.then:
  %call = call i32 @puts(ptr @.str)
 br label %if.end

if.end:
  ret i32 0
}

declare i32 @puts(ptr)
```

2. Run: llc -O2 repro.ll -o repro.s

**Actual Results:** The compiler replaces the dynamic comparison with a constant-time jump. In the generated assembly, the comparison against input %a is completely missing:
```
test_func:
# %bb.0:
    movb    $1, %al
    testb   %al, %al
    jne .LBB0_2         # Unconditionally jumps to end
# %bb.1: # Dead code: puts("ok") is never reached
    ...
    callq puts@PLT
.LBB0_2:
    xorl    %eax, %eax
    retq
```
The compiler has hardcoded %al = 1 and jne, ensuring the if.then block is never executed, regardless of the runtime value of %a.

**Expected Results:** While undef allows flexibility, the silent removal of defensive logic (like overflow or bounds checks) is problematic. The compiler should maintain the check's determinism, perhaps by automatically inserting a freeze on undef values when they reach a branch condition to prevent the deletion of the code path. 

_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to