[llvm] [DirectX][SimplifyCFG] Don't narrow to i8 arrays for switch tables (PR #203103)
Farzon Lotfi via llvm-commits
llvm-commits at lists.llvm.org
Wed Jun 10 13:54:13 PDT 2026
https://github.com/farzonl created https://github.com/llvm/llvm-project/pull/203103
fixes #202481
This change adds a TTI to disable the narrowing for targets that don't support it like DirectX.
The `isTypeLegal` TTI was considered, instead of adding a new one, but that was causing significant test failures that needed to be triaged through.
>From 53566b51d20fd7a8f47af4c43641897d3188ad14 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzon at farzon.org>
Date: Mon, 8 Jun 2026 22:11:48 -0400
Subject: [PATCH] [DirectX][SimplifyCFG] Don't narrow to i8 arrays for switch
tables fixes #202481
This change adds a TTI to disable the narrowing for targets that don't
support it like DirectX.
The `isTypeLegal` TTI was considered, instead of adding a new one, but
that was causing significant test failures that needed to be triaged
through.
---
.../llvm/Analysis/TargetTransformInfo.h | 4 ++
.../llvm/Analysis/TargetTransformInfoImpl.h | 2 +
llvm/lib/Analysis/TargetTransformInfo.cpp | 4 ++
.../DirectX/DirectXTargetTransformInfo.cpp | 6 +++
.../DirectX/DirectXTargetTransformInfo.h | 1 +
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 15 ++++---
.../switch-to-lookup-table-no-i8-narrowing.ll | 42 +++++++++++++++++++
7 files changed, 69 insertions(+), 5 deletions(-)
create mode 100644 llvm/test/CodeGen/DirectX/switch-to-lookup-table-no-i8-narrowing.ll
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfo.h b/llvm/include/llvm/Analysis/TargetTransformInfo.h
index 7d58473b81265..7ef643a288a3e 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfo.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfo.h
@@ -1025,6 +1025,10 @@ class TargetTransformInfo {
/// containing this constant value for the target.
LLVM_ABI bool shouldBuildLookupTablesForConstant(Constant *C) const;
+ /// Return true if \p Ty may be used as the element type of a switch lookup
+ /// table on this target.
+ LLVM_ABI bool isLegalLookupTableElementType(Type *Ty) const;
+
/// Return true if lookup tables should be turned into relative lookup tables.
LLVM_ABI bool shouldBuildRelLookupTables() const;
diff --git a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
index 89fd4a1e7628e..b94df409dcb11 100644
--- a/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
+++ b/llvm/include/llvm/Analysis/TargetTransformInfoImpl.h
@@ -475,6 +475,8 @@ class LLVM_ABI TargetTransformInfoImplBase {
return true;
}
+ virtual bool isLegalLookupTableElementType(Type *Ty) const { return true; }
+
virtual bool shouldBuildRelLookupTables() const { return false; }
virtual bool useColdCCForColdCall(Function &F) const { return false; }
diff --git a/llvm/lib/Analysis/TargetTransformInfo.cpp b/llvm/lib/Analysis/TargetTransformInfo.cpp
index 856950ccae595..d8eaff3ca1c73 100644
--- a/llvm/lib/Analysis/TargetTransformInfo.cpp
+++ b/llvm/lib/Analysis/TargetTransformInfo.cpp
@@ -617,6 +617,10 @@ bool TargetTransformInfo::shouldBuildLookupTablesForConstant(
return TTIImpl->shouldBuildLookupTablesForConstant(C);
}
+bool TargetTransformInfo::isLegalLookupTableElementType(Type *Ty) const {
+ return TTIImpl->isLegalLookupTableElementType(Ty);
+}
+
bool TargetTransformInfo::shouldBuildRelLookupTables() const {
return TTIImpl->shouldBuildRelLookupTables();
}
diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
index 9952038aaf7bd..7453bd84dd1fc 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
+++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.cpp
@@ -44,3 +44,9 @@ bool DirectXTTIImpl::isTargetIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
return OpdIdx == -1;
}
}
+
+bool DirectXTTIImpl::isLegalLookupTableElementType(Type *Ty) const {
+ // DXIL does not support i8, so switch lookup tables must not be narrowed to
+ // an i8 element type.
+ return !Ty->isIntegerTy(8);
+}
diff --git a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
index fdbbc18003419..b860324b11295 100644
--- a/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
+++ b/llvm/lib/Target/DirectX/DirectXTargetTransformInfo.h
@@ -38,6 +38,7 @@ class DirectXTTIImpl final : public BasicTTIImplBase<DirectXTTIImpl> {
unsigned ScalarOpdIdx) const override;
bool isTargetIntrinsicWithOverloadTypeAtArg(Intrinsic::ID ID,
int OpdIdx) const override;
+ bool isLegalLookupTableElementType(Type *Ty) const override;
InstructionCost getPartialReductionCost(
unsigned Opcode, Type *InputTypeA, Type *InputTypeB, Type *AccumType,
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 4b21b20beb895..b04b0cdd39d5b 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -6780,7 +6780,8 @@ class SwitchReplacement {
SwitchReplacement(
Module &M, uint64_t TableSize, ConstantInt *Offset,
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
- Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName);
+ Constant *DefaultValue, const DataLayout &DL,
+ const TargetTransformInfo &TTI, const StringRef &FuncName);
/// Build instructions with Builder to retrieve values using Index
/// and replace the switch.
@@ -6850,7 +6851,8 @@ class SwitchReplacement {
SwitchReplacement::SwitchReplacement(
Module &M, uint64_t TableSize, ConstantInt *Offset,
const SmallVectorImpl<std::pair<ConstantInt *, Constant *>> &Values,
- Constant *DefaultValue, const DataLayout &DL, const StringRef &FuncName)
+ Constant *DefaultValue, const DataLayout &DL,
+ const TargetTransformInfo &TTI, const StringRef &FuncName)
: DefaultValue(DefaultValue) {
assert(Values.size() && "Can't build lookup table without values!");
assert(TableSize >= Values.size() && "Can't fit values in table!");
@@ -6980,8 +6982,11 @@ SwitchReplacement::SwitchReplacement(
std::max(8u, unsigned(PowerOf2Ceil(Range.getActiveBits())));
if (NeededBitWidth < IT->getBitWidth()) {
IntegerType *DstTy = IntegerType::get(IT->getContext(), NeededBitWidth);
- for (Constant *&Value : TableContents)
- Value = ConstantFoldCastInstruction(Instruction::Trunc, Value, DstTy);
+ // Only narrow the table element type if the narrower type is legal on
+ // this target.
+ if (TTI.isLegalLookupTableElementType(DstTy))
+ for (Constant *&Value : TableContents)
+ Value = ConstantFoldCastInstruction(Instruction::Trunc, Value, DstTy);
}
}
@@ -7439,7 +7444,7 @@ static bool simplifySwitchLookup(SwitchInst *SI, IRBuilder<> &Builder,
AllHolesArePoison ? PoisonValue::get(ResultType) : DefaultResults[PHI];
StringRef FuncName = Fn->getName();
SwitchReplacement Replacement(*Fn->getParent(), TableSize, TableIndexOffset,
- ResultList, DefaultVal, DL, FuncName);
+ ResultList, DefaultVal, DL, TTI, FuncName);
PhiToReplacementMap.insert({PHI, Replacement});
}
diff --git a/llvm/test/CodeGen/DirectX/switch-to-lookup-table-no-i8-narrowing.ll b/llvm/test/CodeGen/DirectX/switch-to-lookup-table-no-i8-narrowing.ll
new file mode 100644
index 0000000000000..86259cdcb0799
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/switch-to-lookup-table-no-i8-narrowing.ll
@@ -0,0 +1,42 @@
+; RUN: opt -S -passes=simplifycfg -switch-to-lookup=true -keep-loops=false -mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+; The switch result values all fit in i8, so on a typical target SimplifyCFG
+; narrows the lookup table element type from i32 down to i8. DXIL/DXC does not
+; support i8, and the DirectX target transform reports i8 as an illegal type, so
+; SimplifyCFG must keep the original i32 element type instead of downcasting the
+; table to i8.
+
+; CHECK: @switch.table.test = private unnamed_addr constant [4 x i32] [i32 3, i32 1, i32 2, i32 5]
+; CHECK-NOT: @switch.table.test = private unnamed_addr constant [4 x i8]
+
+define i32 @test(i32 %i) {
+; CHECK-LABEL: define i32 @test(
+; CHECK: getelementptr inbounds [4 x i32], ptr @switch.table.test
+; CHECK: load i32, ptr
+entry:
+ switch i32 %i, label %def [
+ i32 0, label %bb0
+ i32 1, label %bb1
+ i32 2, label %bb2
+ i32 3, label %bb3
+ ]
+
+bb0:
+ br label %ret
+
+bb1:
+ br label %ret
+
+bb2:
+ br label %ret
+
+bb3:
+ br label %ret
+
+def:
+ br label %ret
+
+ret:
+ %r = phi i32 [ 3, %bb0 ], [ 1, %bb1 ], [ 2, %bb2 ], [ 5, %bb3 ], [ 0, %def ]
+ ret i32 %r
+}
More information about the llvm-commits
mailing list