@@ -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;
@@ -87,21 +90,7 @@ impl<'tcx> CodegenCx<'tcx> {
87
90
for ( arg_abi, hir_param) in fn_abi. args . iter ( ) . zip ( hir_params) {
88
91
match arg_abi. mode {
89
92
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 ( ..) => { }
105
94
// FIXME(eddyb) support these (by just ignoring them) - if there
106
95
// is any validation concern, it should be done on the types.
107
96
PassMode :: Ignore => self . tcx . dcx ( ) . span_fatal (
@@ -442,6 +431,36 @@ impl<'tcx> CodegenCx<'tcx> {
442
431
} = self . entry_param_deduce_from_rust_ref_or_value ( entry_arg_abi. layout , hir_param, & attrs) ;
443
432
let value_spirv_type = value_layout. spirv_type ( hir_param. ty_span , self ) ;
444
433
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
+
445
464
let ( var_id, spec_const_id) = match storage_class {
446
465
// Pre-allocate the module-scoped `OpVariable` *Result* ID.
447
466
Ok ( _) => (
@@ -491,14 +510,6 @@ impl<'tcx> CodegenCx<'tcx> {
491
510
vs layout:\n {value_layout:#?}",
492
511
entry_arg_abi. layout. ty
493
512
) ;
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
513
// FIXME(eddyb) should this talk about "typed buffers" instead of "interface blocks"?
503
514
// FIXME(eddyb) should we talk about "descriptor indexing" or
504
515
// actually use more reasonable terms like "resource arrays"?
@@ -621,8 +632,8 @@ impl<'tcx> CodegenCx<'tcx> {
621
632
}
622
633
}
623
634
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.
626
637
Some ( bx. undef ( self . type_isize ( ) ) )
627
638
} else {
628
639
None
@@ -645,21 +656,54 @@ impl<'tcx> CodegenCx<'tcx> {
645
656
_ => unreachable ! ( ) ,
646
657
}
647
658
} 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.
652
679
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 ) ;
658
704
}
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
+ }
663
707
}
664
708
665
709
// FIXME(eddyb) check whether the storage class is compatible with the
0 commit comments