[llvm] [NVPTX] Implement shouldBuildLookupTablesForConstant (PR #220088)

Alex MacLean via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 23 14:00:21 PDT 2026


https://github.com/AlexMaclean updated https://github.com/llvm/llvm-project/pull/220088

>From ba0adc874860c1ce6000146076084abf60898d29 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 31 Aug 2026 14:11:31 -0700
Subject: [PATCH 1/3] [NVPTX] Implement shouldBuildLookupTablesForConstant

---
 .../Target/NVPTX/NVPTXTargetTransformInfo.cpp |  26 +
 .../Target/NVPTX/NVPTXTargetTransformInfo.h   |   2 +
 .../SimplifyCFG/NVPTX/lit.local.cfg           |   2 +
 .../NVPTX/switch-to-lookup-table-addrspace.ll | 644 ++++++++++++++++++
 4 files changed, 674 insertions(+)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/NVPTX/lit.local.cfg
 create mode 100644 llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll

diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 47ca32336c8c72..7696eb8da4f2f1 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -9,6 +9,7 @@
 #include "NVPTXTargetTransformInfo.h"
 #include "NVVMProperties.h"
 #include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -672,6 +673,31 @@ void NVPTXTTIImpl::collectKernelLaunchBounds(
     LB.push_back({"maxntidz", MaxNTID[2]});
 }
 
+// A switch lookup table is materialized as an array with an initializer. PTX
+// only allows a variable's initial value to name a symbol in the .global or
+// .const state space; ptxas rejects anything else with "Variable used as
+// initial value not in .global or .const state space".
+bool NVPTXTTIImpl::shouldBuildLookupTablesForConstant(Constant *C) const {
+  SmallVector<Constant *, 8> WorkList = {C};
+  SmallPtrSet<Constant *, 8> Visited = {C};
+  while (!WorkList.empty()) {
+    Constant *Cur = WorkList.pop_back_val();
+    if (const auto *GV = dyn_cast<GlobalValue>(Cur)) {
+      const unsigned AS = GV->getAddressSpace();
+      if (AS != NVPTXAS::ADDRESS_SPACE_GENERIC &&
+          AS != NVPTXAS::ADDRESS_SPACE_GLOBAL &&
+          AS != NVPTXAS::ADDRESS_SPACE_CONST)
+        return false;
+      continue;
+    }
+    for (Value *Op : Cur->operands())
+      if (auto *COp = dyn_cast<Constant>(Op))
+        if (Visited.insert(COp).second)
+          WorkList.push_back(COp);
+  }
+  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 c6313a5a0fb518..608295fdc21d6c 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 00000000000000..0d37b86e1c8e6e
--- /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 00000000000000..13410b3eea0993
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
@@ -0,0 +1,644 @@
+; 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] undef, align 16
+ at buf1 = addrspace(3) global [16 x i8] undef, align 16
+ at buf2 = addrspace(3) global [16 x i8] undef, align 16
+ at buf3 = addrspace(3) global [16 x i8] undef, align 16
+
+ at loc0 = addrspace(5) global i32 undef
+ at loc1 = addrspace(5) global i32 undef
+ at loc2 = addrspace(5) global i32 undef
+ at loc3 = addrspace(5) global i32 undef
+
+ 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] undef, align 16
+; CHECK: @buf1 = addrspace(3) global [16 x i8] undef, align 16
+; CHECK: @buf2 = addrspace(3) global [16 x i8] undef, align 16
+; CHECK: @buf3 = addrspace(3) global [16 x i8] undef, align 16
+; CHECK: @loc0 = addrspace(5) global i32 undef
+; CHECK: @loc1 = addrspace(5) global i32 undef
+; CHECK: @loc2 = addrspace(5) global i32 undef
+; CHECK: @loc3 = addrspace(5) global i32 undef
+; 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
+}
+
+; Known trade-off: SimplifyCFG screens switch-to-select candidates with the same
+; TTI hook, so a small switch over .shared symbols is no longer folded into a
+; select either, even though a select materializes no initializer at all. ARM's
+; ROPI/RWPI override behaves the same way.
+define ptr addrspace(3) @shared_two_cases(i32 %i) {
+; CHECK-LABEL: define ptr addrspace(3) @shared_two_cases(
+; 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:    ]
+; CHECK:       [[SW_BB1]]:
+; 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]] ], [ @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
+  ]
+
+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
+}

>From d54c82ed2ed4af8fc921d3a768f27148d9bcc862 Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Mon, 31 Aug 2026 14:48:00 -0700
Subject: [PATCH 2/3] scracth

---
 .../NVPTX/switch-to-lookup-table-addrspace.ll | 32 +++++++++----------
 1 file changed, 16 insertions(+), 16 deletions(-)

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
index 13410b3eea0993..2052b6895f4960 100644
--- a/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
+++ b/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
@@ -3,15 +3,15 @@
 
 target triple = "nvptx64-nvidia-cuda"
 
- at buf0 = addrspace(3) global [16 x i8] undef, align 16
- at buf1 = addrspace(3) global [16 x i8] undef, align 16
- at buf2 = addrspace(3) global [16 x i8] undef, align 16
- at buf3 = addrspace(3) global [16 x i8] undef, align 16
+ 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 undef
- at loc1 = addrspace(5) global i32 undef
- at loc2 = addrspace(5) global i32 undef
- at loc3 = addrspace(5) global i32 undef
+ 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
 
 @gg0 = addrspace(1) global i32 0
 @gg1 = addrspace(1) global i32 0
@@ -32,14 +32,14 @@ target triple = "nvptx64-nvidia-cuda"
 
 ; The reported case: a phi of .shared globals.
 ;.
-; CHECK: @buf0 = addrspace(3) global [16 x i8] undef, align 16
-; CHECK: @buf1 = addrspace(3) global [16 x i8] undef, align 16
-; CHECK: @buf2 = addrspace(3) global [16 x i8] undef, align 16
-; CHECK: @buf3 = addrspace(3) global [16 x i8] undef, align 16
-; CHECK: @loc0 = addrspace(5) global i32 undef
-; CHECK: @loc1 = addrspace(5) global i32 undef
-; CHECK: @loc2 = addrspace(5) global i32 undef
-; CHECK: @loc3 = addrspace(5) global i32 undef
+; 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

>From bb6789ea8660da937234ca4d8d0a009c28499ffa Mon Sep 17 00:00:00 2001
From: Alex Maclean <amaclean at nvidia.com>
Date: Wed, 23 Sep 2026 13:57:18 -0700
Subject: [PATCH 3/3] [NVPTX] Simplify lookup table constant validation

---
 .../Target/NVPTX/NVPTXTargetTransformInfo.cpp | 28 +++++--------------
 .../NVPTX/switch-to-lookup-table-addrspace.ll | 22 +++++----------
 2 files changed, 14 insertions(+), 36 deletions(-)

diff --git a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
index 7696eb8da4f2f1..49d63c726d8010 100644
--- a/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/NVPTX/NVPTXTargetTransformInfo.cpp
@@ -9,7 +9,6 @@
 #include "NVPTXTargetTransformInfo.h"
 #include "NVVMProperties.h"
 #include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallPtrSet.h"
 #include "llvm/Analysis/LoopInfo.h"
 #include "llvm/Analysis/TargetTransformInfo.h"
 #include "llvm/Analysis/ValueTracking.h"
@@ -673,27 +672,14 @@ void NVPTXTTIImpl::collectKernelLaunchBounds(
     LB.push_back({"maxntidz", MaxNTID[2]});
 }
 
-// A switch lookup table is materialized as an array with an initializer. PTX
-// only allows a variable's initial value to name a symbol in the .global or
-// .const state space; ptxas rejects anything else with "Variable used as
-// initial value not in .global or .const state space".
+// Global addresses can only be materialized if they are in generic global or
+// constant space.
 bool NVPTXTTIImpl::shouldBuildLookupTablesForConstant(Constant *C) const {
-  SmallVector<Constant *, 8> WorkList = {C};
-  SmallPtrSet<Constant *, 8> Visited = {C};
-  while (!WorkList.empty()) {
-    Constant *Cur = WorkList.pop_back_val();
-    if (const auto *GV = dyn_cast<GlobalValue>(Cur)) {
-      const unsigned AS = GV->getAddressSpace();
-      if (AS != NVPTXAS::ADDRESS_SPACE_GENERIC &&
-          AS != NVPTXAS::ADDRESS_SPACE_GLOBAL &&
-          AS != NVPTXAS::ADDRESS_SPACE_CONST)
-        return false;
-      continue;
-    }
-    for (Value *Op : Cur->operands())
-      if (auto *COp = dyn_cast<Constant>(Op))
-        if (Visited.insert(COp).second)
-          WorkList.push_back(COp);
+  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;
 }
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
index 2052b6895f4960..5127f9fdef29dd 100644
--- a/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
+++ b/llvm/test/Transforms/SimplifyCFG/NVPTX/switch-to-lookup-table-addrspace.ll
@@ -605,24 +605,16 @@ return:
   ret ptr %r
 }
 
-; Known trade-off: SimplifyCFG screens switch-to-select candidates with the same
-; TTI hook, so a small switch over .shared symbols is no longer folded into a
-; select either, even though a select materializes no initializer at all. ARM's
-; ROPI/RWPI override behaves the same way.
+; 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:  [[ENTRY:.*]]:
-; CHECK-NEXT:    switch i32 [[I]], label %[[SW_DEFAULT:.*]] [
-; CHECK-NEXT:      i32 0, label %[[RETURN:.*]]
-; CHECK-NEXT:      i32 1, label %[[SW_BB1:.*]]
-; CHECK-NEXT:    ]
-; CHECK:       [[SW_BB1]]:
-; 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]] ], [ @buf0, %[[ENTRY]] ]
+; 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:



More information about the llvm-commits mailing list