@@ -11,7 +11,10 @@ use rspirv::dr::Operand;
1111use rspirv:: spirv:: {
1212 Capability , Decoration , Dim , ExecutionModel , FunctionControl , StorageClass , Word ,
1313} ;
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+ } ;
1518use rustc_data_structures:: fx:: FxHashMap ;
1619use rustc_errors:: MultiSpan ;
1720use rustc_hir as hir;
@@ -87,21 +90,7 @@ impl<'tcx> CodegenCx<'tcx> {
8790 for ( arg_abi, hir_param) in fn_abi. args . iter ( ) . zip ( hir_params) {
8891 match arg_abi. mode {
8992 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- }
93+ PassMode :: Pair ( ..) => { }
10594 // FIXME(eddyb) support these (by just ignoring them) - if there
10695 // is any validation concern, it should be done on the types.
10796 PassMode :: Ignore => self . tcx . dcx ( ) . span_fatal (
@@ -442,6 +431,36 @@ impl<'tcx> CodegenCx<'tcx> {
442431 } = self . entry_param_deduce_from_rust_ref_or_value ( entry_arg_abi. layout , hir_param, & attrs) ;
443432 let value_spirv_type = value_layout. spirv_type ( hir_param. ty_span , self ) ;
444433
434+ // In compute shaders, user-provided data must come from buffers or push
435+ // constants, i.e. by-reference parameters.
436+ if execution_model == ExecutionModel :: GLCompute
437+ && matches ! ( entry_arg_abi. mode, PassMode :: Direct ( _) | PassMode :: Pair ( ..) )
438+ && !matches ! ( entry_arg_abi. layout. ty. kind( ) , ty:: Ref ( ..) )
439+ && attrs. builtin . is_none ( )
440+ {
441+ let param_name = if let hir:: PatKind :: Binding ( _, _, ident, _) = & hir_param. pat . kind {
442+ ident. name . to_string ( )
443+ } else {
444+ "parameter" . to_string ( )
445+ } ;
446+ self . tcx
447+ . dcx ( )
448+ . struct_span_err (
449+ hir_param. ty_span ,
450+ format ! (
451+ "compute entry parameter `{}` must be by-reference" ,
452+ param_name
453+ ) ,
454+ )
455+ . with_help ( format ! (
456+ "consider changing the type to `&{}`" ,
457+ entry_arg_abi. layout. ty
458+ ) )
459+ . emit ( ) ;
460+ // Keep this a hard error to stop compilation after emitting help.
461+ self . tcx . dcx ( ) . abort_if_errors ( ) ;
462+ }
463+
445464 let ( var_id, spec_const_id) = match storage_class {
446465 // Pre-allocate the module-scoped `OpVariable` *Result* ID.
447466 Ok ( _) => (
@@ -491,14 +510,6 @@ impl<'tcx> CodegenCx<'tcx> {
491510 vs layout:\n {value_layout:#?}",
492511 entry_arg_abi. layout. ty
493512 ) ;
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- }
502513 // FIXME(eddyb) should this talk about "typed buffers" instead of "interface blocks"?
503514 // FIXME(eddyb) should we talk about "descriptor indexing" or
504515 // actually use more reasonable terms like "resource arrays"?
@@ -621,8 +632,8 @@ impl<'tcx> CodegenCx<'tcx> {
621632 }
622633 }
623634
624- let value_len = if is_pair {
625- // We've already emitted an error, fill in a placeholder value
635+ let value_len = if is_pair && is_unsized {
636+ // For wide references (e.g., slices), the second component is a length.
626637 Some ( bx. undef ( self . type_isize ( ) ) )
627638 } else {
628639 None
@@ -645,21 +656,54 @@ impl<'tcx> CodegenCx<'tcx> {
645656 _ => unreachable ! ( ) ,
646657 }
647658 } else {
648- assert_matches ! ( entry_arg_abi. mode, PassMode :: Direct ( _) ) ;
649-
650- let value = match storage_class {
651- Ok ( _) => {
659+ match entry_arg_abi. mode {
660+ PassMode :: Direct ( _) => {
661+ let value = match storage_class {
662+ Ok ( _) => {
663+ assert_eq ! ( storage_class, Ok ( StorageClass :: Input ) ) ;
664+ bx. load (
665+ entry_arg_abi. layout . spirv_type ( hir_param. ty_span , bx) ,
666+ value_ptr. unwrap ( ) ,
667+ entry_arg_abi. layout . align . abi ,
668+ )
669+ }
670+ Err ( SpecConstant { .. } ) => {
671+ spec_const_id. unwrap ( ) . with_type ( value_spirv_type)
672+ }
673+ } ;
674+ call_args. push ( value) ;
675+ assert_eq ! ( value_len, None ) ;
676+ }
677+ PassMode :: Pair ( ..) => {
678+ // Load both elements of the scalar pair from the input variable.
652679 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- )
680+ let layout = entry_arg_abi. layout ;
681+ let ( a, b) = match layout. backend_repr {
682+ rustc_abi:: BackendRepr :: ScalarPair ( a, b) => ( a, b) ,
683+ other => span_bug ! (
684+ hir_param. ty_span,
685+ "ScalarPair expected for entry param, found {other:?}"
686+ ) ,
687+ } ;
688+ let b_offset = a
689+ . primitive ( )
690+ . size ( self )
691+ . align_to ( b. primitive ( ) . align ( self ) . abi ) ;
692+
693+ let elem0_ty = self . scalar_pair_element_backend_type ( layout, 0 , false ) ;
694+ let elem1_ty = self . scalar_pair_element_backend_type ( layout, 1 , false ) ;
695+
696+ let base_ptr = value_ptr. unwrap ( ) ;
697+ let ptr1 = bx. inbounds_ptradd ( base_ptr, self . const_usize ( b_offset. bytes ( ) ) ) ;
698+
699+ let v0 = bx. load ( elem0_ty, base_ptr, layout. align . abi ) ;
700+ let v1 = bx. load ( elem1_ty, ptr1, layout. align . restrict_for_offset ( b_offset) ) ;
701+ call_args. push ( v0) ;
702+ call_args. push ( v1) ;
703+ assert_eq ! ( value_len, None ) ;
658704 }
659- Err ( SpecConstant { .. } ) => spec_const_id. unwrap ( ) . with_type ( value_spirv_type) ,
660- } ;
661- call_args. push ( value) ;
662- assert_eq ! ( value_len, None ) ;
705+ _ => unreachable ! ( ) ,
706+ }
663707 }
664708
665709 // FIXME(eddyb) check whether the storage class is compatible with the
0 commit comments