[hlsl] Add `unpack*` support.

This Cl adds support to the HLSL IR backend for the various `unpack`
methods.

Bug: 42251045
Change-Id: Ic06ad065d5fc8c1e42a164f08a38ecdb43ad86fc
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/198757
Reviewed-by: James Price <jrprice@google.com>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/hlsl/builtin_fn.cc b/src/tint/lang/hlsl/builtin_fn.cc
index 7db232d..de112ff 100644
--- a/src/tint/lang/hlsl/builtin_fn.cc
+++ b/src/tint/lang/hlsl/builtin_fn.cc
@@ -56,6 +56,10 @@
             return "mul";
         case BuiltinFn::kSign:
             return "sign";
+        case BuiltinFn::kUnpackS8S32:
+            return "unpack_s8s32";
+        case BuiltinFn::kUnpackU8U32:
+            return "unpack_u8u32";
         case BuiltinFn::kLoad:
             return "Load";
         case BuiltinFn::kLoad2:
diff --git a/src/tint/lang/hlsl/builtin_fn.h b/src/tint/lang/hlsl/builtin_fn.h
index b443159..274fb89 100644
--- a/src/tint/lang/hlsl/builtin_fn.h
+++ b/src/tint/lang/hlsl/builtin_fn.h
@@ -54,6 +54,8 @@
     kF16Tof32,
     kMul,
     kSign,
+    kUnpackS8S32,
+    kUnpackU8U32,
     kLoad,
     kLoad2,
     kLoad3,
diff --git a/src/tint/lang/hlsl/hlsl.def b/src/tint/lang/hlsl/hlsl.def
index daa4806..3f71d36 100644
--- a/src/tint/lang/hlsl/hlsl.def
+++ b/src/tint/lang/hlsl/hlsl.def
@@ -64,6 +64,8 @@
 @display("mat{N}x{M}<{T}>") type mat<N: num, M: num, T>
 
 type byte_address_buffer<A: access>
+type int8_t4_packed
+type uint8_t4_packed
 
 type sampler
 type sampler_comparison
@@ -155,6 +157,9 @@
 fn sign[T: fi32_f16](T) -> i32
 fn sign[N: num, T: fi32_f16](vec<N, T>) -> vec<N, i32>
 
+fn unpack_s8s32(int8_t4_packed) -> vec4<i32>
+fn unpack_u8u32(uint8_t4_packed) -> vec4<u32>
+
 @member_function fn Load(byte_address_buffer<readable>, offset: u32) -> u32
 @member_function fn Load2(byte_address_buffer<readable>, offset: u32) -> vec2<u32>
 @member_function fn Load3(byte_address_buffer<readable>, offset: u32) -> vec3<u32>
diff --git a/src/tint/lang/hlsl/intrinsic/data.cc b/src/tint/lang/hlsl/intrinsic/data.cc
index 67206ae..61a763c 100644
--- a/src/tint/lang/hlsl/intrinsic/data.cc
+++ b/src/tint/lang/hlsl/intrinsic/data.cc
@@ -481,6 +481,34 @@
 };
 
 
+/// TypeMatcher for 'type int8_t4_packed'
+constexpr TypeMatcher kInt8T4PackedMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchInt8T4Packed(state, ty)) {
+      return nullptr;
+    }
+    return BuildInt8T4Packed(state, ty);
+  },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+    out << style::Type("int8_t4_packed");
+  }
+};
+
+
+/// TypeMatcher for 'type uint8_t4_packed'
+constexpr TypeMatcher kUint8T4PackedMatcher {
+/* match */ [](MatchState& state, const Type* ty) -> const Type* {
+    if (!MatchUint8T4Packed(state, ty)) {
+      return nullptr;
+    }
+    return BuildUint8T4Packed(state, ty);
+  },
+/* print */ []([[maybe_unused]] MatchState* state, StyledText& out) {
+    out << style::Type("uint8_t4_packed");
+  }
+};
+
+
 /// TypeMatcher for 'type sampler'
 constexpr TypeMatcher kSamplerMatcher {
 /* match */ [](MatchState& state, const Type* ty) -> const Type* {
@@ -1077,30 +1105,32 @@
   /* [21] */ kMat4X4Matcher,
   /* [22] */ kMatMatcher,
   /* [23] */ kByteAddressBufferMatcher,
-  /* [24] */ kSamplerMatcher,
-  /* [25] */ kSamplerComparisonMatcher,
-  /* [26] */ kTexture1DMatcher,
-  /* [27] */ kTexture2DMatcher,
-  /* [28] */ kTexture2DArrayMatcher,
-  /* [29] */ kTexture3DMatcher,
-  /* [30] */ kTextureCubeMatcher,
-  /* [31] */ kTextureCubeArrayMatcher,
-  /* [32] */ kTextureDepth2DMatcher,
-  /* [33] */ kTextureDepth2DArrayMatcher,
-  /* [34] */ kTextureDepthCubeMatcher,
-  /* [35] */ kTextureDepthCubeArrayMatcher,
-  /* [36] */ kTextureDepthMultisampled2DMatcher,
-  /* [37] */ kTextureMultisampled2DMatcher,
-  /* [38] */ kTextureStorage1DMatcher,
-  /* [39] */ kTextureStorage2DMatcher,
-  /* [40] */ kTextureStorage2DArrayMatcher,
-  /* [41] */ kTextureStorage3DMatcher,
-  /* [42] */ kIu32Matcher,
-  /* [43] */ kFiu32Matcher,
-  /* [44] */ kF32U32Matcher,
-  /* [45] */ kF32I32Matcher,
-  /* [46] */ kF32F16Matcher,
-  /* [47] */ kFi32F16Matcher,
+  /* [24] */ kInt8T4PackedMatcher,
+  /* [25] */ kUint8T4PackedMatcher,
+  /* [26] */ kSamplerMatcher,
+  /* [27] */ kSamplerComparisonMatcher,
+  /* [28] */ kTexture1DMatcher,
+  /* [29] */ kTexture2DMatcher,
+  /* [30] */ kTexture2DArrayMatcher,
+  /* [31] */ kTexture3DMatcher,
+  /* [32] */ kTextureCubeMatcher,
+  /* [33] */ kTextureCubeArrayMatcher,
+  /* [34] */ kTextureDepth2DMatcher,
+  /* [35] */ kTextureDepth2DArrayMatcher,
+  /* [36] */ kTextureDepthCubeMatcher,
+  /* [37] */ kTextureDepthCubeArrayMatcher,
+  /* [38] */ kTextureDepthMultisampled2DMatcher,
+  /* [39] */ kTextureMultisampled2DMatcher,
+  /* [40] */ kTextureStorage1DMatcher,
+  /* [41] */ kTextureStorage2DMatcher,
+  /* [42] */ kTextureStorage2DArrayMatcher,
+  /* [43] */ kTextureStorage3DMatcher,
+  /* [44] */ kIu32Matcher,
+  /* [45] */ kFiu32Matcher,
+  /* [46] */ kF32U32Matcher,
+  /* [47] */ kF32I32Matcher,
+  /* [48] */ kF32F16Matcher,
+  /* [49] */ kFi32F16Matcher,
 };
 
 /// The template numbers, and number matchers
@@ -1166,78 +1196,78 @@
   /* [44] */ MatcherIndex(12),
   /* [45] */ MatcherIndex(0),
   /* [46] */ MatcherIndex(1),
-  /* [47] */ MatcherIndex(38),
+  /* [47] */ MatcherIndex(40),
   /* [48] */ MatcherIndex(0),
   /* [49] */ MatcherIndex(1),
-  /* [50] */ MatcherIndex(39),
+  /* [50] */ MatcherIndex(41),
   /* [51] */ MatcherIndex(0),
   /* [52] */ MatcherIndex(1),
-  /* [53] */ MatcherIndex(40),
+  /* [53] */ MatcherIndex(42),
   /* [54] */ MatcherIndex(0),
   /* [55] */ MatcherIndex(1),
-  /* [56] */ MatcherIndex(41),
+  /* [56] */ MatcherIndex(43),
   /* [57] */ MatcherIndex(0),
   /* [58] */ MatcherIndex(1),
-  /* [59] */ MatcherIndex(38),
+  /* [59] */ MatcherIndex(40),
   /* [60] */ MatcherIndex(8),
   /* [61] */ MatcherIndex(7),
-  /* [62] */ MatcherIndex(39),
+  /* [62] */ MatcherIndex(41),
   /* [63] */ MatcherIndex(8),
   /* [64] */ MatcherIndex(7),
-  /* [65] */ MatcherIndex(40),
+  /* [65] */ MatcherIndex(42),
   /* [66] */ MatcherIndex(8),
   /* [67] */ MatcherIndex(7),
-  /* [68] */ MatcherIndex(41),
+  /* [68] */ MatcherIndex(43),
   /* [69] */ MatcherIndex(8),
   /* [70] */ MatcherIndex(7),
-  /* [71] */ MatcherIndex(38),
+  /* [71] */ MatcherIndex(40),
   /* [72] */ MatcherIndex(10),
   /* [73] */ MatcherIndex(7),
-  /* [74] */ MatcherIndex(39),
+  /* [74] */ MatcherIndex(41),
   /* [75] */ MatcherIndex(10),
   /* [76] */ MatcherIndex(7),
-  /* [77] */ MatcherIndex(40),
+  /* [77] */ MatcherIndex(42),
   /* [78] */ MatcherIndex(10),
   /* [79] */ MatcherIndex(7),
-  /* [80] */ MatcherIndex(41),
+  /* [80] */ MatcherIndex(43),
   /* [81] */ MatcherIndex(10),
   /* [82] */ MatcherIndex(7),
-  /* [83] */ MatcherIndex(38),
+  /* [83] */ MatcherIndex(40),
   /* [84] */ MatcherIndex(9),
   /* [85] */ MatcherIndex(7),
-  /* [86] */ MatcherIndex(39),
+  /* [86] */ MatcherIndex(41),
   /* [87] */ MatcherIndex(9),
   /* [88] */ MatcherIndex(7),
-  /* [89] */ MatcherIndex(40),
+  /* [89] */ MatcherIndex(42),
   /* [90] */ MatcherIndex(9),
   /* [91] */ MatcherIndex(7),
-  /* [92] */ MatcherIndex(41),
+  /* [92] */ MatcherIndex(43),
   /* [93] */ MatcherIndex(9),
   /* [94] */ MatcherIndex(7),
-  /* [95] */ MatcherIndex(23),
-  /* [96] */ MatcherIndex(6),
+  /* [95] */ MatcherIndex(11),
+  /* [96] */ MatcherIndex(4),
   /* [97] */ MatcherIndex(11),
-  /* [98] */ MatcherIndex(0),
-  /* [99] */ MatcherIndex(26),
-  /* [100] */ MatcherIndex(0),
-  /* [101] */ MatcherIndex(9),
-  /* [102] */ MatcherIndex(4),
-  /* [103] */ MatcherIndex(27),
+  /* [98] */ MatcherIndex(5),
+  /* [99] */ MatcherIndex(23),
+  /* [100] */ MatcherIndex(6),
+  /* [101] */ MatcherIndex(11),
+  /* [102] */ MatcherIndex(0),
+  /* [103] */ MatcherIndex(28),
   /* [104] */ MatcherIndex(0),
-  /* [105] */ MatcherIndex(10),
+  /* [105] */ MatcherIndex(9),
   /* [106] */ MatcherIndex(4),
-  /* [107] */ MatcherIndex(28),
+  /* [107] */ MatcherIndex(29),
   /* [108] */ MatcherIndex(0),
-  /* [109] */ MatcherIndex(11),
+  /* [109] */ MatcherIndex(10),
   /* [110] */ MatcherIndex(4),
-  /* [111] */ MatcherIndex(37),
+  /* [111] */ MatcherIndex(30),
   /* [112] */ MatcherIndex(0),
-  /* [113] */ MatcherIndex(29),
+  /* [113] */ MatcherIndex(39),
   /* [114] */ MatcherIndex(0),
-  /* [115] */ MatcherIndex(11),
-  /* [116] */ MatcherIndex(6),
+  /* [115] */ MatcherIndex(31),
+  /* [116] */ MatcherIndex(0),
   /* [117] */ MatcherIndex(11),
-  /* [118] */ MatcherIndex(5),
+  /* [118] */ MatcherIndex(6),
   /* [119] */ MatcherIndex(9),
   /* [120] */ MatcherIndex(5),
   /* [121] */ MatcherIndex(10),
@@ -1248,25 +1278,27 @@
   /* [126] */ MatcherIndex(7),
   /* [127] */ MatcherIndex(23),
   /* [128] */ MatcherIndex(0),
-  /* [129] */ MatcherIndex(30),
+  /* [129] */ MatcherIndex(32),
   /* [130] */ MatcherIndex(0),
-  /* [131] */ MatcherIndex(31),
+  /* [131] */ MatcherIndex(33),
   /* [132] */ MatcherIndex(0),
   /* [133] */ MatcherIndex(9),
   /* [134] */ MatcherIndex(0),
   /* [135] */ MatcherIndex(10),
   /* [136] */ MatcherIndex(0),
-  /* [137] */ MatcherIndex(44),
-  /* [138] */ MatcherIndex(45),
-  /* [139] */ MatcherIndex(42),
-  /* [140] */ MatcherIndex(46),
-  /* [141] */ MatcherIndex(47),
-  /* [142] */ MatcherIndex(43),
-  /* [143] */ MatcherIndex(32),
-  /* [144] */ MatcherIndex(33),
-  /* [145] */ MatcherIndex(36),
-  /* [146] */ MatcherIndex(34),
-  /* [147] */ MatcherIndex(35),
+  /* [137] */ MatcherIndex(46),
+  /* [138] */ MatcherIndex(47),
+  /* [139] */ MatcherIndex(44),
+  /* [140] */ MatcherIndex(48),
+  /* [141] */ MatcherIndex(49),
+  /* [142] */ MatcherIndex(24),
+  /* [143] */ MatcherIndex(25),
+  /* [144] */ MatcherIndex(45),
+  /* [145] */ MatcherIndex(34),
+  /* [146] */ MatcherIndex(35),
+  /* [147] */ MatcherIndex(38),
+  /* [148] */ MatcherIndex(36),
+  /* [149] */ MatcherIndex(37),
 };
 
 static_assert(MatcherIndicesIndex::CanIndex(kMatcherIndices),
@@ -1276,7 +1308,7 @@
   {
     /* [0] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(107),
+    /* matcher_indices */ MatcherIndicesIndex(111),
   },
   {
     /* [1] */
@@ -1306,7 +1338,7 @@
   {
     /* [6] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(113),
+    /* matcher_indices */ MatcherIndicesIndex(115),
   },
   {
     /* [7] */
@@ -1366,7 +1398,7 @@
   {
     /* [18] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(144),
+    /* matcher_indices */ MatcherIndicesIndex(146),
   },
   {
     /* [19] */
@@ -1396,7 +1428,7 @@
   {
     /* [24] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(147),
+    /* matcher_indices */ MatcherIndicesIndex(149),
   },
   {
     /* [25] */
@@ -1426,7 +1458,7 @@
   {
     /* [30] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(103),
+    /* matcher_indices */ MatcherIndicesIndex(107),
   },
   {
     /* [31] */
@@ -1476,7 +1508,7 @@
   {
     /* [40] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(143),
+    /* matcher_indices */ MatcherIndicesIndex(145),
   },
   {
     /* [41] */
@@ -1501,7 +1533,7 @@
   {
     /* [45] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(146),
+    /* matcher_indices */ MatcherIndicesIndex(148),
   },
   {
     /* [46] */
@@ -1526,7 +1558,7 @@
   {
     /* [50] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(99),
+    /* matcher_indices */ MatcherIndicesIndex(103),
   },
   {
     /* [51] */
@@ -1546,7 +1578,7 @@
   {
     /* [54] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(107),
+    /* matcher_indices */ MatcherIndicesIndex(111),
   },
   {
     /* [55] */
@@ -1586,7 +1618,7 @@
   {
     /* [62] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(113),
+    /* matcher_indices */ MatcherIndicesIndex(115),
   },
   {
     /* [63] */
@@ -1646,7 +1678,7 @@
   {
     /* [74] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(111),
+    /* matcher_indices */ MatcherIndicesIndex(113),
   },
   {
     /* [75] */
@@ -1666,7 +1698,7 @@
   {
     /* [78] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(144),
+    /* matcher_indices */ MatcherIndicesIndex(146),
   },
   {
     /* [79] */
@@ -1686,7 +1718,7 @@
   {
     /* [82] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(147),
+    /* matcher_indices */ MatcherIndicesIndex(149),
   },
   {
     /* [83] */
@@ -1706,7 +1738,7 @@
   {
     /* [86] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(145),
+    /* matcher_indices */ MatcherIndicesIndex(147),
   },
   {
     /* [87] */
@@ -1726,12 +1758,12 @@
   {
     /* [90] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(111),
+    /* matcher_indices */ MatcherIndicesIndex(113),
   },
   {
     /* [91] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(101),
+    /* matcher_indices */ MatcherIndicesIndex(105),
   },
   {
     /* [92] */
@@ -1741,12 +1773,12 @@
   {
     /* [93] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(145),
+    /* matcher_indices */ MatcherIndicesIndex(147),
   },
   {
     /* [94] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(101),
+    /* matcher_indices */ MatcherIndicesIndex(105),
   },
   {
     /* [95] */
@@ -1811,12 +1843,12 @@
   {
     /* [107] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(117),
+    /* matcher_indices */ MatcherIndicesIndex(97),
   },
   {
     /* [108] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(103),
+    /* matcher_indices */ MatcherIndicesIndex(107),
   },
   {
     /* [109] */
@@ -1861,7 +1893,7 @@
   {
     /* [117] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(143),
+    /* matcher_indices */ MatcherIndicesIndex(145),
   },
   {
     /* [118] */
@@ -1876,7 +1908,7 @@
   {
     /* [120] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(146),
+    /* matcher_indices */ MatcherIndicesIndex(148),
   },
   {
     /* [121] */
@@ -1901,7 +1933,7 @@
   {
     /* [125] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(115),
+    /* matcher_indices */ MatcherIndicesIndex(117),
   },
   {
     /* [126] */
@@ -1916,7 +1948,7 @@
   {
     /* [128] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(115),
+    /* matcher_indices */ MatcherIndicesIndex(117),
   },
   {
     /* [129] */
@@ -1931,7 +1963,7 @@
   {
     /* [131] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(115),
+    /* matcher_indices */ MatcherIndicesIndex(117),
   },
   {
     /* [132] */
@@ -1946,7 +1978,7 @@
   {
     /* [134] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(115),
+    /* matcher_indices */ MatcherIndicesIndex(117),
   },
   {
     /* [135] */
@@ -1961,7 +1993,7 @@
   {
     /* [137] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [138] */
@@ -1976,7 +2008,7 @@
   {
     /* [140] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [141] */
@@ -1991,7 +2023,7 @@
   {
     /* [143] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [144] */
@@ -2006,7 +2038,7 @@
   {
     /* [146] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [147] */
@@ -2021,7 +2053,7 @@
   {
     /* [149] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(117),
+    /* matcher_indices */ MatcherIndicesIndex(97),
   },
   {
     /* [150] */
@@ -2036,7 +2068,7 @@
   {
     /* [152] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(117),
+    /* matcher_indices */ MatcherIndicesIndex(97),
   },
   {
     /* [153] */
@@ -2051,7 +2083,7 @@
   {
     /* [155] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(117),
+    /* matcher_indices */ MatcherIndicesIndex(97),
   },
   {
     /* [156] */
@@ -2066,7 +2098,7 @@
   {
     /* [158] */
     /* usage */ core::ParameterUsage::kValue,
-    /* matcher_indices */ MatcherIndicesIndex(117),
+    /* matcher_indices */ MatcherIndicesIndex(97),
   },
   {
     /* [159] */
@@ -2101,7 +2133,7 @@
   {
     /* [165] */
     /* usage */ core::ParameterUsage::kNone,
-    /* matcher_indices */ MatcherIndicesIndex(95),
+    /* matcher_indices */ MatcherIndicesIndex(99),
   },
   {
     /* [166] */
@@ -2111,62 +2143,62 @@
   {
     /* [167] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(99),
+    /* matcher_indices */ MatcherIndicesIndex(103),
   },
   {
     /* [168] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(101),
+    /* matcher_indices */ MatcherIndicesIndex(105),
   },
   {
     /* [169] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(103),
+    /* matcher_indices */ MatcherIndicesIndex(107),
   },
   {
     /* [170] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(105),
+    /* matcher_indices */ MatcherIndicesIndex(109),
   },
   {
     /* [171] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(107),
+    /* matcher_indices */ MatcherIndicesIndex(111),
   },
   {
     /* [172] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [173] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(113),
+    /* matcher_indices */ MatcherIndicesIndex(115),
   },
   {
     /* [174] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [175] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(143),
+    /* matcher_indices */ MatcherIndicesIndex(145),
   },
   {
     /* [176] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(105),
+    /* matcher_indices */ MatcherIndicesIndex(109),
   },
   {
     /* [177] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(144),
+    /* matcher_indices */ MatcherIndicesIndex(146),
   },
   {
     /* [178] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [179] */
@@ -2176,7 +2208,7 @@
   {
     /* [180] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(101),
+    /* matcher_indices */ MatcherIndicesIndex(105),
   },
   {
     /* [181] */
@@ -2186,7 +2218,7 @@
   {
     /* [182] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(105),
+    /* matcher_indices */ MatcherIndicesIndex(109),
   },
   {
     /* [183] */
@@ -2196,7 +2228,7 @@
   {
     /* [184] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [185] */
@@ -2206,7 +2238,7 @@
   {
     /* [186] */
     /* usage */ core::ParameterUsage::kLocation,
-    /* matcher_indices */ MatcherIndicesIndex(109),
+    /* matcher_indices */ MatcherIndicesIndex(95),
   },
   {
     /* [187] */
@@ -2221,7 +2253,7 @@
   {
     /* [189] */
     /* usage */ core::ParameterUsage::kTexture,
-    /* matcher_indices */ MatcherIndicesIndex(99),
+    /* matcher_indices */ MatcherIndicesIndex(103),
   },
   {
     /* [190] */
@@ -2268,6 +2300,16 @@
     /* usage */ core::ParameterUsage::kNone,
     /* matcher_indices */ MatcherIndicesIndex(44),
   },
+  {
+    /* [199] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* matcher_indices */ MatcherIndicesIndex(142),
+  },
+  {
+    /* [200] */
+    /* usage */ core::ParameterUsage::kNone,
+    /* matcher_indices */ MatcherIndicesIndex(143),
+  },
 };
 
 static_assert(ParameterIndex::CanIndex(kParameters),
@@ -2409,7 +2451,7 @@
   {
     /* [22] */
     /* name */ "T",
-    /* matcher_indices */ MatcherIndicesIndex(142),
+    /* matcher_indices */ MatcherIndicesIndex(144),
     /* kind */ TemplateInfo::Kind::kType,
   },
   {
@@ -2740,7 +2782,7 @@
     /* num_templates   */ 1,
     /* templates */ TemplateIndex(22),
     /* parameters */ ParameterIndex(167),
-    /* return_matcher_indices */ MatcherIndicesIndex(97),
+    /* return_matcher_indices */ MatcherIndicesIndex(101),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2751,7 +2793,7 @@
     /* num_templates   */ 1,
     /* templates */ TemplateIndex(22),
     /* parameters */ ParameterIndex(169),
-    /* return_matcher_indices */ MatcherIndicesIndex(97),
+    /* return_matcher_indices */ MatcherIndicesIndex(101),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2762,7 +2804,7 @@
     /* num_templates   */ 1,
     /* templates */ TemplateIndex(22),
     /* parameters */ ParameterIndex(171),
-    /* return_matcher_indices */ MatcherIndicesIndex(97),
+    /* return_matcher_indices */ MatcherIndicesIndex(101),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2773,7 +2815,7 @@
     /* num_templates   */ 1,
     /* templates */ TemplateIndex(22),
     /* parameters */ ParameterIndex(90),
-    /* return_matcher_indices */ MatcherIndicesIndex(97),
+    /* return_matcher_indices */ MatcherIndicesIndex(101),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2784,7 +2826,7 @@
     /* num_templates   */ 1,
     /* templates */ TemplateIndex(22),
     /* parameters */ ParameterIndex(173),
-    /* return_matcher_indices */ MatcherIndicesIndex(97),
+    /* return_matcher_indices */ MatcherIndicesIndex(101),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2795,7 +2837,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(175),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2806,7 +2848,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(177),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2817,7 +2859,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(93),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2828,7 +2870,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(14),
     /* parameters */ ParameterIndex(179),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2839,7 +2881,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(14),
     /* parameters */ ParameterIndex(181),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2850,7 +2892,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(14),
     /* parameters */ ParameterIndex(183),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2861,7 +2903,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(14),
     /* parameters */ ParameterIndex(185),
-    /* return_matcher_indices */ MatcherIndicesIndex(115),
+    /* return_matcher_indices */ MatcherIndicesIndex(117),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2872,7 +2914,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(16),
     /* parameters */ ParameterIndex(179),
-    /* return_matcher_indices */ MatcherIndicesIndex(117),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2883,7 +2925,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(16),
     /* parameters */ ParameterIndex(181),
-    /* return_matcher_indices */ MatcherIndicesIndex(117),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2894,7 +2936,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(16),
     /* parameters */ ParameterIndex(183),
-    /* return_matcher_indices */ MatcherIndicesIndex(117),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2905,7 +2947,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(16),
     /* parameters */ ParameterIndex(185),
-    /* return_matcher_indices */ MatcherIndicesIndex(117),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2916,7 +2958,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(18),
     /* parameters */ ParameterIndex(179),
-    /* return_matcher_indices */ MatcherIndicesIndex(109),
+    /* return_matcher_indices */ MatcherIndicesIndex(95),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2927,7 +2969,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(18),
     /* parameters */ ParameterIndex(181),
-    /* return_matcher_indices */ MatcherIndicesIndex(109),
+    /* return_matcher_indices */ MatcherIndicesIndex(95),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2938,7 +2980,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(18),
     /* parameters */ ParameterIndex(183),
-    /* return_matcher_indices */ MatcherIndicesIndex(109),
+    /* return_matcher_indices */ MatcherIndicesIndex(95),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -2949,7 +2991,7 @@
     /* num_templates   */ 2,
     /* templates */ TemplateIndex(18),
     /* parameters */ ParameterIndex(185),
-    /* return_matcher_indices */ MatcherIndicesIndex(109),
+    /* return_matcher_indices */ MatcherIndicesIndex(95),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3251,24 +3293,24 @@
   },
   {
     /* [75] */
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
-    /* num_parameters */ 2,
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 1,
     /* num_explicit_templates */ 0,
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
-    /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(119),
+    /* parameters */ ParameterIndex(199),
+    /* return_matcher_indices */ MatcherIndicesIndex(95),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
     /* [76] */
-    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
-    /* num_parameters */ 2,
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline),
+    /* num_parameters */ 1,
     /* num_explicit_templates */ 0,
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
-    /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(121),
+    /* parameters */ ParameterIndex(200),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3279,7 +3321,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(117),
+    /* return_matcher_indices */ MatcherIndicesIndex(119),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3290,7 +3332,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(19),
+    /* return_matcher_indices */ MatcherIndicesIndex(121),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3301,7 +3343,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(84),
+    /* return_matcher_indices */ MatcherIndicesIndex(97),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3312,7 +3354,7 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(72),
+    /* return_matcher_indices */ MatcherIndicesIndex(19),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
@@ -3323,12 +3365,34 @@
     /* num_templates   */ 0,
     /* templates */ TemplateIndex(/* invalid */),
     /* parameters */ ParameterIndex(165),
-    /* return_matcher_indices */ MatcherIndicesIndex(123),
+    /* return_matcher_indices */ MatcherIndicesIndex(84),
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
     /* [82] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
+    /* num_parameters */ 2,
+    /* num_explicit_templates */ 0,
+    /* num_templates   */ 0,
+    /* templates */ TemplateIndex(/* invalid */),
+    /* parameters */ ParameterIndex(165),
+    /* return_matcher_indices */ MatcherIndicesIndex(72),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [83] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
+    /* num_parameters */ 2,
+    /* num_explicit_templates */ 0,
+    /* num_templates   */ 0,
+    /* templates */ TemplateIndex(/* invalid */),
+    /* parameters */ ParameterIndex(165),
+    /* return_matcher_indices */ MatcherIndicesIndex(123),
+    /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
+  },
+  {
+    /* [84] */
+    /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
     /* num_parameters */ 3,
     /* num_explicit_templates */ 0,
     /* num_templates   */ 0,
@@ -3338,7 +3402,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
-    /* [83] */
+    /* [85] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
     /* num_parameters */ 3,
     /* num_explicit_templates */ 0,
@@ -3349,7 +3413,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
-    /* [84] */
+    /* [86] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
     /* num_parameters */ 3,
     /* num_explicit_templates */ 0,
@@ -3360,7 +3424,7 @@
     /* const_eval_fn */ ConstEvalFunctionIndex(/* invalid */),
   },
   {
-    /* [85] */
+    /* [87] */
     /* flags */ OverloadFlags(OverloadFlag::kIsBuiltin, OverloadFlag::kSupportsVertexPipeline, OverloadFlag::kSupportsFragmentPipeline, OverloadFlag::kSupportsComputePipeline, OverloadFlag::kMemberFunction),
     /* num_parameters */ 3,
     /* num_explicit_templates */ 0,
@@ -3428,6 +3492,18 @@
   },
   {
     /* [7] */
+    /* fn unpack_s8s32(int8_t4_packed) -> vec4<i32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(75),
+  },
+  {
+    /* [8] */
+    /* fn unpack_u8u32(uint8_t4_packed) -> vec4<u32> */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(76),
+  },
+  {
+    /* [9] */
     /* fn Load(byte_address_buffer<readable>, offset: u32) -> u32 */
     /* fn Load[T : fiu32](texture: texture_1d<T>, location: vec2<i32>) -> vec4<T> */
     /* fn Load[T : fiu32](texture: texture_2d<T>, location: vec3<i32>) -> vec4<T> */
@@ -3453,73 +3529,73 @@
     /* overloads */ OverloadIndex(27),
   },
   {
-    /* [8] */
-    /* fn Load2(byte_address_buffer<readable>, offset: u32) -> vec2<u32> */
-    /* num overloads */ 1,
-    /* overloads */ OverloadIndex(75),
-  },
-  {
-    /* [9] */
-    /* fn Load3(byte_address_buffer<readable>, offset: u32) -> vec3<u32> */
-    /* num overloads */ 1,
-    /* overloads */ OverloadIndex(76),
-  },
-  {
     /* [10] */
-    /* fn Load4(byte_address_buffer<readable>, offset: u32) -> vec4<u32> */
+    /* fn Load2(byte_address_buffer<readable>, offset: u32) -> vec2<u32> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(77),
   },
   {
     /* [11] */
-    /* fn LoadF16(byte_address_buffer<readable>, offset: u32) -> f16 */
+    /* fn Load3(byte_address_buffer<readable>, offset: u32) -> vec3<u32> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(78),
   },
   {
     /* [12] */
-    /* fn Load2F16(byte_address_buffer<readable>, offset: u32) -> vec2<f16> */
+    /* fn Load4(byte_address_buffer<readable>, offset: u32) -> vec4<u32> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(79),
   },
   {
     /* [13] */
-    /* fn Load3F16(byte_address_buffer<readable>, offset: u32) -> vec3<f16> */
+    /* fn LoadF16(byte_address_buffer<readable>, offset: u32) -> f16 */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(80),
   },
   {
     /* [14] */
-    /* fn Load4F16(byte_address_buffer<readable>, offset: u32) -> vec4<f16> */
+    /* fn Load2F16(byte_address_buffer<readable>, offset: u32) -> vec2<f16> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(81),
   },
   {
     /* [15] */
-    /* fn Store(byte_address_buffer<writable>, offset: u32, value: u32) */
+    /* fn Load3F16(byte_address_buffer<readable>, offset: u32) -> vec3<f16> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(82),
   },
   {
     /* [16] */
-    /* fn Store2(byte_address_buffer<writable>, offset: u32, value: vec2<u32>) */
+    /* fn Load4F16(byte_address_buffer<readable>, offset: u32) -> vec4<f16> */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(83),
   },
   {
     /* [17] */
-    /* fn Store3(byte_address_buffer<writable>, offset: u32, value: vec3<u32>) */
+    /* fn Store(byte_address_buffer<writable>, offset: u32, value: u32) */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(84),
   },
   {
     /* [18] */
-    /* fn Store4(byte_address_buffer<writable>, offset: u32, value: vec4<u32>) */
+    /* fn Store2(byte_address_buffer<writable>, offset: u32, value: vec2<u32>) */
     /* num overloads */ 1,
     /* overloads */ OverloadIndex(85),
   },
   {
     /* [19] */
+    /* fn Store3(byte_address_buffer<writable>, offset: u32, value: vec3<u32>) */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(86),
+  },
+  {
+    /* [20] */
+    /* fn Store4(byte_address_buffer<writable>, offset: u32, value: vec4<u32>) */
+    /* num overloads */ 1,
+    /* overloads */ OverloadIndex(87),
+  },
+  {
+    /* [21] */
     /* fn GetDimensions[A : access](byte_address_buffer<A>, width: ptr<function, u32, writable>) */
     /* fn GetDimensions[T : fiu32](texture: texture_1d<T>, width: ptr<function, u32, writable>) */
     /* fn GetDimensions[T : fiu32](texture: texture_1d<T>, level: u32, width: ptr<function, u32, writable>, num_levels: ptr<function, u32, writable>) */
@@ -3551,7 +3627,7 @@
     /* overloads */ OverloadIndex(0),
   },
   {
-    /* [20] */
+    /* [22] */
     /* fn textureStore[C : iu32](texture: texture_storage_1d<f32_texel_format, writable>, coords: C, value: vec4<f32>) */
     /* fn textureStore[C : iu32](texture: texture_storage_2d<f32_texel_format, writable>, coords: vec2<C>, value: vec4<f32>) */
     /* fn textureStore[C : iu32](texture: texture_storage_2d_array<f32_texel_format, writable>, coords: vec3<C>, value: vec4<f32>) */
diff --git a/src/tint/lang/hlsl/intrinsic/type_matchers.h b/src/tint/lang/hlsl/intrinsic/type_matchers.h
index e99c48b..1d76522 100644
--- a/src/tint/lang/hlsl/intrinsic/type_matchers.h
+++ b/src/tint/lang/hlsl/intrinsic/type_matchers.h
@@ -31,6 +31,8 @@
 #include "src/tint/lang/core/intrinsic/table.h"
 #include "src/tint/lang/core/type/manager.h"
 #include "src/tint/lang/hlsl/type/byte_address_buffer.h"
+#include "src/tint/lang/hlsl/type/int8_t4_packed.h"
+#include "src/tint/lang/hlsl/type/uint8_t4_packed.h"
 
 namespace tint::hlsl::intrinsic {
 
@@ -50,6 +52,24 @@
     return state.types.Get<type::ByteAddressBuffer>(static_cast<core::Access>(A.Value()));
 }
 
+inline bool MatchInt8T4Packed(core::intrinsic::MatchState&, const core::type::Type* ty) {
+    return ty->Is<type::Int8T4Packed>();
+}
+
+inline const type::Int8T4Packed* BuildInt8T4Packed(core::intrinsic::MatchState& state,
+                                                   const core::type::Type*) {
+    return state.types.Get<type::Int8T4Packed>();
+}
+
+inline bool MatchUint8T4Packed(core::intrinsic::MatchState&, const core::type::Type* ty) {
+    return ty->Is<type::Uint8T4Packed>();
+}
+
+inline const type::Uint8T4Packed* BuildUint8T4Packed(core::intrinsic::MatchState& state,
+                                                     const core::type::Type*) {
+    return state.types.Get<type::Uint8T4Packed>();
+}
+
 }  // namespace tint::hlsl::intrinsic
 
 #endif  // SRC_TINT_LANG_HLSL_INTRINSIC_TYPE_MATCHERS_H_
diff --git a/src/tint/lang/hlsl/type/BUILD.bazel b/src/tint/lang/hlsl/type/BUILD.bazel
index 96620ca..fbf73a0 100644
--- a/src/tint/lang/hlsl/type/BUILD.bazel
+++ b/src/tint/lang/hlsl/type/BUILD.bazel
@@ -40,9 +40,13 @@
   name = "type",
   srcs = [
     "byte_address_buffer.cc",
+    "int8_t4_packed.cc",
+    "uint8_t4_packed.cc",
   ],
   hdrs = [
     "byte_address_buffer.h",
+    "int8_t4_packed.h",
+    "uint8_t4_packed.h",
   ],
   deps = [
     "//src/tint/lang/core",
@@ -69,6 +73,8 @@
   alwayslink = True,
   srcs = [
     "byte_address_buffer_test.cc",
+    "int8_t4_packed_test.cc",
+    "uint8_t4_packed_test.cc",
   ],
   deps = [
     "//src/tint/lang/core",
diff --git a/src/tint/lang/hlsl/type/BUILD.cmake b/src/tint/lang/hlsl/type/BUILD.cmake
index ac50dd3..49b481b 100644
--- a/src/tint/lang/hlsl/type/BUILD.cmake
+++ b/src/tint/lang/hlsl/type/BUILD.cmake
@@ -41,6 +41,10 @@
 tint_add_target(tint_lang_hlsl_type lib
   lang/hlsl/type/byte_address_buffer.cc
   lang/hlsl/type/byte_address_buffer.h
+  lang/hlsl/type/int8_t4_packed.cc
+  lang/hlsl/type/int8_t4_packed.h
+  lang/hlsl/type/uint8_t4_packed.cc
+  lang/hlsl/type/uint8_t4_packed.h
 )
 
 tint_target_add_dependencies(tint_lang_hlsl_type lib
@@ -67,6 +71,8 @@
 ################################################################################
 tint_add_target(tint_lang_hlsl_type_test test
   lang/hlsl/type/byte_address_buffer_test.cc
+  lang/hlsl/type/int8_t4_packed_test.cc
+  lang/hlsl/type/uint8_t4_packed_test.cc
 )
 
 tint_target_add_dependencies(tint_lang_hlsl_type_test test
diff --git a/src/tint/lang/hlsl/type/BUILD.gn b/src/tint/lang/hlsl/type/BUILD.gn
index cf5bf71..b4c1a07 100644
--- a/src/tint/lang/hlsl/type/BUILD.gn
+++ b/src/tint/lang/hlsl/type/BUILD.gn
@@ -46,6 +46,10 @@
   sources = [
     "byte_address_buffer.cc",
     "byte_address_buffer.h",
+    "int8_t4_packed.cc",
+    "int8_t4_packed.h",
+    "uint8_t4_packed.cc",
+    "uint8_t4_packed.h",
   ]
   deps = [
     "${tint_src_dir}/lang/core",
@@ -67,7 +71,11 @@
 }
 if (tint_build_unittests) {
   tint_unittests_source_set("unittests") {
-    sources = [ "byte_address_buffer_test.cc" ]
+    sources = [
+      "byte_address_buffer_test.cc",
+      "int8_t4_packed_test.cc",
+      "uint8_t4_packed_test.cc",
+    ]
     deps = [
       "${tint_src_dir}:gmock_and_gtest",
       "${tint_src_dir}/lang/core",
diff --git a/src/tint/lang/hlsl/type/int8_t4_packed.cc b/src/tint/lang/hlsl/type/int8_t4_packed.cc
new file mode 100644
index 0000000..20a1f1e
--- /dev/null
+++ b/src/tint/lang/hlsl/type/int8_t4_packed.cc
@@ -0,0 +1,61 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/type/int8_t4_packed.h"
+
+#include <cstddef>
+#include <string>
+
+#include "src/tint/lang/core/type/clone_context.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/core/type/unique_node.h"
+#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/rtti/castable.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::hlsl::type::Int8T4Packed);
+
+namespace tint::hlsl::type {
+
+Int8T4Packed::Int8T4Packed()
+    : Base(static_cast<size_t>(Hash(tint::TypeCode::Of<Int8T4Packed>().bits)),
+           core::type::Flags{}) {}
+
+bool Int8T4Packed::Equals([[maybe_unused]] const UniqueNode& other) const {
+    return true;
+}
+
+std::string Int8T4Packed::FriendlyName() const {
+    StringStream out;
+    out << "hlsl.int8_t4_packed";
+    return out.str();
+}
+
+Int8T4Packed* Int8T4Packed::Clone(core::type::CloneContext& ctx) const {
+    return ctx.dst.mgr->Get<Int8T4Packed>();
+}
+
+}  // namespace tint::hlsl::type
diff --git a/src/tint/lang/hlsl/type/int8_t4_packed.h b/src/tint/lang/hlsl/type/int8_t4_packed.h
new file mode 100644
index 0000000..2eceb2a
--- /dev/null
+++ b/src/tint/lang/hlsl/type/int8_t4_packed.h
@@ -0,0 +1,57 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_TYPE_INT8_T4_PACKED_H_
+#define SRC_TINT_LANG_HLSL_TYPE_INT8_T4_PACKED_H_
+
+#include <string>
+
+#include "src/tint/lang/core/type/type.h"
+
+namespace tint::hlsl::type {
+
+/// Int8T4Packed represents a packed int8 vector
+class Int8T4Packed final : public Castable<Int8T4Packed, core::type::Type> {
+  public:
+    /// Constructor
+    Int8T4Packed();
+
+    /// @param other the other node to compare against
+    /// @returns true if the this type is equal to @p other
+    bool Equals(const UniqueNode& other) const override;
+
+    /// @returns the friendly name for this type
+    std::string FriendlyName() const override;
+
+    /// @param ctx the clone context
+    /// @returns a clone of this type
+    Int8T4Packed* Clone(core::type::CloneContext& ctx) const override;
+};
+
+}  // namespace tint::hlsl::type
+
+#endif  // SRC_TINT_LANG_HLSL_TYPE_INT8_T4_PACKED_H_
diff --git a/src/tint/lang/hlsl/type/int8_t4_packed_test.cc b/src/tint/lang/hlsl/type/int8_t4_packed_test.cc
new file mode 100644
index 0000000..955d7ed
--- /dev/null
+++ b/src/tint/lang/hlsl/type/int8_t4_packed_test.cc
@@ -0,0 +1,52 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/type/int8_t4_packed.h"
+
+#include <gtest/gtest.h>
+
+#include "src/tint/lang/core/type/f32.h"
+#include "src/tint/lang/core/type/i32.h"
+
+namespace tint::hlsl::type {
+namespace {
+
+TEST(HlslTypeInt8T4Packed, Equals) {
+    const Int8T4Packed a;
+    const Int8T4Packed b;
+
+    EXPECT_TRUE(a.Equals(b));
+}
+
+TEST(HlslTypeInt8T4Packed, FriendlyName) {
+    const Int8T4Packed l;
+
+    EXPECT_EQ(l.FriendlyName(), "hlsl.int8_t4_packed");
+}
+
+}  // namespace
+}  // namespace tint::hlsl::type
diff --git a/src/tint/lang/hlsl/type/uint8_t4_packed.cc b/src/tint/lang/hlsl/type/uint8_t4_packed.cc
new file mode 100644
index 0000000..962a6cb
--- /dev/null
+++ b/src/tint/lang/hlsl/type/uint8_t4_packed.cc
@@ -0,0 +1,61 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/type/uint8_t4_packed.h"
+
+#include <cstddef>
+#include <string>
+
+#include "src/tint/lang/core/type/clone_context.h"
+#include "src/tint/lang/core/type/manager.h"
+#include "src/tint/lang/core/type/unique_node.h"
+#include "src/tint/utils/math/hash.h"
+#include "src/tint/utils/rtti/castable.h"
+
+TINT_INSTANTIATE_TYPEINFO(tint::hlsl::type::Uint8T4Packed);
+
+namespace tint::hlsl::type {
+
+Uint8T4Packed::Uint8T4Packed()
+    : Base(static_cast<size_t>(Hash(tint::TypeCode::Of<Uint8T4Packed>().bits)),
+           core::type::Flags{}) {}
+
+bool Uint8T4Packed::Equals([[maybe_unused]] const UniqueNode& other) const {
+    return true;
+}
+
+std::string Uint8T4Packed::FriendlyName() const {
+    StringStream out;
+    out << "hlsl.uint8_t4_packed";
+    return out.str();
+}
+
+Uint8T4Packed* Uint8T4Packed::Clone(core::type::CloneContext& ctx) const {
+    return ctx.dst.mgr->Get<Uint8T4Packed>();
+}
+
+}  // namespace tint::hlsl::type
diff --git a/src/tint/lang/hlsl/type/uint8_t4_packed.h b/src/tint/lang/hlsl/type/uint8_t4_packed.h
new file mode 100644
index 0000000..d2ecff6
--- /dev/null
+++ b/src/tint/lang/hlsl/type/uint8_t4_packed.h
@@ -0,0 +1,57 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef SRC_TINT_LANG_HLSL_TYPE_UINT8_T4_PACKED_H_
+#define SRC_TINT_LANG_HLSL_TYPE_UINT8_T4_PACKED_H_
+
+#include <string>
+
+#include "src/tint/lang/core/type/type.h"
+
+namespace tint::hlsl::type {
+
+/// Uint8T4Packed represents a packed unsigned int vector
+class Uint8T4Packed final : public Castable<Uint8T4Packed, core::type::Type> {
+  public:
+    /// Constructor
+    Uint8T4Packed();
+
+    /// @param other the other node to compare against
+    /// @returns true if the this type is equal to @p other
+    bool Equals(const UniqueNode& other) const override;
+
+    /// @returns the friendly name for this type
+    std::string FriendlyName() const override;
+
+    /// @param ctx the clone context
+    /// @returns a clone of this type
+    Uint8T4Packed* Clone(core::type::CloneContext& ctx) const override;
+};
+
+}  // namespace tint::hlsl::type
+
+#endif  // SRC_TINT_LANG_HLSL_TYPE_UINT8_T4_PACKED_H_
diff --git a/src/tint/lang/hlsl/type/uint8_t4_packed_test.cc b/src/tint/lang/hlsl/type/uint8_t4_packed_test.cc
new file mode 100644
index 0000000..af44acd
--- /dev/null
+++ b/src/tint/lang/hlsl/type/uint8_t4_packed_test.cc
@@ -0,0 +1,52 @@
+// Copyright 2024 The Dawn & Tint Authors
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice, this
+//    list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the copyright holder nor the names of its
+//    contributors may be used to endorse or promote products derived from
+//    this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#include "src/tint/lang/hlsl/type/uint8_t4_packed.h"
+
+#include <gtest/gtest.h>
+
+#include "src/tint/lang/core/type/f32.h"
+#include "src/tint/lang/core/type/i32.h"
+
+namespace tint::hlsl::type {
+namespace {
+
+TEST(HlslTypeUint8T4Packed, Equals) {
+    const Uint8T4Packed a;
+    const Uint8T4Packed b;
+
+    EXPECT_TRUE(a.Equals(b));
+}
+
+TEST(HlslTypeUint8T4Packed, FriendlyName) {
+    const Uint8T4Packed l;
+
+    EXPECT_EQ(l.FriendlyName(), "hlsl.uint8_t4_packed");
+}
+
+}  // namespace
+}  // namespace tint::hlsl::type
diff --git a/src/tint/lang/hlsl/writer/builtin_test.cc b/src/tint/lang/hlsl/writer/builtin_test.cc
index 795b93f..64ea3a5 100644
--- a/src/tint/lang/hlsl/writer/builtin_test.cc
+++ b/src/tint/lang/hlsl/writer/builtin_test.cc
@@ -1318,5 +1318,182 @@
 )");
 }
 
+TEST_F(HlslWriterTest, BuiltinUnpack2x16Float) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Float, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint v = u;
+  float2 a = f16tof32(uint2((v & 65535u), (v >> 16u)));
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack2x16Snorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Snorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  int v = int(u);
+  float2 a = clamp((float2((int2((v << 16u), v) >> (16u).xx)) / 32767.0f), (-1.0f).xx, (1.0f).xx);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack2x16Unorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Unorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint v = u;
+  float2 a = (float2(uint2((v & 65535u), (v >> 16u))) / 65535.0f);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4x8Snorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Snorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  int v = int(u);
+  float4 a = clamp((float4((int4((v << 24u), (v << 16u), (v << 8u), v) >> (24u).xxxx)) / 127.0f), (-1.0f).xxxx, (1.0f).xxxx);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4x8Unorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Unorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint v = u;
+  float4 a = (float4(uint4((v & 255u), ((v >> 8u) & 255u), ((v >> 16u) & 255u), (v >> 24u))) / 255.0f);
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4xI8CorePolyfill) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<i32>(), core::BuiltinFn::kUnpack4XI8, b.Load(u)));
+        b.Return(func);
+    });
+
+    Options opts{};
+    opts.polyfill_pack_unpack_4x8 = true;
+    ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint v = u;
+  uint4 v_1 = uint4(24u, 16u, 8u, 0u);
+  int4 v_2 = asint((uint4((v).xxxx) << v_1));
+  int4 a = (v_2 >> uint4((24u).xxxx));
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4xI8) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<i32>(), core::BuiltinFn::kUnpack4XI8, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  int4 a = unpack_s8s32(int8_t4_packed(u));
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4xU8CorePolyfill) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<u32>(), core::BuiltinFn::kUnpack4XU8, b.Load(u)));
+        b.Return(func);
+    });
+
+    Options opts{};
+    opts.polyfill_pack_unpack_4x8 = true;
+    ASSERT_TRUE(Generate(opts)) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint v = u;
+  uint4 v_1 = uint4(0u, 8u, 16u, 24u);
+  uint4 v_2 = (uint4((v).xxxx) >> v_1);
+  uint4 a = (v_2 & uint4((255u).xxxx));
+}
+
+)");
+}
+
+TEST_F(HlslWriterTest, BuiltinUnpack4xU8) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<u32>(), core::BuiltinFn::kUnpack4XU8, b.Load(u)));
+        b.Return(func);
+    });
+
+    ASSERT_TRUE(Generate()) << err_ << output_.hlsl;
+    EXPECT_EQ(output_.hlsl, R"(
+void foo() {
+  uint u = 2u;
+  uint4 a = unpack_u8u32(uint8_t4_packed(u));
+}
+
+)");
+}
+
 }  // namespace
 }  // namespace tint::hlsl::writer
diff --git a/src/tint/lang/hlsl/writer/printer/printer.cc b/src/tint/lang/hlsl/writer/printer/printer.cc
index c330bde..1f247a7 100644
--- a/src/tint/lang/hlsl/writer/printer/printer.cc
+++ b/src/tint/lang/hlsl/writer/printer/printer.cc
@@ -107,6 +107,8 @@
 #include "src/tint/lang/hlsl/ir/member_builtin_call.h"
 #include "src/tint/lang/hlsl/ir/ternary.h"
 #include "src/tint/lang/hlsl/type/byte_address_buffer.h"
+#include "src/tint/lang/hlsl/type/int8_t4_packed.h"
+#include "src/tint/lang/hlsl/type/uint8_t4_packed.h"
 #include "src/tint/utils/containers/hashmap.h"
 #include "src/tint/utils/containers/map.h"
 #include "src/tint/utils/generator/text_generator.h"
@@ -1221,6 +1223,9 @@
                 }
                 out << "ByteAddressBuffer";
             },
+            [&](const hlsl::type::Int8T4Packed*) { out << "int8_t4_packed"; },
+            [&](const hlsl::type::Uint8T4Packed*) { out << "uint8_t4_packed"; },
+
             [&](const core::type::Bool*) { out << "bool"; },      //
             [&](const core::type::F16*) { out << "float16_t"; },  //
             [&](const core::type::F32*) { out << "float"; },      //
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
index 7552384..80274c7 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill.cc
@@ -47,6 +47,8 @@
 #include "src/tint/lang/hlsl/ir/builtin_call.h"
 #include "src/tint/lang/hlsl/ir/member_builtin_call.h"
 #include "src/tint/lang/hlsl/ir/ternary.h"
+#include "src/tint/lang/hlsl/type/int8_t4_packed.h"
+#include "src/tint/lang/hlsl/type/uint8_t4_packed.h"
 #include "src/tint/utils/containers/hashmap.h"
 #include "src/tint/utils/math/hash.h"
 
@@ -94,6 +96,13 @@
                     case core::BuiltinFn::kTextureNumSamples:
                     case core::BuiltinFn::kTextureStore:
                     case core::BuiltinFn::kTrunc:
+                    case core::BuiltinFn::kUnpack2X16Float:
+                    case core::BuiltinFn::kUnpack2X16Snorm:
+                    case core::BuiltinFn::kUnpack2X16Unorm:
+                    case core::BuiltinFn::kUnpack4X8Snorm:
+                    case core::BuiltinFn::kUnpack4X8Unorm:
+                    case core::BuiltinFn::kUnpack4XI8:
+                    case core::BuiltinFn::kUnpack4XU8:
                         call_worklist.Push(call);
                         break;
                     default:
@@ -150,6 +159,27 @@
                 case core::BuiltinFn::kTrunc:
                     Trunc(call);
                     break;
+                case core::BuiltinFn::kUnpack2X16Float:
+                    Unpack2x16Float(call);
+                    break;
+                case core::BuiltinFn::kUnpack2X16Snorm:
+                    Unpack2x16Snorm(call);
+                    break;
+                case core::BuiltinFn::kUnpack2X16Unorm:
+                    Unpack2x16Unorm(call);
+                    break;
+                case core::BuiltinFn::kUnpack4X8Snorm:
+                    Unpack4x8Snorm(call);
+                    break;
+                case core::BuiltinFn::kUnpack4X8Unorm:
+                    Unpack4x8Unorm(call);
+                    break;
+                case core::BuiltinFn::kUnpack4XI8:
+                    Unpack4xI8(call);
+                    break;
+                case core::BuiltinFn::kUnpack4XU8:
+                    Unpack4xU8(call);
+                    break;
                 default:
                     TINT_UNREACHABLE();
             }
@@ -702,6 +732,112 @@
         });
         call->Destroy();
     }
+
+    void Unpack2x16Float(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* x = b.And(ty.u32(), args[0], 0xffff_u);
+            auto* y = b.ShiftRight(ty.u32(), args[0], 16_u);
+            auto* conv = b.Construct(ty.vec2<u32>(), x, y);
+
+            b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
+                                                    hlsl::BuiltinFn::kF16Tof32, conv);
+        });
+        call->Destroy();
+    }
+
+    void Unpack2x16Snorm(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* conv = b.Convert(ty.i32(), args[0]);
+            auto* x = b.ShiftLeft(ty.i32(), conv, 16_u);
+
+            auto* vec = b.Construct(ty.vec2<i32>(), x, conv);
+            auto* v = b.ShiftRight(ty.vec2<i32>(), vec, b.Composite(ty.vec2<u32>(), 16_u));
+
+            auto* flt = b.Convert(ty.vec2<f32>(), v);
+            auto* scale = b.Divide(ty.vec2<f32>(), flt, 32767_f);
+
+            auto* lower = b.Splat(ty.vec2<f32>(), -1_f);
+            auto* upper = b.Splat(ty.vec2<f32>(), 1_f);
+            b.CallWithResult(call->DetachResult(), core::BuiltinFn::kClamp, scale, lower, upper);
+        });
+        call->Destroy();
+    }
+
+    void Unpack2x16Unorm(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* x = b.And(ty.u32(), args[0], 0xffff_u);
+            auto* y = b.ShiftRight(ty.u32(), args[0], 16_u);
+            auto* conv = b.Construct(ty.vec2<u32>(), x, y);
+            auto* flt_conv = b.Convert(ty.vec2<f32>(), conv);
+            auto* scale = b.Divide(ty.vec2<f32>(), flt_conv, 0xffff_f);
+
+            call->Result(0)->ReplaceAllUsesWith(scale->Result(0));
+        });
+        call->Destroy();
+    }
+
+    void Unpack4x8Snorm(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* conv = b.Convert(ty.i32(), args[0]);
+            auto* x = b.ShiftLeft(ty.i32(), conv, 24_u);
+            auto* y = b.ShiftLeft(ty.i32(), conv, 16_u);
+            auto* z = b.ShiftLeft(ty.i32(), conv, 8_u);
+            auto* cons = b.Construct(ty.vec4<i32>(), x, y, z, conv);
+            auto* shr = b.ShiftRight(ty.vec4<i32>(), cons, b.Composite(ty.vec4<u32>(), 24_u));
+            auto* flt = b.Convert(ty.vec4<f32>(), shr);
+            auto* scale = b.Divide(ty.vec4<f32>(), flt, 127_f);
+
+            auto* lower = b.Splat(ty.vec4<f32>(), -1_f);
+            auto* upper = b.Splat(ty.vec4<f32>(), 1_f);
+            b.CallWithResult(call->DetachResult(), core::BuiltinFn::kClamp, scale, lower, upper);
+        });
+        call->Destroy();
+    }
+
+    void Unpack4x8Unorm(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* val = args[0];
+            auto* x = b.And(ty.u32(), val, 0xff_u);
+            auto* y = b.And(ty.u32(), b.ShiftRight(ty.u32(), val, 8_u), 0xff_u);
+            auto* z = b.And(ty.u32(), b.ShiftRight(ty.u32(), val, 16_u), 0xff_u);
+            auto* w = b.ShiftRight(ty.u32(), val, 24_u);
+            auto* cons = b.Construct(ty.vec4<u32>(), x, y, z, w);
+            auto* conv = b.Convert(ty.vec4<f32>(), cons);
+            auto* scale = b.Divide(ty.vec4<f32>(), conv, 255_f);
+
+            call->Result(0)->ReplaceAllUsesWith(scale->Result(0));
+        });
+        call->Destroy();
+    }
+
+    void Unpack4xI8(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* type = ty.Get<hlsl::type::Int8T4Packed>();
+            auto* conv = b.Convert(type, args[0]);
+
+            b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
+                                                    hlsl::BuiltinFn::kUnpackS8S32, conv);
+        });
+        call->Destroy();
+    }
+
+    void Unpack4xU8(core::ir::CoreBuiltinCall* call) {
+        auto args = call->Args();
+        b.InsertBefore(call, [&] {
+            auto* type = ty.Get<hlsl::type::Uint8T4Packed>();
+            auto* conv = b.Convert(type, args[0]);
+
+            b.CallWithResult<hlsl::ir::BuiltinCall>(call->DetachResult(),
+                                                    hlsl::BuiltinFn::kUnpackU8U32, conv);
+        });
+        call->Destroy();
+    }
 };
 
 }  // namespace
diff --git a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
index 1cc357d..ed52790 100644
--- a/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
+++ b/src/tint/lang/hlsl/writer/raise/builtin_polyfill_test.cc
@@ -1173,5 +1173,295 @@
     EXPECT_EQ(expect, str());
 }
 
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack2x16Float) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Float, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec2<f32> = unpack2x16float %3
+    %a:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:u32 = and %3, 65535u
+    %5:u32 = shr %3, 16u
+    %6:vec2<u32> = construct %4, %5
+    %7:vec2<f32> = hlsl.f16tof32 %6
+    %a:vec2<f32> = let %7
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack2x16snorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Snorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec2<f32> = unpack2x16snorm %3
+    %a:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:i32 = convert %3
+    %5:i32 = shl %4, 16u
+    %6:vec2<i32> = construct %5, %4
+    %7:vec2<i32> = shr %6, vec2<u32>(16u)
+    %8:vec2<f32> = convert %7
+    %9:vec2<f32> = div %8, 32767.0f
+    %10:vec2<f32> = clamp %9, vec2<f32>(-1.0f), vec2<f32>(1.0f)
+    %a:vec2<f32> = let %10
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack2x16unorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec2<f32>(), core::BuiltinFn::kUnpack2X16Unorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec2<f32> = unpack2x16unorm %3
+    %a:vec2<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:u32 = and %3, 65535u
+    %5:u32 = shr %3, 16u
+    %6:vec2<u32> = construct %4, %5
+    %7:vec2<f32> = convert %6
+    %8:vec2<f32> = div %7, 65535.0f
+    %a:vec2<f32> = let %8
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack4x8Snorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Snorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec4<f32> = unpack4x8snorm %3
+    %a:vec4<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:i32 = convert %3
+    %5:i32 = shl %4, 24u
+    %6:i32 = shl %4, 16u
+    %7:i32 = shl %4, 8u
+    %8:vec4<i32> = construct %5, %6, %7, %4
+    %9:vec4<i32> = shr %8, vec4<u32>(24u)
+    %10:vec4<f32> = convert %9
+    %11:vec4<f32> = div %10, 127.0f
+    %12:vec4<f32> = clamp %11, vec4<f32>(-1.0f), vec4<f32>(1.0f)
+    %a:vec4<f32> = let %12
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack4x8Unorm) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<f32>(), core::BuiltinFn::kUnpack4X8Unorm, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec4<f32> = unpack4x8unorm %3
+    %a:vec4<f32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:u32 = and %3, 255u
+    %5:u32 = shr %3, 8u
+    %6:u32 = and %5, 255u
+    %7:u32 = shr %3, 16u
+    %8:u32 = and %7, 255u
+    %9:u32 = shr %3, 24u
+    %10:vec4<u32> = construct %4, %6, %8, %9
+    %11:vec4<f32> = convert %10
+    %12:vec4<f32> = div %11, 255.0f
+    %a:vec4<f32> = let %12
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack4xI8) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<i32>(), core::BuiltinFn::kUnpack4XI8, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec4<i32> = unpack4xI8 %3
+    %a:vec4<i32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:hlsl.int8_t4_packed = convert %3
+    %5:vec4<i32> = hlsl.unpack_s8s32 %4
+    %a:vec4<i32> = let %5
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
+TEST_F(HlslWriter_BuiltinPolyfillTest, Unpack4xU8) {
+    auto* func = b.Function("foo", ty.void_(), core::ir::Function::PipelineStage::kFragment);
+    b.Append(func->Block(), [&] {
+        auto* u = b.Var("u", 2_u);
+        b.Let("a", b.Call(ty.vec4<u32>(), core::BuiltinFn::kUnpack4XU8, b.Load(u)));
+        b.Return(func);
+    });
+
+    auto* src = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:vec4<u32> = unpack4xU8 %3
+    %a:vec4<u32> = let %4
+    ret
+  }
+}
+)";
+    ASSERT_EQ(src, str());
+
+    auto* expect = R"(
+%foo = @fragment func():void {
+  $B1: {
+    %u:ptr<function, u32, read_write> = var, 2u
+    %3:u32 = load %u
+    %4:hlsl.uint8_t4_packed = convert %3
+    %5:vec4<u32> = hlsl.unpack_u8u32 %4
+    %a:vec4<u32> = let %5
+    ret
+  }
+}
+)";
+    Run(BuiltinPolyfill);
+
+    EXPECT_EQ(expect, str());
+}
+
 }  // namespace
 }  // namespace tint::hlsl::writer::raise