Skip to content

SimplifyCFG switch removal should add no-wrap flags when possible #59671

@scottmcm

Description

@scottmcm

Today, LLVM optimizes

define noundef i8 @src(i8 noundef %x) unnamed_addr {
start:
  switch i8 %x, label %bb3 [
    i8 -1, label %bb1
    i8 0, label %bb5
    i8 1, label %bb2
  ]

bb3:                                              ; preds = %start
  unreachable

bb5:                                              ; preds = %start
  br label %bb1

bb2:                                              ; preds = %start
  br label %bb1

bb1:                                              ; preds = %start, %bb5, %bb2
  %.0 = phi i8 [ -1, %bb2 ], [ 0, %bb5 ], [ 1, %start ]
  ret i8 %.0
}

down to

start:
  %switch.offset = sub i8 0, %x
  ret i8 %switch.offset

That's a huge improvement, but it could be slightly better as a sub nsw instead: https://alive2.llvm.org/ce/z/GZs_dj

If I'm understanding things right, SimplifyCFG turns the switch into

define noundef i8 @tgt(i8 noundef %x) unnamed_addr {
start:
  %switch.tableidx = sub i8 %x, -1
  %switch.idx.mult = mul i8 %switch.tableidx, -1
  %switch.offset = add i8 %switch.idx.mult, 1
  ret i8 %switch.offset
}

but in this case it could (https://alive2.llvm.org/ce/z/XzPeQv) have those be sub nsw, mul nsw, and add nsw, to better preserve the knowledge of the limited input range -- or maybe special case switches that map 0 to 0 to just emit mul nsw (or nuw) when legal without the extra sub/add complication.

Then something else (instcombine?) could take advantage of those nsw flags to optimize down to just the sub nsw i8, 0, %x: https://alive2.llvm.org/ce/z/tESh4R. But it looks like they got lost right now (https://llvm.godbolt.org/z/3dMW8j1sr), so maybe there'd be more work there too. (If SimplifyCFG left off the sub/add, though, and just had the mul nsw, then InstCombine looks like it would already preserve the nsw to the sub https://llvm.godbolt.org/z/9der4sraG.)


Original rust exploration that led me here: https://rust.godbolt.org/z/EW1aba8Mr

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