[SimplifyCFG] Improve linear mapping in switch lookup tables by dtcxzyw · Pull Request #67881 · llvm/llvm-project (original) (raw)

@llvm/pr-subscribers-llvm-transforms

Changes

This patch handles the pattern highbits | ((offset + index * multiplier) & lowbits_mask).

Example:

int f1(int x) {
  switch (x) {
    case 0: return 255;
    case 1: return 0;
    case 2: return 1;
    case 3: return 2;
    default: __builtin_unreachable();
  }
}

generates:

define i32 @<!-- -->f1(i32 %x) {
entry:
  %switch.offset = add i32 %x, 255
  %switch.masked = and i32 %switch.offset, 255
  ret i32 %switch.masked
}

Fixes #67843.


Full diff: https://github.com/llvm/llvm-project/pull/67881.diff

3 Files Affected:

diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index 35fead111aa9666..ff323e43866b477 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -6082,6 +6082,8 @@ class SwitchLookupTable { ConstantInt *LinearOffset = nullptr; ConstantInt *LinearMultiplier = nullptr; bool LinearMapValWrapped = false;

@@ -6139,46 +6141,80 @@ SwitchLookupTable::SwitchLookupTable( // Check if we can derive the value with a linear transformation from the // table index. if (isa(ValueType)) {

@@ -6232,6 +6268,19 @@ Value *SwitchLookupTable::BuildLookup(Value *Index, IRBuilder<> &Builder) { Result = Builder.CreateAdd(Result, LinearOffset, "switch.offset", /*HasNUW = */ false, /*HasNSW = */ !LinearMapValWrapped); +

+; The table for @linearmap_masked_with_common_highbits_fail +; CHECK: @switch.table.linearmap_masked_with_common_highbits_fail = private unnamed_addr constant [3 x i32] [i32 1023, i32 256, i32 257], align 4 + ; A simple int-to-int selection switch. ; It is dense enough to be replaced by table lookup. ; The result is directly by a ret from an otherwise empty bb, @@ -2068,3 +2071,93 @@ cond.end: ; preds = %entry, %cond.false %conv = sext i3 %cond to i8 ret i8 %conv } + +define i32 @pr67843(i8 %0) { +; CHECK-LABEL: @pr67843( +; CHECK-NEXT: start: +; CHECK-NEXT: [[SWITCH_TABLEIDX:%.]] = sub nsw i8 [[TMP0:%.]], -1 +; CHECK-NEXT: [[SWITCH_IDX_CAST:%.]] = zext i8 [[SWITCH_TABLEIDX]] to i32 +; CHECK-NEXT: [[SWITCH_OFFSET:%.]] = add i32 [[SWITCH_IDX_CAST]], 255 +; CHECK-NEXT: [[SWITCH_MASKED:%.*]] = and i32 [[SWITCH_OFFSET]], 255 +; CHECK-NEXT: ret i32 [[SWITCH_MASKED]] +; +start: