From 1e04e45f69ba5d479caef02739d3be59df24cea1 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Mon, 11 May 2026 21:11:48 -0700 Subject: [PATCH 1/5] [SimplifyCFG] Fix illegal-width bitmap from switch lookup table (#8421) SwitchLookupTable built bitmap APInts of width `TableSize * ResultBitWidth`, producing non-standard integer widths (i9, i17, i26, i33, i40, ...) that DXIL validation rejects - DXIL only allows i1/i8/i16/i32/i64. Round the bitmap width up to a legal width, and cap the optimization at 32 bits to avoid silently promoting to i64 (which would set the Int64Ops shader flag and add a 64-bit-integer capability requirement the source shader did not have). Wider tables fall back to the array path, or - for i1 results - preserve the original switch. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- lib/Transforms/Utils/SimplifyCFG.cpp | 21 ++- .../dxil_switch_bitmap_avoids_int64.ll | 79 +++++++++ .../dxil_switch_bitmap_legal_types.ll | 152 ++++++++++++++++++ 3 files changed, 251 insertions(+), 1 deletion(-) create mode 100644 tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll create mode 100644 tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 5b36485692..c8375f82b1 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -3855,7 +3855,16 @@ SwitchLookupTable::SwitchLookupTable( // If the type is integer and the table fits in a register, build a bitmap. if (WouldFitInRegister(DL, TableSize, ValueType)) { IntegerType *IT = cast(ValueType); - APInt TableInt(TableSize * IT->getBitWidth(), 0); + // HLSL Change Begin: Round the bitmap width up to a legal integer width + // (i8/i16/i32) so we never produce non-standard widths like i26 that + // DXIL validation rejects. WouldFitInRegister already caps the width + // at 32 bits to avoid promoting to i64 (which would set the Int64Ops + // shader feature flag the source shader did not necessarily require). + uint64_t RawBitMapWidth = TableSize * IT->getBitWidth(); + uint64_t BitMapWidth = + NextPowerOf2(std::max(UINT64_C(7), RawBitMapWidth - 1)); + APInt TableInt(BitMapWidth, 0); + // HLSL Change End for (uint64_t I = TableSize; I > 0; --I) { TableInt <<= IT->getBitWidth(); // Insert values into the bitmap. Undef values are set to zero. @@ -3950,6 +3959,16 @@ bool SwitchLookupTable::WouldFitInRegister(const DataLayout &DL, // Avoid overflow, fitsInLegalInteger uses unsigned int for the width. if (TableSize >= UINT_MAX/IT->getBitWidth()) return false; + // HLSL Change Begin: Cap bitmap width at 32 bits. A wider bitmap would be + // rounded up to i64 by the constructor, which emits i64 lshr/trunc ops and + // sets the Int64Ops shader feature flag, silently imposing a 64-bit-integer + // capability requirement the source shader did not have. When the bitmap + // would need more than 32 bits, fall back to keeping the original switch + // (the array path is unsuitable here because i1 array globals do not + // survive DXIL lowering). (#8421) + if (TableSize * IT->getBitWidth() > 32) + return false; + // HLSL Change End return DL.fitsInLegalInteger(TableSize * IT->getBitWidth()); } diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll new file mode 100644 index 0000000000..f889dc0f6f --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll @@ -0,0 +1,79 @@ +; RUN: %opt %s -simplifycfg -S | FileCheck %s +; +; Companion test for https://github.com/microsoft/DirectXShaderCompiler/issues/8421 +; +; A switch with 33 boolean cases would naively build an `i33` bitmap (illegal +; in DXIL). A "fix" that simply rounded the bitmap width up to the next legal +; integer width would round i33 -> i64 and emit i64 lshr/trunc instructions. +; Those i64 ops cause DXIL's shader-flag analysis to set the Int64Ops feature +; flag, silently imposing a 64-bit-integer capability requirement the source +; shader did not need. +; +; The chosen fix caps the bitmap optimization at 32 bits: when the bitmap +; would need more than 32 bits, the lookup table is not built and the original +; switch is preserved. That keeps the shader free of incidental i64 operations +; and avoids adding the Int64Ops capability requirement. +; +; Verify that the original switch is preserved and no i33/i64 bitmap is built. + +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +; CHECK-LABEL: @switch_bool_33_cases +; CHECK-NOT: i33 +; CHECK-NOT: lshr i64 +; CHECK-NOT: trunc i64 +; CHECK: switch i32 +; CHECK: ret i1 + +define i1 @switch_bool_33_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 1, label %case_true + i32 2, label %case_true + i32 3, label %case_false + i32 4, label %case_true + i32 5, label %case_false + i32 6, label %case_true + i32 7, label %case_true + i32 8, label %case_false + i32 9, label %case_false + i32 10, label %case_true + i32 11, label %case_true + i32 12, label %case_false + i32 13, label %case_true + i32 14, label %case_false + i32 15, label %case_true + i32 16, label %case_true + i32 17, label %case_false + i32 18, label %case_true + i32 19, label %case_false + i32 20, label %case_false + i32 21, label %case_true + i32 22, label %case_true + i32 23, label %case_false + i32 24, label %case_true + i32 25, label %case_false + i32 26, label %case_true + i32 27, label %case_false + i32 28, label %case_true + i32 29, label %case_true + i32 30, label %case_false + i32 31, label %case_true + i32 32, label %case_false + i32 33, label %case_true + ] + +case_true: + br label %end + +case_false: + br label %end + +default: + br label %end + +end: + %result = phi i1 [ true, %case_true ], [ false, %case_false ], [ false, %default ] + ret i1 %result +} diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll new file mode 100644 index 0000000000..0ceab11b8b --- /dev/null +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll @@ -0,0 +1,152 @@ +; RUN: %opt %s -simplifycfg -S | FileCheck %s +; +; Regression test for https://github.com/microsoft/DirectXShaderCompiler/issues/8421 +; +; SimplifyCFG's switch-to-lookup-table optimization builds a bitmap whose +; width is "TableSize * ValueBitWidth". For a switch with 26 boolean cases +; this used to produce an `i26` constant, which the DXIL validator (correctly) +; rejects because DXIL only allows i1/i8/i16/i32/i64. The fix rounds the +; bitmap width up to the next legal integer width so the resulting bitmap +; uses i8/i16/i32 (and never a non-standard width). + +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +; A switch with boolean results spanning cases 1..26 would previously produce +; an i26 bitmap. With the fix it should use i32 instead. +; +; CHECK-LABEL: @switch_bool_26_cases +; CHECK: switch.lookup: +; CHECK: lshr i32 +; CHECK-NOT: i26 +; CHECK: ret i1 + +define i1 @switch_bool_26_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 1, label %case_true + i32 6, label %case_true + i32 11, label %case_true + i32 16, label %case_true + i32 21, label %case_true + i32 26, label %case_true + ] + +case_true: + br label %end + +default: + br label %end + +end: + %result = phi i1 [ true, %case_true ], [ false, %default ] + ret i1 %result +} + +; A switch with 9 boolean cases would previously produce an i9 bitmap. +; With the fix it should use i16 instead. +; +; CHECK-LABEL: @switch_bool_9_cases +; CHECK: switch.lookup: +; CHECK: lshr i16 +; CHECK-NOT: i9 +; CHECK: ret i1 + +define i1 @switch_bool_9_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 0, label %case_true + i32 1, label %case_true + i32 3, label %case_true + i32 4, label %case_true + i32 5, label %case_true + i32 6, label %case_true + i32 7, label %case_true + i32 8, label %case_true + ] + +case_true: + br label %end + +default: + br label %end + +end: + %result = phi i1 [ true, %case_true ], [ false, %default ] + ret i1 %result +} + +; A switch with 17 boolean cases would previously produce an i17 bitmap. +; With the fix it should use i32 instead. +; +; CHECK-LABEL: @switch_bool_17_cases +; CHECK: switch.lookup: +; CHECK: lshr i32 +; CHECK-NOT: i17 +; CHECK: ret i1 + +define i1 @switch_bool_17_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 0, label %case_true + i32 1, label %case_true + i32 3, label %case_true + i32 4, label %case_true + i32 5, label %case_true + i32 7, label %case_true + i32 8, label %case_true + i32 10, label %case_true + i32 11, label %case_true + i32 12, label %case_true + i32 14, label %case_true + i32 15, label %case_true + i32 16, label %case_true + ] + +case_true: + br label %end + +default: + br label %end + +end: + %result = phi i1 [ true, %case_true ], [ false, %default ] + ret i1 %result +} + +; The same root cause affects non-i1 result types whose bitmap width does not +; round to a legal width. A switch with 5 i8 cases would previously produce an +; `i40` bitmap (5 * 8 bits) - illegal in DXIL. The fix prevents the bitmap +; optimization for any table wider than 32 bits, so for these cases the table +; is built as a global array (or the switch is preserved) instead of an +; illegal-width bitmap. +; +; CHECK-LABEL: @switch_i8_5_cases +; CHECK-NOT: i40 +; CHECK-NOT: lshr i40 +; CHECK-NOT: trunc i40 +; CHECK: ret i8 + +define i8 @switch_i8_5_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 0, label %c0 + i32 1, label %c1 + i32 2, label %c2 + i32 3, label %c3 + i32 4, label %c4 + ] + +c0: br label %end +c1: br label %end +c2: br label %end +c3: br label %end +c4: br label %end +default: br label %end + +end: + ; Non-linear values prevent the LinearMap fast path so the bitmap path is + ; the one that would have been chosen. + %result = phi i8 [73, %c0], [42, %c1], [19, %c2], [88, %c3], [31, %c4], [0, %default] + ret i8 %result +} From 84cd5135ec4cfd965a4f891c6b81e6a20b924378 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Tue, 12 May 2026 14:27:54 -0700 Subject: [PATCH 2/5] Tidy up comments; use i16 as smallest integer size --- lib/Transforms/Utils/SimplifyCFG.cpp | 17 +--- .../dxil_switch_bitmap_avoids_int64.ll | 16 +--- .../dxil_switch_bitmap_legal_types.ll | 87 ++++++++++++------- 3 files changed, 62 insertions(+), 58 deletions(-) diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index c8375f82b1..4bed7f7ad8 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -3855,14 +3855,10 @@ SwitchLookupTable::SwitchLookupTable( // If the type is integer and the table fits in a register, build a bitmap. if (WouldFitInRegister(DL, TableSize, ValueType)) { IntegerType *IT = cast(ValueType); - // HLSL Change Begin: Round the bitmap width up to a legal integer width - // (i8/i16/i32) so we never produce non-standard widths like i26 that - // DXIL validation rejects. WouldFitInRegister already caps the width - // at 32 bits to avoid promoting to i64 (which would set the Int64Ops - // shader feature flag the source shader did not necessarily require). + // HLSL Change Begin: Round bitmap width up to size supported by DXIL (i16 or i32) uint64_t RawBitMapWidth = TableSize * IT->getBitWidth(); uint64_t BitMapWidth = - NextPowerOf2(std::max(UINT64_C(7), RawBitMapWidth - 1)); + NextPowerOf2(std::max(UINT64_C(15), RawBitMapWidth - 1)); APInt TableInt(BitMapWidth, 0); // HLSL Change End for (uint64_t I = TableSize; I > 0; --I) { @@ -3959,13 +3955,8 @@ bool SwitchLookupTable::WouldFitInRegister(const DataLayout &DL, // Avoid overflow, fitsInLegalInteger uses unsigned int for the width. if (TableSize >= UINT_MAX/IT->getBitWidth()) return false; - // HLSL Change Begin: Cap bitmap width at 32 bits. A wider bitmap would be - // rounded up to i64 by the constructor, which emits i64 lshr/trunc ops and - // sets the Int64Ops shader feature flag, silently imposing a 64-bit-integer - // capability requirement the source shader did not have. When the bitmap - // would need more than 32 bits, fall back to keeping the original switch - // (the array path is unsuitable here because i1 array globals do not - // survive DXIL lowering). (#8421) + // HLSL Change Begin: Cap at 32 bits so the bitmap stays in a DXIL-supported + // integer width and never promotes to i64 (which would set Int64Ops). if (TableSize * IT->getBitWidth() > 32) return false; // HLSL Change End diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll index f889dc0f6f..4b94f9f530 100644 --- a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_avoids_int64.ll @@ -2,19 +2,9 @@ ; ; Companion test for https://github.com/microsoft/DirectXShaderCompiler/issues/8421 ; -; A switch with 33 boolean cases would naively build an `i33` bitmap (illegal -; in DXIL). A "fix" that simply rounded the bitmap width up to the next legal -; integer width would round i33 -> i64 and emit i64 lshr/trunc instructions. -; Those i64 ops cause DXIL's shader-flag analysis to set the Int64Ops feature -; flag, silently imposing a 64-bit-integer capability requirement the source -; shader did not need. -; -; The chosen fix caps the bitmap optimization at 32 bits: when the bitmap -; would need more than 32 bits, the lookup table is not built and the original -; switch is preserved. That keeps the shader free of incidental i64 operations -; and avoids adding the Int64Ops capability requirement. -; -; Verify that the original switch is preserved and no i33/i64 bitmap is built. +; A switch with 33 boolean cases would naively build an i33 bitmap. Rounding up +; to i64 would emit i64 ops and silently set the Int64Ops shader flag, so the +; bitmap optimization is capped at 32 bits and the switch is preserved instead. target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" target triple = "dxil-ms-dx" diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll index 0ceab11b8b..382d06e1f2 100644 --- a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll @@ -2,49 +2,47 @@ ; ; Regression test for https://github.com/microsoft/DirectXShaderCompiler/issues/8421 ; -; SimplifyCFG's switch-to-lookup-table optimization builds a bitmap whose -; width is "TableSize * ValueBitWidth". For a switch with 26 boolean cases -; this used to produce an `i26` constant, which the DXIL validator (correctly) -; rejects because DXIL only allows i1/i8/i16/i32/i64. The fix rounds the -; bitmap width up to the next legal integer width so the resulting bitmap -; uses i8/i16/i32 (and never a non-standard width). +; SimplifyCFG's switch-to-lookup-table built bitmaps of width +; "TableSize * ValueBitWidth", producing illegal widths like i9, i17, i26 or +; i40. The fix rounds the bitmap up to i16 or i32. target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" target triple = "dxil-ms-dx" -; A switch with boolean results spanning cases 1..26 would previously produce -; an i26 bitmap. With the fix it should use i32 instead. +; 5 boolean cases with mixed values would naively build an i5 bitmap; rounded +; to i16 by the fix. ; -; CHECK-LABEL: @switch_bool_26_cases +; CHECK-LABEL: @switch_bool_5_cases ; CHECK: switch.lookup: -; CHECK: lshr i32 -; CHECK-NOT: i26 +; CHECK: lshr i16 +; CHECK-NOT: i5 ; CHECK: ret i1 -define i1 @switch_bool_26_cases(i32 %x) { +define i1 @switch_bool_5_cases(i32 %x) { entry: switch i32 %x, label %default [ - i32 1, label %case_true - i32 6, label %case_true - i32 11, label %case_true - i32 16, label %case_true - i32 21, label %case_true - i32 26, label %case_true + i32 0, label %case_t + i32 1, label %case_t + i32 2, label %case_f + i32 3, label %case_t + i32 4, label %case_f ] -case_true: +case_t: + br label %end + +case_f: br label %end default: br label %end end: - %result = phi i1 [ true, %case_true ], [ false, %default ] + %result = phi i1 [ true, %case_t ], [ false, %case_f ], [ false, %default ] ret i1 %result } -; A switch with 9 boolean cases would previously produce an i9 bitmap. -; With the fix it should use i16 instead. +; 9 boolean cases would naively build an i9 bitmap; rounded to i16 by the fix. ; ; CHECK-LABEL: @switch_bool_9_cases ; CHECK: switch.lookup: @@ -76,8 +74,8 @@ end: ret i1 %result } -; A switch with 17 boolean cases would previously produce an i17 bitmap. -; With the fix it should use i32 instead. +; 17 boolean cases would naively build an i17 bitmap; rounded to i32 by the +; fix. ; ; CHECK-LABEL: @switch_bool_17_cases ; CHECK: switch.lookup: @@ -114,17 +112,42 @@ end: ret i1 %result } -; The same root cause affects non-i1 result types whose bitmap width does not -; round to a legal width. A switch with 5 i8 cases would previously produce an -; `i40` bitmap (5 * 8 bits) - illegal in DXIL. The fix prevents the bitmap -; optimization for any table wider than 32 bits, so for these cases the table -; is built as a global array (or the switch is preserved) instead of an -; illegal-width bitmap. +; 26 boolean cases (the original #8421 repro) would naively build an i26 +; bitmap; rounded to i32 by the fix. +; +; CHECK-LABEL: @switch_bool_26_cases +; CHECK: switch.lookup: +; CHECK: lshr i32 +; CHECK-NOT: i26 +; CHECK: ret i1 + +define i1 @switch_bool_26_cases(i32 %x) { +entry: + switch i32 %x, label %default [ + i32 1, label %case_true + i32 6, label %case_true + i32 11, label %case_true + i32 16, label %case_true + i32 21, label %case_true + i32 26, label %case_true + ] + +case_true: + br label %end + +default: + br label %end + +end: + %result = phi i1 [ true, %case_true ], [ false, %default ] + ret i1 %result +} + +; Non-i1 result: 5 i8 cases would naively build an i40 bitmap. The fix makes +; bitmaps wider than 32 bits fall back to an array (or preserve the switch). ; ; CHECK-LABEL: @switch_i8_5_cases ; CHECK-NOT: i40 -; CHECK-NOT: lshr i40 -; CHECK-NOT: trunc i40 ; CHECK: ret i8 define i8 @switch_i8_5_cases(i32 %x) { From a1276d70ec8ce8ce61aab02fc6732c230a2eedd0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 12 May 2026 21:39:29 +0000 Subject: [PATCH 3/5] chore: autopublish 2026-05-12T21:39:28Z --- lib/Transforms/Utils/SimplifyCFG.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/Transforms/Utils/SimplifyCFG.cpp b/lib/Transforms/Utils/SimplifyCFG.cpp index 4bed7f7ad8..aa9596f38a 100644 --- a/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/lib/Transforms/Utils/SimplifyCFG.cpp @@ -3855,7 +3855,8 @@ SwitchLookupTable::SwitchLookupTable( // If the type is integer and the table fits in a register, build a bitmap. if (WouldFitInRegister(DL, TableSize, ValueType)) { IntegerType *IT = cast(ValueType); - // HLSL Change Begin: Round bitmap width up to size supported by DXIL (i16 or i32) + // HLSL Change Begin: Round bitmap width up to size supported by DXIL (i16 + // or i32) uint64_t RawBitMapWidth = TableSize * IT->getBitWidth(); uint64_t BitMapWidth = NextPowerOf2(std::max(UINT64_C(15), RawBitMapWidth - 1)); From 6c8a138b911926b12be1057ae9e3d6819afb8509 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Tue, 12 May 2026 16:02:20 -0700 Subject: [PATCH 4/5] Avoid i8's in tests, explicitly test that bitmaps aren't used when >i32 bits --- .../dxil_switch_bitmap_legal_types.ll | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll index 382d06e1f2..6979fd7c83 100644 --- a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll @@ -4,7 +4,8 @@ ; ; SimplifyCFG's switch-to-lookup-table built bitmaps of width ; "TableSize * ValueBitWidth", producing illegal widths like i9, i17, i26 or -; i40. The fix rounds the bitmap up to i16 or i32. +; i48. The fix rounds the bitmap up to i16 or i32, and skips the lookup table +; entirely if the bitmap would exceed 32 bits. target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" target triple = "dxil-ms-dx" @@ -143,33 +144,32 @@ end: ret i1 %result } -; Non-i1 result: 5 i8 cases would naively build an i40 bitmap. The fix makes -; bitmaps wider than 32 bits fall back to an array (or preserve the switch). +; Non-i1 result: 3 i16 cases would naively build an i48 bitmap. The fix makes +; bitmaps wider than 32 bits skip the lookup table; the original switch is +; preserved. ; -; CHECK-LABEL: @switch_i8_5_cases -; CHECK-NOT: i40 -; CHECK: ret i8 +; CHECK-LABEL: @switch_i16_3_cases +; CHECK: switch i32 +; CHECK-NOT: switch.lookup +; CHECK-NOT: i48 +; CHECK: ret i16 -define i8 @switch_i8_5_cases(i32 %x) { +define i16 @switch_i16_3_cases(i32 %x) { entry: switch i32 %x, label %default [ i32 0, label %c0 i32 1, label %c1 i32 2, label %c2 - i32 3, label %c3 - i32 4, label %c4 ] c0: br label %end c1: br label %end c2: br label %end -c3: br label %end -c4: br label %end default: br label %end end: ; Non-linear values prevent the LinearMap fast path so the bitmap path is ; the one that would have been chosen. - %result = phi i8 [73, %c0], [42, %c1], [19, %c2], [88, %c3], [31, %c4], [0, %default] - ret i8 %result + %result = phi i16 [ 73, %c0 ], [ 42, %c1 ], [ 88, %c2 ], [ 0, %default ] + ret i16 %result } From b9bb75a7d0d0400325b508b7fd6c0448c2b0e459 Mon Sep 17 00:00:00 2001 From: Damyan Pepper Date: Tue, 12 May 2026 16:12:01 -0700 Subject: [PATCH 5/5] Clarify comment --- .../passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll index 6979fd7c83..96d7f26b63 100644 --- a/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll +++ b/tools/clang/test/HLSLFileCheck/passes/llvm/simplifycfg/dxil_switch_bitmap_legal_types.ll @@ -169,7 +169,8 @@ default: br label %end end: ; Non-linear values prevent the LinearMap fast path so the bitmap path is - ; the one that would have been chosen. + ; the one that would have been chosen, but since this would want to use an i48 + ; (which isn't valid in DXIL) the switch is preserved. %result = phi i16 [ 73, %c0 ], [ 42, %c1 ], [ 88, %c2 ], [ 0, %default ] ret i16 %result }