diff --git a/crates/rustc_codegen_spirv/src/abi.rs b/crates/rustc_codegen_spirv/src/abi.rs index a473c40dd5..003227e1cc 100644 --- a/crates/rustc_codegen_spirv/src/abi.rs +++ b/crates/rustc_codegen_spirv/src/abi.rs @@ -19,7 +19,7 @@ use rustc_middle::{bug, span_bug}; use rustc_span::def_id::DefId; use rustc_span::Span; use rustc_span::DUMMY_SP; -use rustc_target::abi::call::{ArgAbi, ArgAttributes, CastTarget, FnAbi, PassMode, Reg, RegKind}; +use rustc_target::abi::call::{ArgAbi, ArgAttributes, FnAbi, PassMode}; use rustc_target::abi::{Abi, Align, FieldsShape, Primitive, Scalar, Size, VariantIdx, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; use std::cell::RefCell; @@ -236,87 +236,6 @@ impl<'tcx> ConvSpirvType<'tcx> for PointeeTy<'tcx> { } } -impl<'tcx> ConvSpirvType<'tcx> for Reg { - fn spirv_type(&self, span: Span, cx: &CodegenCx<'tcx>) -> Word { - match self.kind { - RegKind::Integer => SpirvType::Integer(self.size.bits() as u32, false).def(span, cx), - RegKind::Float => SpirvType::Float(self.size.bits() as u32).def(span, cx), - RegKind::Vector => SpirvType::Vector { - element: SpirvType::Integer(8, false).def(span, cx), - count: self.size.bytes() as u32, - } - .def(span, cx), - } - } -} - -impl<'tcx> ConvSpirvType<'tcx> for CastTarget { - fn spirv_type(&self, span: Span, cx: &CodegenCx<'tcx>) -> Word { - let rest_ll_unit = self.rest.unit.spirv_type(span, cx); - let (rest_count, rem_bytes) = if self.rest.unit.size.bytes() == 0 { - (0, 0) - } else { - ( - self.rest.total.bytes() / self.rest.unit.size.bytes(), - self.rest.total.bytes() % self.rest.unit.size.bytes(), - ) - }; - - if self.prefix.iter().all(|x| x.is_none()) { - // Simplify to a single unit when there is no prefix and size <= unit size - if self.rest.total <= self.rest.unit.size { - return rest_ll_unit; - } - - // Simplify to array when all chunks are the same size and type - if rem_bytes == 0 { - return SpirvType::Array { - element: rest_ll_unit, - count: cx.constant_u32(span, rest_count as u32), - } - .def(span, cx); - } - } - - // Create list of fields in the main structure - let mut args: Vec<_> = self - .prefix - .iter() - .flatten() - .map(|&kind| { - Reg { - kind, - size: self.prefix_chunk_size, - } - .spirv_type(span, cx) - }) - .chain((0..rest_count).map(|_| rest_ll_unit)) - .collect(); - - // Append final integer - if rem_bytes != 0 { - // Only integers can be really split further. - assert_eq!(self.rest.unit.kind, RegKind::Integer); - args.push(SpirvType::Integer(rem_bytes as u32 * 8, false).def(span, cx)); - } - - let size = Some(self.size(cx)); - let align = self.align(cx); - let (field_offsets, computed_size, computed_align) = auto_struct_layout(cx, &args); - assert_eq!(size, computed_size, "{:#?}", self); - assert_eq!(align, computed_align, "{:#?}", self); - SpirvType::Adt { - def_id: None, - size, - align, - field_types: args, - field_offsets, - field_names: None, - } - .def(span, cx) - } -} - impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> { fn spirv_type(&self, span: Span, cx: &CodegenCx<'tcx>) -> Word { let mut argument_types = Vec::new(); @@ -326,14 +245,11 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> { PassMode::Direct(_) | PassMode::Pair(..) => { self.ret.layout.spirv_type_immediate(span, cx) } - PassMode::Cast(cast_target) => cast_target.spirv_type(span, cx), - PassMode::Indirect { .. } => { - let pointee = self.ret.layout.spirv_type(span, cx); - let pointer = SpirvType::Pointer { pointee }.def(span, cx); - // Important: the return pointer comes *first*, not last. - argument_types.push(pointer); - SpirvType::Void.def(span, cx) - } + PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!( + span, + "query hooks should've made this `PassMode` impossible: {:#?}", + self.ret + ), }; for arg in &self.args { @@ -349,27 +265,11 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> { )); continue; } - PassMode::Cast(cast_target) => cast_target.spirv_type(span, cx), - PassMode::Indirect { - extra_attrs: Some(_), - .. - } => { - let ptr_ty = cx.tcx.mk_mut_ptr(arg.layout.ty); - let ptr_layout = cx.layout_of(ptr_ty); - argument_types.push(scalar_pair_element_backend_type( - cx, span, ptr_layout, 0, true, - )); - argument_types.push(scalar_pair_element_backend_type( - cx, span, ptr_layout, 1, true, - )); - continue; - } - PassMode::Indirect { - extra_attrs: None, .. - } => { - let pointee = arg.layout.spirv_type(span, cx); - SpirvType::Pointer { pointee }.def(span, cx) - } + PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!( + span, + "query hooks should've made this `PassMode` impossible: {:#?}", + arg + ), }; argument_types.push(arg_type); } diff --git a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs index a12d4bfb7b..3633b6abb4 100644 --- a/crates/rustc_codegen_spirv/src/builder/intrinsics.rs +++ b/crates/rustc_codegen_spirv/src/builder/intrinsics.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{FnDef, Instance, ParamEnv, Ty, TyKind}; use rustc_span::source_map::Span; use rustc_span::sym; use rustc_target::abi::call::{FnAbi, PassMode}; +use std::assert_matches::assert_matches; fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_>) -> Option<(u64, bool)> { match ty.kind() { @@ -100,16 +101,9 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { sym::volatile_load | sym::unaligned_volatile_load => { let ptr = args[0].immediate(); - if let PassMode::Cast(ty) = fn_abi.ret.mode { - let pointee = ty.spirv_type(self.span(), self); - let pointer = SpirvType::Pointer { pointee }.def(self.span(), self); - let ptr = self.pointercast(ptr, pointer); - self.volatile_load(pointee, ptr) - } else { - let layout = self.layout_of(substs.type_at(0)); - let load = self.volatile_load(layout.spirv_type(self.span(), self), ptr); - self.to_immediate(load, layout) - } + let layout = self.layout_of(substs.type_at(0)); + let load = self.volatile_load(layout.spirv_type(self.span(), self), ptr); + self.to_immediate(load, layout) } sym::prefetch_read_data @@ -330,13 +324,10 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> { }; if !fn_abi.ret.is_ignore() { - if let PassMode::Cast(_ty) = fn_abi.ret.mode { - self.fatal("TODO: PassMode::Cast not implemented yet in intrinsics"); - } else { - OperandRef::from_immediate_or_packed_pair(self, value, result.layout) - .val - .store(self, result); - } + assert_matches!(fn_abi.ret.mode, PassMode::Direct(_) | PassMode::Pair(..)); + OperandRef::from_immediate_or_packed_pair(self, value, result.layout) + .val + .store(self, result); } } diff --git a/crates/rustc_codegen_spirv/src/builder/mod.rs b/crates/rustc_codegen_spirv/src/builder/mod.rs index 775ca382d2..5a8995de62 100644 --- a/crates/rustc_codegen_spirv/src/builder/mod.rs +++ b/crates/rustc_codegen_spirv/src/builder/mod.rs @@ -24,6 +24,7 @@ use rustc_errors::DiagnosticBuilder; use rustc_middle::mir::coverage::{ CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op, }; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{ FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout, @@ -286,27 +287,18 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> { val } match arg_abi.mode { - PassMode::Ignore => (), + PassMode::Ignore => {} + PassMode::Direct(_) => { + OperandValue::Immediate(next(self, idx)).store(self, dst); + } PassMode::Pair(..) => { OperandValue::Pair(next(self, idx), next(self, idx)).store(self, dst); } - PassMode::Indirect { - extra_attrs: Some(_), - .. - } => OperandValue::Ref( - next(self, idx), - Some(next(self, idx)), - arg_abi.layout.align.abi, - ) - .store(self, dst), - PassMode::Direct(_) - | PassMode::Indirect { - extra_attrs: None, .. - } - | PassMode::Cast(_) => { - let next_arg = next(self, idx); - self.store_arg(arg_abi, next_arg, dst); - } + PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!( + self.span(), + "query hooks should've made this `PassMode` impossible: {:#?}", + arg_abi + ), } } @@ -316,20 +308,16 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> { val: Self::Value, dst: PlaceRef<'tcx, Self::Value>, ) { - if arg_abi.is_ignore() { - return; - } - if arg_abi.is_sized_indirect() { - OperandValue::Ref(val, None, arg_abi.layout.align.abi).store(self, dst); - } else if arg_abi.is_unsized_indirect() { - self.fatal("unsized `ArgAbi` must be handled through `store_fn_arg`"); - } else if let PassMode::Cast(cast) = arg_abi.mode { - let cast_ty = cast.spirv_type(self.span(), self); - let cast_ptr_ty = SpirvType::Pointer { pointee: cast_ty }.def(self.span(), self); - let cast_dst = self.pointercast(dst.llval, cast_ptr_ty); - self.store(val, cast_dst, arg_abi.layout.align.abi); - } else { - OperandValue::Immediate(val).store(self, dst); + match arg_abi.mode { + PassMode::Ignore => {} + PassMode::Direct(_) | PassMode::Pair(..) => { + OperandValue::Immediate(val).store(self, dst); + } + PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!( + self.span(), + "query hooks should've made this `PassMode` impossible: {:#?}", + arg_abi + ), } } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs index f1d83c2c89..75c8f845fd 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/entry.rs @@ -11,13 +11,12 @@ use rspirv::spirv::{ use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; +use rustc_middle::span_bug; use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; -use rustc_middle::ty::{Instance, Ty, TyKind}; +use rustc_middle::ty::{self, Instance, Ty}; use rustc_span::Span; -use rustc_target::abi::{ - call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode}, - Size, -}; +use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode}; +use std::assert_matches::assert_matches; impl<'tcx> CodegenCx<'tcx> { // Entry points declare their "interface" (all uniforms, inputs, outputs, etc.) as parameters. @@ -47,43 +46,53 @@ impl<'tcx> CodegenCx<'tcx> { let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(fn_hir_id)); body.params }; - const EMPTY: ArgAttribute = ArgAttribute::empty(); - for (abi, hir_param) in fn_abi.args.iter().zip(hir_params) { - match abi.mode { - PassMode::Direct(_) - | PassMode::Indirect { .. } - // plain DST/RTA/VLA - | PassMode::Pair( - ArgAttributes { - pointee_size: Size::ZERO, - .. - }, - ArgAttributes { regular: EMPTY, .. }, - ) - // DST struct with fields before the DST member - | PassMode::Pair( - ArgAttributes { .. }, - ArgAttributes { - pointee_size: Size::ZERO, - .. - }, - ) => {} - _ => self.tcx.sess.span_err( + for (arg_abi, hir_param) in fn_abi.args.iter().zip(hir_params) { + match arg_abi.mode { + PassMode::Direct(_) => {} + PassMode::Pair(..) => { + // FIXME(eddyb) implement `ScalarPair` `Input`s, or change + // the `FnAbi` readjustment to only use `PassMode::Pair` for + // pointers to `!Sized` types, but not other `ScalarPair`s. + if !matches!(arg_abi.layout.ty.kind(), ty::Ref(..)) { + self.tcx.sess.span_err( + hir_param.ty_span, + &format!( + "entry point parameter type not yet supported \ + (`{}` has `ScalarPair` ABI but is not a `&T`)", + arg_abi.layout.ty + ), + ); + } + } + // FIXME(eddyb) support these (by just ignoring them) - if there + // is any validation concern, it should be done on the types. + PassMode::Ignore => self.tcx.sess.span_err( hir_param.ty_span, - &format!("PassMode {:?} invalid for entry point parameter", abi.mode), + &format!( + "entry point parameter type not yet supported \ + (`{}` has size `0`)", + arg_abi.layout.ty + ), + ), + _ => span_bug!( + hir_param.ty_span, + "query hooks should've made this `PassMode` impossible: {:#?}", + arg_abi ), } } - if let PassMode::Ignore = fn_abi.ret.mode { + if fn_abi.ret.layout.ty.is_unit() { + assert_matches!(fn_abi.ret.mode, PassMode::Ignore); } else { self.tcx.sess.span_err( span, &format!( - "PassMode {:?} invalid for entry point return type", - fn_abi.ret.mode + "entry point should return `()`, not `{}`", + fn_abi.ret.layout.ty ), ); } + // let execution_model = entry.execution_model; let fn_id = self.shader_entry_stub( span, @@ -168,7 +177,7 @@ impl<'tcx> CodegenCx<'tcx> { // FIXME(eddyb) also check the type for compatibility with being // part of the interface, including potentially `Sync`ness etc. let (value_ty, mutbl, is_ref) = match *layout.ty.kind() { - TyKind::Ref(_, pointee_ty, mutbl) => (pointee_ty, mutbl, true), + ty::Ref(_, pointee_ty, mutbl) => (pointee_ty, mutbl, true), _ => (layout.ty, hir::Mutability::Not, false), }; let spirv_ty = self.layout_of(value_ty).spirv_type(hir_param.ty_span, self); @@ -396,7 +405,7 @@ impl<'tcx> CodegenCx<'tcx> { // Compute call argument(s) to match what the Rust entry `fn` expects, // starting from the `value_ptr` pointing to a `value_spirv_type` // (e.g. `Input` doesn't use indirection, so we have to load from it). - if let TyKind::Ref(..) = entry_arg_abi.layout.ty.kind() { + if let ty::Ref(..) = entry_arg_abi.layout.ty.kind() { call_args.push(value_ptr); match entry_arg_abi.mode { PassMode::Direct(_) => assert_eq!(value_len, None), @@ -405,16 +414,14 @@ impl<'tcx> CodegenCx<'tcx> { } } else { assert_eq!(storage_class, StorageClass::Input); + assert_matches!(entry_arg_abi.mode, PassMode::Direct(_)); - call_args.push(match entry_arg_abi.mode { - PassMode::Indirect { .. } => value_ptr, - PassMode::Direct(_) => bx.load( - entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx), - value_ptr, - entry_arg_abi.layout.align.abi, - ), - _ => unreachable!(), - }); + let value = bx.load( + entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx), + value_ptr, + entry_arg_abi.layout.align.abi, + ); + call_args.push(value); assert_eq!(value_len, None); } diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs index 3fba937071..379feaac98 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/type_.rs @@ -72,7 +72,10 @@ impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> { } fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type { - ty.spirv_type(DUMMY_SP, self) + bug!( + "cast_backend_type({:?}): query hooks should've made `PassMode::Cast` impossible", + ty + ) } fn fn_decl_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Type { @@ -84,7 +87,10 @@ impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> { } fn reg_backend_type(&self, ty: &Reg) -> Self::Type { - ty.spirv_type(DUMMY_SP, self) + bug!( + "reg_backend_type({:?}): query hooks should've made `PassMode::Cast` impossible", + ty + ) } fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type {