Issue 124841
Summary Unnecessary sext when optimizing a switch on riscv
Labels new issue
Assignees
Reporter WaffleLapkin
    Given this llvm-ir (output of rustc, see details in https://github.com/rust-lang/rust/issues/136216):
```llvm
define dso_local noundef range(i8 1, 9) i8 @opposite_match(i8 noundef zeroext range(i8 1, 9) %0) unnamed_addr {
start:
  %_0 = alloca [1 x i8], align 1
 %x = alloca [1 x i8], align 1
  store i8 %0, ptr %x, align 1
  %1 = load i8, ptr %x, align 1
  %_2 = zext i8 %1 to i32
  switch i32 %_2, label %bb1 [
    i32 1, label %bb5
    i32 2, label %bb4
    i32 4, label %bb3
 i32 8, label %bb2
  ]

bb1:                                              ; preds = %start
  unreachable

bb5: ; preds = %start
  store i8 4, ptr %_0, align 1
  br label %bb6

bb4:                                              ; preds = %start
 store i8 8, ptr %_0, align 1
  br label %bb6

bb3: ; preds = %start
  store i8 1, ptr %_0, align 1
  br label %bb6

bb2:                                              ; preds = %start
  store i8 2, ptr %_0, align 1
  br label %bb6

bb6: ; preds = %bb2, %bb3, %bb4, %bb5
  %2 = load i8, ptr %_0, align 1
  ret i8 %2
}
```
llvm currently produces this:

```asm
opposite_match:
        addi    a0, a0, -1
        slli a0, a0, 24
        srai    a0, a0, 24
        lui     a1, %hi(.Lswitch.table.opposite_match)
        addi    a1, a1, %lo(.Lswitch.table.opposite_match)
        add     a0, a1, a0
        lbu a0, 0(a0)
        ret

.Lswitch.table.opposite_match:
        .ascii "\004\b\004\001\004\004\004\002"
```

`slli` + `srai` is a `i8`->`i32` sign extension, but it's not needed here -- `1 <= a0 <= 8` originally (from the `range` attribute) and after subtracting `1` it's obviously `0 <= a0 <= 7`, so sign extension is the same as zero extension (and thus could be a noop in this case).

`sext` is added in an `InstCombinePass`:

```diff
 define dso_local noundef range(i8 1, 9) i8 @opposite_match(i8 noundef zeroext range(i8 1, 9) %0) unnamed_addr {
 start:
-  %switch.tableidx = sub nsw i8 %0, 1
-  %switch.gep = getelementptr inbounds [8 x i8], ptr @switch.table.opposite_match, i32 0, i8 %switch.tableidx
+  %switch.tableidx = add nsw i8 %0, -1
+  %1 = sext i8 %switch.tableidx to i32
+  %switch.gep = getelementptr inbounds [8 x i8], ptr @switch.table.opposite_match, i32 0, i32 %1
   %switch.load = load i8, ptr %switch.gep, align 1
   ret i8 %switch.load
 }
```

[Godbolt link](https://godbolt.org/z/jdE4vYPYa) (and [godbolt link with more versions of the function, which I was experimenting with](https://godbolt.org/z/vGjGT9oW1)).
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to