[llvm] 68079ef - Teach SimplifyCFG to fold switches into lookup tables in more cases.

Owen Anderson via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 15 15:07:13 PDT 2021


Author: Owen Anderson
Date: 2021-09-15T22:07:08Z
New Revision: 68079ef0eb011c8349e5ae84b95216e5039dbc16

URL: https://github.com/llvm/llvm-project/commit/68079ef0eb011c8349e5ae84b95216e5039dbc16
DIFF: https://github.com/llvm/llvm-project/commit/68079ef0eb011c8349e5ae84b95216e5039dbc16.diff

LOG: Teach SimplifyCFG to fold switches into lookup tables in more cases.

In particular, it couldn't handle cases where lookup table constant
expressions involved bitcasts. This does not seem to come up
frequently in C++, but comes up reasonably often in Rust via
`#[derive(Debug)]`.

Originally reported by pcwalton.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D109565

Added: 
    llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-bitcast.ll
    llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-gep.ll

Modified: 
    llvm/lib/Transforms/Utils/SimplifyCFG.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 590a961e02d04..2a05dd7f5012a 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -5066,9 +5066,10 @@ static bool ValidLookupTableConstant(Constant *C, const TargetTransformInfo &TTI
     return false;
 
   if (ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
-    if (!CE->isGEPWithNoNotionalOverIndexing())
-      return false;
-    if (!ValidLookupTableConstant(CE->getOperand(0), TTI))
+    // Pointer casts and in-bounds GEPs will not prohibit the backend from
+    // materializing the array of constants.
+    Constant *StrippedC = cast<Constant>(CE->stripInBoundsConstantOffsets());
+    if (StrippedC == C || !ValidLookupTableConstant(StrippedC, TTI))
       return false;
   }
 

diff  --git a/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-bitcast.ll b/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-bitcast.ll
new file mode 100644
index 0000000000000..9a567f38a24b4
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-bitcast.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes
+; RUN: opt -simplifycfg --switch-to-lookup -S < %s | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+
+ at alloc0 = private unnamed_addr constant <{ [1 x i8] }> <{ [1 x i8] c"A" }>, align 1
+ at alloc1 = private unnamed_addr constant <{ [1 x i8] }> <{ [1 x i8] c"B" }>, align 1
+ at alloc2 = private unnamed_addr constant <{ [1 x i8] }> <{ [1 x i8] c"C" }>, align 1
+
+define { [0 x i8]*, i64 } @switch_to_lookup_bitcast(i8 %0) unnamed_addr {
+; CHECK-LABEL: @switch_to_lookup_bitcast(
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x [0 x i8]*], [3 x [0 x i8]*]* @switch.table.switch_to_lookup_bitcast, i32 0, i8 [[TMP0:%.*]]
+; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load [0 x i8]*, [0 x i8]** [[SWITCH_GEP]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { [0 x i8]*, i64 } undef, [0 x i8]* [[SWITCH_LOAD]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { [0 x i8]*, i64 } [[TMP1]], i64 1, 1
+; CHECK-NEXT:    ret { [0 x i8]*, i64 } [[TMP2]]
+;
+start:
+  switch i8 %0, label %default [
+  i8 0, label %bb0
+  i8 1, label %bb1
+  i8 2, label %bb2
+  ]
+
+bb0:
+  br label %end
+
+bb1:
+  br label %end
+
+bb2:
+  br label %end
+
+default:
+  unreachable
+
+end:
+  %.sroa.0.0 = phi [0 x i8]* [ bitcast (<{ [1 x i8] }>* @alloc0 to [0 x i8]*), %bb0 ], [ bitcast (<{ [1 x i8] }>* @alloc1 to [0 x i8]*), %bb1 ], [ bitcast (<{ [1 x i8] }>* @alloc2 to [0 x i8]*), %bb2 ]
+  %1 = insertvalue { [0 x i8]*, i64 } undef, [0 x i8]* %.sroa.0.0, 0
+  %2 = insertvalue { [0 x i8]*, i64 } %1, i64 1, 1
+  ret { [0 x i8]*, i64 } %2
+}

diff  --git a/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-gep.ll b/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-gep.ll
new file mode 100644
index 0000000000000..0bd7ef94a18b1
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/X86/switch-to-lookup-gep.ll
@@ -0,0 +1,134 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --scrub-attributes
+; RUN: opt -simplifycfg --switch-to-lookup -S < %s | FileCheck %s
+target triple = "x86_64-unknown-linux-gnu"
+
+ at alloc0 = private unnamed_addr constant <{ [2 x i8] }> <{ [2 x i8] c"A1" }>, align 1
+ at alloc1 = private unnamed_addr constant <{ [2 x i8] }> <{ [2 x i8] c"B2" }>, align 1
+ at alloc2 = private unnamed_addr constant <{ [2 x i8] }> <{ [2 x i8] c"C3" }>, align 1
+
+define { i8*, i64 } @switch_to_lookup_gep(i8 %0) unnamed_addr {
+; CHECK-LABEL: @switch_to_lookup_gep(
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    [[SWITCH_GEP:%.*]] = getelementptr inbounds [3 x i8*], [3 x i8*]* @switch.table.switch_to_lookup_gep, i32 0, i8 [[TMP0:%.*]]
+; CHECK-NEXT:    [[SWITCH_LOAD:%.*]] = load i8*, i8** [[SWITCH_GEP]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8*, i64 } undef, i8* [[SWITCH_LOAD]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { i8*, i64 } [[TMP1]], i64 1, 1
+; CHECK-NEXT:    ret { i8*, i64 } [[TMP2]]
+;
+start:
+  switch i8 %0, label %default [
+  i8 0, label %bb0
+  i8 1, label %bb1
+  i8 2, label %bb2
+  ]
+
+bb0:
+  br label %end
+
+bb1:
+  br label %end
+
+bb2:
+  br label %end
+
+default:
+  unreachable
+
+end:
+  %.sroa.0.0 = phi i8* [ getelementptr inbounds (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc0, i32 0, i32 0, i32 1), %bb0 ], [ getelementptr inbounds (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc1, i32 0, i32 0, i32 1), %bb1 ], [ getelementptr inbounds (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc2, i32 0, i32 0, i32 1), %bb2 ]
+  %1 = insertvalue { i8*, i64 } undef, i8* %.sroa.0.0, 0
+  %2 = insertvalue { i8*, i64 } %1, i64 1, 1
+  ret { i8*, i64 } %2
+}
+
+define { i8*, i64 } @switch_to_lookup_gep_oob(i8 %0) unnamed_addr {
+; CHECK-LABEL: @switch_to_lookup_gep_oob(
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[TMP0:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:    i8 0, label [[END:%.*]]
+; CHECK-NEXT:    i8 1, label [[BB1:%.*]]
+; CHECK-NEXT:    i8 2, label [[BB2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       bb1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       bb2:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       default:
+; CHECK-NEXT:    unreachable
+; CHECK:       end:
+; CHECK-NEXT:    [[DOTSROA_0_0:%.*]] = phi i8* [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc1, i32 0, i32 0, i32 4), [[BB1]] ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc2, i32 0, i32 0, i32 4), [[BB2]] ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc0, i32 0, i32 0, i32 4), [[START:%.*]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8*, i64 } undef, i8* [[DOTSROA_0_0]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { i8*, i64 } [[TMP1]], i64 1, 1
+; CHECK-NEXT:    ret { i8*, i64 } [[TMP2]]
+;
+start:
+  switch i8 %0, label %default [
+  i8 0, label %bb0
+  i8 1, label %bb1
+  i8 2, label %bb2
+  ]
+
+bb0:
+  br label %end
+
+bb1:
+  br label %end
+
+bb2:
+  br label %end
+
+default:
+  unreachable
+
+end:
+  %.sroa.0.0 = phi i8* [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc0, i32 0, i32 0, i32 4), %bb0 ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc1, i32 0, i32 0, i32 4), %bb1 ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc2, i32 0, i32 0, i32 4), %bb2 ]
+  %1 = insertvalue { i8*, i64 } undef, i8* %.sroa.0.0, 0
+  %2 = insertvalue { i8*, i64 } %1, i64 1, 1
+  ret { i8*, i64 } %2
+}
+
+define { i8*, i64 } @switch_to_lookup_gep_ptrtoint(i8 %0) unnamed_addr {
+; CHECK-LABEL: @switch_to_lookup_gep_ptrtoint(
+; CHECK-NEXT:  start:
+; CHECK-NEXT:    switch i8 [[TMP0:%.*]], label [[DEFAULT:%.*]] [
+; CHECK-NEXT:    i8 0, label [[END:%.*]]
+; CHECK-NEXT:    i8 1, label [[BB1:%.*]]
+; CHECK-NEXT:    i8 2, label [[BB2:%.*]]
+; CHECK-NEXT:    ]
+; CHECK:       bb1:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       bb2:
+; CHECK-NEXT:    br label [[END]]
+; CHECK:       default:
+; CHECK-NEXT:    unreachable
+; CHECK:       end:
+; CHECK-NEXT:    [[DOTSROA_0_0:%.*]] = phi i8* [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc1, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), [[BB1]] ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc2, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), [[BB2]] ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc0, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), [[START:%.*]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = insertvalue { i8*, i64 } undef, i8* [[DOTSROA_0_0]], 0
+; CHECK-NEXT:    [[TMP2:%.*]] = insertvalue { i8*, i64 } [[TMP1]], i64 1, 1
+; CHECK-NEXT:    ret { i8*, i64 } [[TMP2]]
+;
+start:
+  switch i8 %0, label %default [
+  i8 0, label %bb0
+  i8 1, label %bb1
+  i8 2, label %bb2
+  ]
+
+bb0:
+  br label %end
+
+bb1:
+  br label %end
+
+bb2:
+  br label %end
+
+default:
+  unreachable
+
+end:
+  %.sroa.0.0 = phi i8* [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc0, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), %bb0 ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc1, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), %bb1 ], [ getelementptr (<{ [2 x i8] }>, <{ [2 x i8] }>* @alloc2, i32 0, i32 0, i64 ptrtoint (<{ [2 x i8] }>* @alloc0 to i64)), %bb2 ]
+  %1 = insertvalue { i8*, i64 } undef, i8* %.sroa.0.0, 0
+  %2 = insertvalue { i8*, i64 } %1, i64 1, 1
+  ret { i8*, i64 } %2
+}


        


More information about the llvm-commits mailing list