@@ -11,7 +11,10 @@ use rspirv::dr::Operand;
11
11
use rspirv:: spirv:: {
12
12
Capability , Decoration , Dim , ExecutionModel , FunctionControl , StorageClass , Word ,
13
13
} ;
14
- use rustc_codegen_ssa:: traits:: { BaseTypeCodegenMethods , BuilderMethods , MiscCodegenMethods as _} ;
14
+ use rustc_codegen_ssa:: traits:: {
15
+ BaseTypeCodegenMethods , BuilderMethods , ConstCodegenMethods , LayoutTypeCodegenMethods ,
16
+ MiscCodegenMethods as _,
17
+ } ;
15
18
use rustc_data_structures:: fx:: FxHashMap ;
16
19
use rustc_errors:: MultiSpan ;
17
20
use rustc_hir as hir;
@@ -86,22 +89,7 @@ impl<'tcx> CodegenCx<'tcx> {
86
89
} ;
87
90
for ( arg_abi, hir_param) in fn_abi. args . iter ( ) . zip ( hir_params) {
88
91
match arg_abi. mode {
89
- PassMode :: Direct ( _) => { }
90
- PassMode :: Pair ( ..) => {
91
- // FIXME(eddyb) implement `ScalarPair` `Input`s, or change
92
- // the `FnAbi` readjustment to only use `PassMode::Pair` for
93
- // pointers to `!Sized` types, but not other `ScalarPair`s.
94
- if !matches ! ( arg_abi. layout. ty. kind( ) , ty:: Ref ( ..) ) {
95
- self . tcx . dcx ( ) . span_err (
96
- hir_param. ty_span ,
97
- format ! (
98
- "entry point parameter type not yet supported \
99
- (`{}` has `ScalarPair` ABI but is not a `&T`)",
100
- arg_abi. layout. ty
101
- ) ,
102
- ) ;
103
- }
104
- }
92
+ PassMode :: Direct ( _) | PassMode :: Pair ( ..) => { }
105
93
// FIXME(eddyb) support these (by just ignoring them) - if there
106
94
// is any validation concern, it should be done on the types.
107
95
PassMode :: Ignore => self . tcx . dcx ( ) . span_fatal (
@@ -442,6 +430,33 @@ impl<'tcx> CodegenCx<'tcx> {
442
430
} = self . entry_param_deduce_from_rust_ref_or_value ( entry_arg_abi. layout , hir_param, & attrs) ;
443
431
let value_spirv_type = value_layout. spirv_type ( hir_param. ty_span , self ) ;
444
432
433
+ // In compute shaders, user-provided data must come from buffers or push
434
+ // constants, i.e. by-reference parameters.
435
+ if execution_model == ExecutionModel :: GLCompute
436
+ && matches ! ( entry_arg_abi. mode, PassMode :: Direct ( _) | PassMode :: Pair ( ..) )
437
+ && !matches ! ( entry_arg_abi. layout. ty. kind( ) , ty:: Ref ( ..) )
438
+ && attrs. builtin . is_none ( )
439
+ {
440
+ let param_name = if let hir:: PatKind :: Binding ( _, _, ident, _) = & hir_param. pat . kind {
441
+ ident. name . to_string ( )
442
+ } else {
443
+ "parameter" . to_string ( )
444
+ } ;
445
+ self . tcx
446
+ . dcx ( )
447
+ . struct_span_err (
448
+ hir_param. ty_span ,
449
+ format ! ( "compute entry parameter `{param_name}` must be by-reference" , ) ,
450
+ )
451
+ . with_help ( format ! (
452
+ "consider changing the type to `&{}`" ,
453
+ entry_arg_abi. layout. ty
454
+ ) )
455
+ . emit ( ) ;
456
+ // Keep this a hard error to stop compilation after emitting help.
457
+ self . tcx . dcx ( ) . abort_if_errors ( ) ;
458
+ }
459
+
445
460
let ( var_id, spec_const_id) = match storage_class {
446
461
// Pre-allocate the module-scoped `OpVariable` *Result* ID.
447
462
Ok ( _) => (
@@ -491,14 +506,6 @@ impl<'tcx> CodegenCx<'tcx> {
491
506
vs layout:\n {value_layout:#?}",
492
507
entry_arg_abi. layout. ty
493
508
) ;
494
- if is_pair && !is_unsized {
495
- // If PassMode is Pair, then we need to fill in the second part of the pair with a
496
- // value. We currently only do that with unsized types, so if a type is a pair for some
497
- // other reason (e.g. a tuple), we bail.
498
- self . tcx
499
- . dcx ( )
500
- . span_fatal ( hir_param. ty_span , "pair type not supported yet" )
501
- }
502
509
// FIXME(eddyb) should this talk about "typed buffers" instead of "interface blocks"?
503
510
// FIXME(eddyb) should we talk about "descriptor indexing" or
504
511
// actually use more reasonable terms like "resource arrays"?
@@ -621,8 +628,8 @@ impl<'tcx> CodegenCx<'tcx> {
621
628
}
622
629
}
623
630
624
- let value_len = if is_pair {
625
- // We've already emitted an error, fill in a placeholder value
631
+ let value_len = if is_pair && is_unsized {
632
+ // For wide references (e.g., slices), the second component is a length.
626
633
Some ( bx. undef ( self . type_isize ( ) ) )
627
634
} else {
628
635
None
@@ -645,21 +652,54 @@ impl<'tcx> CodegenCx<'tcx> {
645
652
_ => unreachable ! ( ) ,
646
653
}
647
654
} else {
648
- assert_matches ! ( entry_arg_abi. mode, PassMode :: Direct ( _) ) ;
649
-
650
- let value = match storage_class {
651
- Ok ( _) => {
655
+ match entry_arg_abi. mode {
656
+ PassMode :: Direct ( _) => {
657
+ let value = match storage_class {
658
+ Ok ( _) => {
659
+ assert_eq ! ( storage_class, Ok ( StorageClass :: Input ) ) ;
660
+ bx. load (
661
+ entry_arg_abi. layout . spirv_type ( hir_param. ty_span , bx) ,
662
+ value_ptr. unwrap ( ) ,
663
+ entry_arg_abi. layout . align . abi ,
664
+ )
665
+ }
666
+ Err ( SpecConstant { .. } ) => {
667
+ spec_const_id. unwrap ( ) . with_type ( value_spirv_type)
668
+ }
669
+ } ;
670
+ call_args. push ( value) ;
671
+ assert_eq ! ( value_len, None ) ;
672
+ }
673
+ PassMode :: Pair ( ..) => {
674
+ // Load both elements of the scalar pair from the input variable.
652
675
assert_eq ! ( storage_class, Ok ( StorageClass :: Input ) ) ;
653
- bx. load (
654
- entry_arg_abi. layout . spirv_type ( hir_param. ty_span , bx) ,
655
- value_ptr. unwrap ( ) ,
656
- entry_arg_abi. layout . align . abi ,
657
- )
676
+ let layout = entry_arg_abi. layout ;
677
+ let ( a, b) = match layout. backend_repr {
678
+ rustc_abi:: BackendRepr :: ScalarPair ( a, b) => ( a, b) ,
679
+ other => span_bug ! (
680
+ hir_param. ty_span,
681
+ "ScalarPair expected for entry param, found {other:?}"
682
+ ) ,
683
+ } ;
684
+ let b_offset = a
685
+ . primitive ( )
686
+ . size ( self )
687
+ . align_to ( b. primitive ( ) . align ( self ) . abi ) ;
688
+
689
+ let elem0_ty = self . scalar_pair_element_backend_type ( layout, 0 , false ) ;
690
+ let elem1_ty = self . scalar_pair_element_backend_type ( layout, 1 , false ) ;
691
+
692
+ let base_ptr = value_ptr. unwrap ( ) ;
693
+ let ptr1 = bx. inbounds_ptradd ( base_ptr, self . const_usize ( b_offset. bytes ( ) ) ) ;
694
+
695
+ let v0 = bx. load ( elem0_ty, base_ptr, layout. align . abi ) ;
696
+ let v1 = bx. load ( elem1_ty, ptr1, layout. align . restrict_for_offset ( b_offset) ) ;
697
+ call_args. push ( v0) ;
698
+ call_args. push ( v1) ;
699
+ assert_eq ! ( value_len, None ) ;
658
700
}
659
- Err ( SpecConstant { .. } ) => spec_const_id. unwrap ( ) . with_type ( value_spirv_type) ,
660
- } ;
661
- call_args. push ( value) ;
662
- assert_eq ! ( value_len, None ) ;
701
+ _ => unreachable ! ( ) ,
702
+ }
663
703
}
664
704
665
705
// FIXME(eddyb) check whether the storage class is compatible with the
0 commit comments