Skip to content

Unnecessary sext when optimizing a switch on riscv #124841

Open
@WaffleLapkin

Description

@WaffleLapkin

Given this llvm-ir (output of rustc, see details in rust-lang/rust#136216):

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:

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:

 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 (and godbolt link with more versions of the function, which I was experimenting with).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions