[llvm] 78386bf - [NVPTX] Implement shouldBuildLookupTablesForConstant (#220088)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Sep 29 09:59:34 PDT 2026
Author: Alex MacLean
Date: 2026-09-29T09:59:27-07:00
New Revision: 78386bf17e0b685790ae83efc9b9f8c316bd5583
URL: https://github.com/llvm/llvm-project/commit/78386bf17e0b685790ae83efc9b9f8c316bd5583
DIFF: https://github.com/llvm/llvm-project/commit/78386bf17e0b685790ae83efc9b9f8c316bd5583.diff
LOG: [NVPTX] Implement shouldBuildLookupTablesForConstant (#220088)
Exclude addresses of GlobalValues in unsupported address spaces.
Assisted-by: Claude.
Added:
llvm/test/Transforms/SimplifyCFG/NVPTX/lit.local.cfg
llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
Modified:
llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 3bbbaef3686ee..72ec95abeb509 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -672,6 +672,18 @@ void NVPTXTTIImpl::collectKernelLaunchBounds(
LB.push_back({"maxntidz", MaxNTID[2]});
}
+// Global addresses can only be materialized if they are in generic global or
+// constant space.
+bool NVPTXTTIImpl::shouldBuildLookupTablesForConstant(Constant *C) const {
+ if (const auto *GV = dyn_cast<GlobalValue>(C)) {
+ const unsigned AS = GV->getAddressSpace();
+ return AS == NVPTXAS::ADDRESS_SPACE_GENERIC ||
+ AS == NVPTXAS::ADDRESS_SPACE_GLOBAL ||
+ AS == NVPTXAS::ADDRESS_SPACE_CONST;
+ }
+ return true;
+}
+
ValueUniformity NVPTXTTIImpl::getValueUniformity(const Value *V) const {
if (isSourceOfDivergence(V))
return ValueUniformity::NeverUniform;
diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
index 89d2bfa337570..37105898038c5 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.h
@@ -231,6 +231,8 @@ class NVPTXTTIImpl final : public BasicTTIImplBase<NVPTXTTIImpl> {
return false;
}
+ bool shouldBuildLookupTablesForConstant(Constant *C) const override;
+
InstructionCost getPartialReductionCost(
unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
ElementCount VF, TTI::PartialReductionExtendKind OpAExtend,
diff --git a/llvm/test/Transforms/SimplifyCFG/NVPTX/lit.local.cfg b/llvm/test/Transforms/SimplifyCFG/NVPTX/lit.local.cfg
new file mode 100644
index 0000000000000..0d37b86e1c8e6
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/NVPTX/lit.local.cfg
@@ -0,0 +1,2 @@
+if not "NVPTX" in config.root.targets:
+ config.unsupported = True
diff --git a/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll b/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
new file mode 100644
index 0000000000000..5127f9fdef29d
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
@@ -0,0 +1,636 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals all --version 6
+; RUN: opt -S -passes='simplifycfg<switch-to-lookup>' < %s | FileCheck %s
+
+target triple = "nvptx64-nvidia-cuda"
+
+ at buf0 = addrspace(3) global [16 x i8] poison, align 16
+ at buf1 = addrspace(3) global [16 x i8] poison, align 16
+ at buf2 = addrspace(3) global [16 x i8] poison, align 16
+ at buf3 = addrspace(3) global [16 x i8] poison, align 16
+
+ at loc0 = addrspace(5) global i32 poison
+ at loc1 = addrspace(5) global i32 poison
+ at loc2 = addrspace(5) global i32 poison
+ at loc3 = addrspace(5) global i32 poison
+
+ at gg0 = addrspace(1) global i32 0
+ at gg1 = addrspace(1) global i32 0
+ at gg2 = addrspace(1) global i32 0
+ at gg3 = addrspace(1) global i32 0
+
+ at cc0 = addrspace(4) constant i32 0
+ at cc1 = addrspace(4) constant i32 0
+ at cc2 = addrspace(4) constant i32 0
+ at cc3 = addrspace(4) constant i32 0
+
+ at ge0 = global i32 0
+ at ge1 = global i32 0
+ at ge2 = global i32 0
+ at ge3 = global i32 0
+
+;; Negative tests: no lookup table may be built for any of these.
+
+; The reported case: a phi of .shared globals.
+;.
+; CHECK: @buf0 = addrspace(3) global [16 x i8] poison, align 16
+; CHECK: @buf1 = addrspace(3) global [16 x i8] poison, align 16
+; CHECK: @buf2 = addrspace(3) global [16 x i8] poison, align 16
+; CHECK: @buf3 = addrspace(3) global [16 x i8] poison, align 16
+; CHECK: @loc0 = addrspace(5) global i32 poison
+; CHECK: @loc1 = addrspace(5) global i32 poison
+; CHECK: @loc2 = addrspace(5) global i32 poison
+; CHECK: @loc3 = addrspace(5) global i32 poison
+; CHECK: @gg0 = addrspace(1) global i32 0
+; CHECK: @gg1 = addrspace(1) global i32 0
+; CHECK: @gg2 = addrspace(1) global i32 0
+; CHECK: @gg3 = addrspace(1) global i32 0
+; CHECK: @cc0 = addrspace(4) constant i32 0
+; CHECK: @cc1 = addrspace(4) constant i32 0
+; CHECK: @cc2 = addrspace(4) constant i32 0
+; CHECK: @cc3 = addrspace(4) constant i32 0
+; CHECK: @ge0 = global i32 0
+; CHECK: @ge1 = global i32 0
+; CHECK: @ge2 = global i32 0
+; CHECK: @ge3 = global i32 0
+; CHECK: @switch.table.shared_only_in_default = private unnamed_addr constant [4 x ptr] [ptr addrspacecast (ptr addrspace(1) @gg0 to ptr), ptr addrspacecast (ptr addrspace(1) @gg1 to ptr), ptr addrspacecast (ptr addrspace(1) @gg2 to ptr), ptr addrspacecast (ptr addrspace(1) @gg3 to ptr)], align 8
+; CHECK: @switch.table.int_table = private unnamed_addr constant [4 x i8] c"*\07c\0D", align 4
+; CHECK: @switch.table.global_table = private unnamed_addr constant [4 x ptr addrspace(1)] [ptr addrspace(1) @gg0, ptr addrspace(1) @gg1, ptr addrspace(1) @gg2, ptr addrspace(1) @gg3], align 8
+; CHECK: @switch.table.const_table = private unnamed_addr constant [4 x ptr addrspace(4)] [ptr addrspace(4) @cc0, ptr addrspace(4) @cc1, ptr addrspace(4) @cc2, ptr addrspace(4) @cc3], align 8
+; CHECK: @switch.table.generic_global_table = private unnamed_addr constant [4 x ptr] [ptr @ge0, ptr @ge1, ptr @ge2, ptr @ge3], align 8
+; CHECK: @switch.table.func_table = private unnamed_addr constant [4 x ptr] [ptr @f0, ptr @f1, ptr @f2, ptr @f3], align 8
+;.
+define ptr addrspace(3) @shared_direct(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(3) @shared_direct(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB1]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr addrspace(3) [ null, %[[SW_DEFAULT]] ], [ @buf1, %[[SW_BB1]] ], [ @buf2, %[[SW_BB2]] ], [ @buf3, %[[SW_BB3]] ], [ @buf0, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr addrspace(3) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(3) [ @buf0, %sw.bb0 ], [ @buf1, %sw.bb1 ], [ @buf2, %sw.bb2 ], [ @buf3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr addrspace(3) %r
+}
+
+; Same, but through addrspacecast, so the table element type is generic. The
+; emitted initializer is "generic(buf0)", which ptxas rejects just the same.
+define ptr @shared_generic(i32 %i) {
+; CHECK-LABEL: define ptr @shared_generic(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB1]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, %[[SW_DEFAULT]] ], [ addrspacecast (ptr addrspace(3) @buf1 to ptr), %[[SW_BB1]] ], [ addrspacecast (ptr addrspace(3) @buf2 to ptr), %[[SW_BB2]] ], [ addrspacecast (ptr addrspace(3) @buf3 to ptr), %[[SW_BB3]] ], [ addrspacecast (ptr addrspace(3) @buf0 to ptr), %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ addrspacecast (ptr addrspace(3) @buf0 to ptr), %sw.bb0 ], [ addrspacecast (ptr addrspace(3) @buf1 to ptr), %sw.bb1 ], [ addrspacecast (ptr addrspace(3) @buf2 to ptr), %sw.bb2 ], [ addrspacecast (ptr addrspace(3) @buf3 to ptr), %sw.bb3 ], [ null, %sw.default ]
+ ret ptr %r
+}
+
+; The symbol is reached through a constant GEP.
+define ptr addrspace(3) @shared_gep(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(3) @shared_gep(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB1]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr addrspace(3) [ null, %[[SW_DEFAULT]] ], [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf1, i64 0, i64 8), %[[SW_BB1]] ], [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf2, i64 0, i64 12), %[[SW_BB2]] ], [ @buf3, %[[SW_BB3]] ], [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf0, i64 0, i64 4), %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr addrspace(3) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(3) [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf0, i64 0, i64 4), %sw.bb0 ], [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf1, i64 0, i64 8), %sw.bb1 ], [ getelementptr inbounds ([16 x i8], ptr addrspace(3) @buf2, i64 0, i64 12), %sw.bb2 ], [ @buf3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr addrspace(3) %r
+}
+
+; ... and through a GEP of an addrspacecast.
+define ptr @shared_nested(i32 %i) {
+; CHECK-LABEL: define ptr @shared_nested(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB1]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, %[[SW_DEFAULT]] ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf1 to ptr), i64 8), %[[SW_BB1]] ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf2 to ptr), i64 8), %[[SW_BB2]] ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf3 to ptr), i64 8), %[[SW_BB3]] ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf0 to ptr), i64 8), %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf0 to ptr), i64 8), %sw.bb0 ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf1 to ptr), i64 8), %sw.bb1 ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf2 to ptr), i64 8), %sw.bb2 ], [ getelementptr inbounds (i8, ptr addrspacecast (ptr addrspace(3) @buf3 to ptr), i64 8), %sw.bb3 ], [ null, %sw.default ]
+ ret ptr %r
+}
+
+; A single bad element poisons the whole table.
+define ptr @shared_one_of_four(i32 %i) {
+; CHECK-LABEL: define ptr @shared_one_of_four(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ null, %[[SW_DEFAULT]] ], [ addrspacecast (ptr addrspace(1) @gg0 to ptr), %[[ENTRY]] ], [ addrspacecast (ptr addrspace(3) @buf2 to ptr), %[[SW_BB2]] ], [ addrspacecast (ptr addrspace(1) @gg1 to ptr), %[[SW_BB3]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ addrspacecast (ptr addrspace(1) @gg0 to ptr), %sw.bb0 ], [ null, %sw.bb1 ], [ addrspacecast (ptr addrspace(3) @buf2 to ptr), %sw.bb2 ], [ addrspacecast (ptr addrspace(1) @gg1 to ptr), %sw.bb3 ], [ null, %sw.default ]
+ ret ptr %r
+}
+
+; .local symbols are not initializer-legal either.
+define ptr addrspace(5) @local_direct(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(5) @local_direct(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
+; CHECK-NEXT: i32 0, label %[[RETURN:.*]]
+; CHECK-NEXT: i32 1, label %[[SW_BB1:.*]]
+; CHECK-NEXT: i32 2, label %[[SW_BB2:.*]]
+; CHECK-NEXT: i32 3, label %[[SW_BB3:.*]]
+; CHECK-NEXT: ]
+; CHECK: [[SW_BB1]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB2]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_BB3]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[SW_DEFAULT]]:
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr addrspace(5) [ null, %[[SW_DEFAULT]] ], [ @loc1, %[[SW_BB1]] ], [ @loc2, %[[SW_BB2]] ], [ @loc3, %[[SW_BB3]] ], [ @loc0, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr addrspace(5) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(5) [ @loc0, %sw.bb0 ], [ @loc1, %sw.bb1 ], [ @loc2, %sw.bb2 ], [ @loc3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr addrspace(5) %r
+}
+
+;; Positive tests: these tables are all initializer-legal and must keep working.
+
+; The .shared symbol is the default result only. It stays an operand of the phi
+; and never enters the table, so the table is still built.
+define ptr @shared_only_in_default(i32 %i) {
+; CHECK-LABEL: define ptr @shared_only_in_default(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x ptr], ptr @switch.table.shared_only_in_default, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr, ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ], [ addrspacecast (ptr addrspace(3) @buf0 to ptr), %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ addrspacecast (ptr addrspace(1) @gg0 to ptr), %sw.bb0 ], [ addrspacecast (ptr addrspace(1) @gg1 to ptr), %sw.bb1 ], [ addrspacecast (ptr addrspace(1) @gg2 to ptr), %sw.bb2 ], [ addrspacecast (ptr addrspace(1) @gg3 to ptr), %sw.bb3 ], [ addrspacecast (ptr addrspace(3) @buf0 to ptr), %sw.default ]
+ ret ptr %r
+}
+
+define i32 @int_table(i32 %i) {
+; CHECK-LABEL: define i32 @int_table(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x i8], ptr @switch.table.int_table, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load i8, ptr [[SWITCH_GEP]], align 1
+; CHECK-NEXT: [[SWITCH_EXT:%.*]] = zext i8 [[SWITCH_LOAD]] to i32
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi i32 [ [[SWITCH_EXT]], %[[SWITCH_LOOKUP]] ], [ 0, %[[ENTRY]] ]
+; CHECK-NEXT: ret i32 [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi i32 [ 42, %sw.bb0 ], [ 7, %sw.bb1 ], [ 99, %sw.bb2 ], [ 13, %sw.bb3 ], [ 0, %sw.default ]
+ ret i32 %r
+}
+
+define ptr addrspace(1) @global_table(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(1) @global_table(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x ptr addrspace(1)], ptr @switch.table.global_table, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr addrspace(1), ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr addrspace(1) [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr addrspace(1) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(1) [ @gg0, %sw.bb0 ], [ @gg1, %sw.bb1 ], [ @gg2, %sw.bb2 ], [ @gg3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr addrspace(1) %r
+}
+
+define ptr addrspace(4) @const_table(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(4) @const_table(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x ptr addrspace(4)], ptr @switch.table.const_table, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr addrspace(4), ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr addrspace(4) [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr addrspace(4) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(4) [ @cc0, %sw.bb0 ], [ @cc1, %sw.bb1 ], [ @cc2, %sw.bb2 ], [ @cc3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr addrspace(4) %r
+}
+
+define ptr @generic_global_table(i32 %i) {
+; CHECK-LABEL: define ptr @generic_global_table(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x ptr], ptr @switch.table.generic_global_table, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr, ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ @ge0, %sw.bb0 ], [ @ge1, %sw.bb1 ], [ @ge2, %sw.bb2 ], [ @ge3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr %r
+}
+
+define void @f0() {
+; CHECK-LABEL: define void @f0() {
+; CHECK-NEXT: ret void
+;
+ ret void
+}
+
+define void @f1() {
+; CHECK-LABEL: define void @f1() {
+; CHECK-NEXT: ret void
+;
+ ret void
+}
+
+define void @f2() {
+; CHECK-LABEL: define void @f2() {
+; CHECK-NEXT: ret void
+;
+ ret void
+}
+
+define void @f3() {
+; CHECK-LABEL: define void @f3() {
+; CHECK-NEXT: ret void
+;
+ ret void
+}
+
+define ptr @func_table(i32 %i) {
+; CHECK-LABEL: define ptr @func_table(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[TMP0:%.*]] = icmp ult i32 [[I]], 4
+; CHECK-NEXT: br i1 [[TMP0]], label %[[SWITCH_LOOKUP:.*]], label %[[RETURN:.*]]
+; CHECK: [[SWITCH_LOOKUP]]:
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[I]] to i64
+; CHECK-NEXT: [[SWITCH_GEP:%.*]] = getelementptr inbounds [4 x ptr], ptr @switch.table.func_table, i64 0, i64 [[TMP1]]
+; CHECK-NEXT: [[SWITCH_LOAD:%.*]] = load ptr, ptr [[SWITCH_GEP]], align 8
+; CHECK-NEXT: br label %[[RETURN]]
+; CHECK: [[RETURN]]:
+; CHECK-NEXT: [[R:%.*]] = phi ptr [ [[SWITCH_LOAD]], %[[SWITCH_LOOKUP]] ], [ null, %[[ENTRY]] ]
+; CHECK-NEXT: ret ptr [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ i32 2, label %sw.bb2
+ i32 3, label %sw.bb3
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.bb2:
+ br label %return
+sw.bb3:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr [ @f0, %sw.bb0 ], [ @f1, %sw.bb1 ], [ @f2, %sw.bb2 ], [ @f3, %sw.bb3 ], [ null, %sw.default ]
+ ret ptr %r
+}
+
+; A small switch over .shared symbols can still fold to selects, which do not
+; need a global initializer.
+define ptr addrspace(3) @shared_two_cases(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(3) @shared_two_cases(
+; CHECK-SAME: i32 [[I:%.*]]) {
+; CHECK-NEXT: [[RETURN:.*:]]
+; CHECK-NEXT: [[SWITCH_SELECTCMP:%.*]] = icmp eq i32 [[I]], 1
+; CHECK-NEXT: [[SWITCH_SELECT:%.*]] = select i1 [[SWITCH_SELECTCMP]], ptr addrspace(3) @buf1, ptr addrspace(3) null
+; CHECK-NEXT: [[SWITCH_SELECTCMP1:%.*]] = icmp eq i32 [[I]], 0
+; CHECK-NEXT: [[R:%.*]] = select i1 [[SWITCH_SELECTCMP1]], ptr addrspace(3) @buf0, ptr addrspace(3) [[SWITCH_SELECT]]
+; CHECK-NEXT: ret ptr addrspace(3) [[R]]
+;
+entry:
+ switch i32 %i, label %sw.default [
+ i32 0, label %sw.bb0
+ i32 1, label %sw.bb1
+ ]
+
+sw.bb0:
+ br label %return
+sw.bb1:
+ br label %return
+sw.default:
+ br label %return
+
+return:
+ %r = phi ptr addrspace(3) [ @buf0, %sw.bb0 ], [ @buf1, %sw.bb1 ], [ null, %sw.default ]
+ ret ptr addrspace(3) %r
+}
More information about the llvm-commits
mailing list