@@ -121,6 +121,9 @@ const fn scalar_is_int(scalar: crate::Scalar) -> bool {
121
121
/// Prefix for cached clamped level-of-detail values for `ImageLoad` expressions.
122
122
const CLAMPED_LOD_LOAD_PREFIX : & str = "clamped_lod_e" ;
123
123
124
+ /// Prefix for reinterpreted expressions using `as_type<T>(...)`.
125
+ const REINTERPRET_PREFIX : & str = "reinterpreted_" ;
126
+
124
127
/// Wrapper for identifier names for clamped level-of-detail values
125
128
///
126
129
/// Values of this type implement [`core::fmt::Display`], formatting as
@@ -156,6 +159,30 @@ impl Display for ArraySizeMember {
156
159
}
157
160
}
158
161
162
+ /// Wrapper for reinterpreted variables using `as_type<target_type>(orig)`.
163
+ ///
164
+ /// Implements [`core::fmt::Display`], formatting as a name derived from
165
+ /// `target_type` and the variable name of `orig`.
166
+ #[ derive( Clone , Copy ) ]
167
+ struct Reinterpreted < ' a > {
168
+ target_type : & ' a str ,
169
+ orig : Handle < crate :: Expression > ,
170
+ }
171
+
172
+ impl < ' a > Reinterpreted < ' a > {
173
+ const fn new ( target_type : & ' a str , orig : Handle < crate :: Expression > ) -> Self {
174
+ Self { target_type, orig }
175
+ }
176
+ }
177
+
178
+ impl Display for Reinterpreted < ' _ > {
179
+ fn fmt ( & self , f : & mut Formatter < ' _ > ) -> core:: fmt:: Result {
180
+ f. write_str ( REINTERPRET_PREFIX ) ?;
181
+ f. write_str ( self . target_type ) ?;
182
+ self . orig . write_prefixed ( f, "_e" )
183
+ }
184
+ }
185
+
159
186
struct TypeContext < ' a > {
160
187
handle : Handle < crate :: Type > ,
161
188
gctx : proc:: GlobalCtx < ' a > ,
@@ -1470,14 +1497,14 @@ impl<W: Write> Writer<W> {
1470
1497
1471
1498
/// Emit code for the arithmetic expression of the dot product.
1472
1499
///
1473
- /// The argument `extractor` is a function that accepts a `Writer`, a handle to a vector,
1474
- /// and an index. writes out the expression for the component at that index.
1475
- fn put_dot_product (
1500
+ /// The argument `extractor` is a function that accepts a `Writer`, a vector, and
1501
+ /// an index. It writes out the expression for the vector component at that index.
1502
+ fn put_dot_product < T : Copy > (
1476
1503
& mut self ,
1477
- arg : Handle < crate :: Expression > ,
1478
- arg1 : Handle < crate :: Expression > ,
1504
+ arg : T ,
1505
+ arg1 : T ,
1479
1506
size : usize ,
1480
- extractor : impl Fn ( & mut Self , Handle < crate :: Expression > , usize ) -> BackendResult ,
1507
+ extractor : impl Fn ( & mut Self , T , usize ) -> BackendResult ,
1481
1508
) -> BackendResult {
1482
1509
// Write parentheses around the dot product expression to prevent operators
1483
1510
// with different precedences from applying earlier.
@@ -2206,24 +2233,22 @@ impl<W: Write> Writer<W> {
2206
2233
) ,
2207
2234
} ,
2208
2235
fun @ ( Mf :: Dot4I8Packed | Mf :: Dot4U8Packed ) => {
2209
- let conversion = match fun {
2210
- Mf :: Dot4I8Packed => "int" ,
2211
- Mf :: Dot4U8Packed => "" ,
2236
+ // The two function arguments were already reinterpreted as packed (signed
2237
+ // or unsigned) chars in `Self::put_block`.
2238
+ let packed_type = match fun {
2239
+ Mf :: Dot4I8Packed => "packed_char4" ,
2240
+ Mf :: Dot4U8Packed => "packed_uchar4" ,
2212
2241
_ => unreachable ! ( ) ,
2213
2242
} ;
2214
2243
2215
2244
return self . put_dot_product (
2216
- arg,
2217
- arg1. unwrap ( ) ,
2245
+ Reinterpreted :: new ( packed_type , arg) ,
2246
+ Reinterpreted :: new ( packed_type , arg1. unwrap ( ) ) ,
2218
2247
4 ,
2219
2248
|writer, arg, index| {
2220
- write ! ( writer. out, "({}(" , conversion) ?;
2221
- writer. put_expression ( arg, context, true ) ?;
2222
- if index == 3 {
2223
- write ! ( writer. out, ") >> 24)" ) ?;
2224
- } else {
2225
- write ! ( writer. out, ") << {} >> 24)" , ( 3 - index) * 8 ) ?;
2226
- }
2249
+ // MSL implicitly promotes these (signed or unsigned) chars to
2250
+ // `int` or `uint` in the multiplication, so no overflow can occur.
2251
+ write ! ( writer. out, "{arg}[{index}]" ) ?;
2227
2252
Ok ( ( ) )
2228
2253
} ,
2229
2254
) ;
@@ -3362,17 +3387,57 @@ impl<W: Write> Writer<W> {
3362
3387
match * statement {
3363
3388
crate :: Statement :: Emit ( ref range) => {
3364
3389
for handle in range. clone ( ) {
3365
- // `ImageLoad` expressions covered by the `Restrict` bounds check policy
3366
- // may need to cache a clamped version of their level-of-detail argument.
3367
- if let crate :: Expression :: ImageLoad {
3368
- image,
3369
- level : mip_level,
3370
- ..
3371
- } = context. expression . function . expressions [ handle]
3372
- {
3373
- self . put_cache_restricted_level (
3374
- handle, image, mip_level, level, context,
3375
- ) ?;
3390
+ use crate :: MathFunction as Mf ;
3391
+
3392
+ match context. expression . function . expressions [ handle] {
3393
+ // `ImageLoad` expressions covered by the `Restrict` bounds check policy
3394
+ // may need to cache a clamped version of their level-of-detail argument.
3395
+ crate :: Expression :: ImageLoad {
3396
+ image,
3397
+ level : mip_level,
3398
+ ..
3399
+ } => {
3400
+ self . put_cache_restricted_level (
3401
+ handle, image, mip_level, level, context,
3402
+ ) ?;
3403
+ }
3404
+
3405
+ // If we are going to write a `Dot4I8Packed` or `Dot4U8Packed` then we
3406
+ // introduce two intermediate variables that recast the two arguments as
3407
+ // packed (signed or unsigned) chars. The actual dot product is
3408
+ // implemented in `Self::put_expression`, and it uses both of these
3409
+ // intermediate variables multiple times.
3410
+ crate :: Expression :: Math {
3411
+ fun : fun @ ( Mf :: Dot4I8Packed | Mf :: Dot4U8Packed ) ,
3412
+ arg,
3413
+ arg1,
3414
+ ..
3415
+ } => {
3416
+ let arg1 = arg1. unwrap ( ) ;
3417
+ let packed_type = match fun {
3418
+ Mf :: Dot4I8Packed => "packed_char4" ,
3419
+ Mf :: Dot4U8Packed => "packed_uchar4" ,
3420
+ _ => unreachable ! ( ) ,
3421
+ } ;
3422
+
3423
+ write ! (
3424
+ self . out,
3425
+ "{level}{packed_type} {0} = as_type<{packed_type}>(" ,
3426
+ Reinterpreted :: new( packed_type, arg)
3427
+ ) ?;
3428
+ self . put_expression ( arg, & context. expression , true ) ?;
3429
+ writeln ! ( self . out, ");" ) ?;
3430
+
3431
+ write ! (
3432
+ self . out,
3433
+ "{level}{packed_type} {0} = as_type<{packed_type}>(" ,
3434
+ Reinterpreted :: new( packed_type, arg1)
3435
+ ) ?;
3436
+ self . put_expression ( arg1, & context. expression , true ) ?;
3437
+ writeln ! ( self . out, ");" ) ?;
3438
+ }
3439
+
3440
+ _ => ( ) ,
3376
3441
}
3377
3442
3378
3443
let ptr_class = context. expression . resolve_type ( handle) . pointer_space ( ) ;
0 commit comments