[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