Simplify FnAbi handling for the fewer PassModes possible now.

This commit is contained in:
Eduard-Mihai Burtescu 2021-10-12 15:39:06 +03:00 committed by Eduard-Mihai Burtescu
parent 6d43d60142
commit 2dc88f26ac
5 changed files with 96 additions and 204 deletions

View File

@ -19,7 +19,7 @@ use rustc_middle::{bug, span_bug};
use rustc_span::def_id::DefId; use rustc_span::def_id::DefId;
use rustc_span::Span; use rustc_span::Span;
use rustc_span::DUMMY_SP; 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::abi::{Abi, Align, FieldsShape, Primitive, Scalar, Size, VariantIdx, Variants};
use rustc_target::spec::abi::Abi as SpecAbi; use rustc_target::spec::abi::Abi as SpecAbi;
use std::cell::RefCell; 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>> { impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
fn spirv_type(&self, span: Span, cx: &CodegenCx<'tcx>) -> Word { fn spirv_type(&self, span: Span, cx: &CodegenCx<'tcx>) -> Word {
let mut argument_types = Vec::new(); let mut argument_types = Vec::new();
@ -326,14 +245,11 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
PassMode::Direct(_) | PassMode::Pair(..) => { PassMode::Direct(_) | PassMode::Pair(..) => {
self.ret.layout.spirv_type_immediate(span, cx) self.ret.layout.spirv_type_immediate(span, cx)
} }
PassMode::Cast(cast_target) => cast_target.spirv_type(span, cx), PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!(
PassMode::Indirect { .. } => { span,
let pointee = self.ret.layout.spirv_type(span, cx); "query hooks should've made this `PassMode` impossible: {:#?}",
let pointer = SpirvType::Pointer { pointee }.def(span, cx); self.ret
// Important: the return pointer comes *first*, not last. ),
argument_types.push(pointer);
SpirvType::Void.def(span, cx)
}
}; };
for arg in &self.args { for arg in &self.args {
@ -349,27 +265,11 @@ impl<'tcx> ConvSpirvType<'tcx> for FnAbi<'tcx, Ty<'tcx>> {
)); ));
continue; continue;
} }
PassMode::Cast(cast_target) => cast_target.spirv_type(span, cx), PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!(
PassMode::Indirect { span,
extra_attrs: Some(_), "query hooks should've made this `PassMode` impossible: {:#?}",
.. arg
} => { ),
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)
}
}; };
argument_types.push(arg_type); argument_types.push(arg_type);
} }

View File

@ -13,6 +13,7 @@ use rustc_middle::ty::{FnDef, Instance, ParamEnv, Ty, TyKind};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::sym; use rustc_span::sym;
use rustc_target::abi::call::{FnAbi, PassMode}; 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)> { fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_>) -> Option<(u64, bool)> {
match ty.kind() { match ty.kind() {
@ -100,17 +101,10 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
sym::volatile_load | sym::unaligned_volatile_load => { sym::volatile_load | sym::unaligned_volatile_load => {
let ptr = args[0].immediate(); 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 layout = self.layout_of(substs.type_at(0));
let load = self.volatile_load(layout.spirv_type(self.span(), self), ptr); let load = self.volatile_load(layout.spirv_type(self.span(), self), ptr);
self.to_immediate(load, layout) self.to_immediate(load, layout)
} }
}
sym::prefetch_read_data sym::prefetch_read_data
| sym::prefetch_write_data | sym::prefetch_write_data
@ -330,15 +324,12 @@ impl<'a, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'tcx> {
}; };
if !fn_abi.ret.is_ignore() { if !fn_abi.ret.is_ignore() {
if let PassMode::Cast(_ty) = fn_abi.ret.mode { assert_matches!(fn_abi.ret.mode, PassMode::Direct(_) | PassMode::Pair(..));
self.fatal("TODO: PassMode::Cast not implemented yet in intrinsics");
} else {
OperandRef::from_immediate_or_packed_pair(self, value, result.layout) OperandRef::from_immediate_or_packed_pair(self, value, result.layout)
.val .val
.store(self, result); .store(self, result);
} }
} }
}
fn abort(&mut self) { fn abort(&mut self) {
// HACK(eddyb) there is no `abort` or `trap` instruction in SPIR-V, // HACK(eddyb) there is no `abort` or `trap` instruction in SPIR-V,

View File

@ -24,6 +24,7 @@ use rustc_errors::DiagnosticBuilder;
use rustc_middle::mir::coverage::{ use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op, CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId, Op,
}; };
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{ use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers,
TyAndLayout, TyAndLayout,
@ -286,27 +287,18 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> {
val val
} }
match arg_abi.mode { match arg_abi.mode {
PassMode::Ignore => (), PassMode::Ignore => {}
PassMode::Direct(_) => {
OperandValue::Immediate(next(self, idx)).store(self, dst);
}
PassMode::Pair(..) => { PassMode::Pair(..) => {
OperandValue::Pair(next(self, idx), next(self, idx)).store(self, dst); OperandValue::Pair(next(self, idx), next(self, idx)).store(self, dst);
} }
PassMode::Indirect { PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!(
extra_attrs: Some(_), self.span(),
.. "query hooks should've made this `PassMode` impossible: {:#?}",
} => OperandValue::Ref( arg_abi
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);
}
} }
} }
@ -316,21 +308,17 @@ impl<'a, 'tcx> ArgAbiMethods<'tcx> for Builder<'a, 'tcx> {
val: Self::Value, val: Self::Value,
dst: PlaceRef<'tcx, Self::Value>, dst: PlaceRef<'tcx, Self::Value>,
) { ) {
if arg_abi.is_ignore() { match arg_abi.mode {
return; PassMode::Ignore => {}
} PassMode::Direct(_) | PassMode::Pair(..) => {
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); OperandValue::Immediate(val).store(self, dst);
} }
PassMode::Cast(_) | PassMode::Indirect { .. } => span_bug!(
self.span(),
"query hooks should've made this `PassMode` impossible: {:#?}",
arg_abi
),
}
} }
fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type { fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type {

View File

@ -11,13 +11,12 @@ use rspirv::spirv::{
use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods}; use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_middle::span_bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout}; 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_span::Span;
use rustc_target::abi::{ use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode};
call::{ArgAbi, ArgAttribute, ArgAttributes, FnAbi, PassMode}, use std::assert_matches::assert_matches;
Size,
};
impl<'tcx> CodegenCx<'tcx> { impl<'tcx> CodegenCx<'tcx> {
// Entry points declare their "interface" (all uniforms, inputs, outputs, etc.) as parameters. // 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)); let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(fn_hir_id));
body.params body.params
}; };
const EMPTY: ArgAttribute = ArgAttribute::empty(); for (arg_abi, hir_param) in fn_abi.args.iter().zip(hir_params) {
for (abi, hir_param) in fn_abi.args.iter().zip(hir_params) { match arg_abi.mode {
match abi.mode { PassMode::Direct(_) => {}
PassMode::Direct(_) PassMode::Pair(..) => {
| PassMode::Indirect { .. } // FIXME(eddyb) implement `ScalarPair` `Input`s, or change
// plain DST/RTA/VLA // the `FnAbi` readjustment to only use `PassMode::Pair` for
| PassMode::Pair( // pointers to `!Sized` types, but not other `ScalarPair`s.
ArgAttributes { if !matches!(arg_abi.layout.ty.kind(), ty::Ref(..)) {
pointee_size: Size::ZERO, self.tcx.sess.span_err(
..
},
ArgAttributes { regular: EMPTY, .. },
)
// DST struct with fields before the DST member
| PassMode::Pair(
ArgAttributes { .. },
ArgAttributes {
pointee_size: Size::ZERO,
..
},
) => {}
_ => self.tcx.sess.span_err(
hir_param.ty_span, hir_param.ty_span,
&format!("PassMode {:?} invalid for entry point parameter", abi.mode), &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!(
"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 { } else {
self.tcx.sess.span_err( self.tcx.sess.span_err(
span, span,
&format!( &format!(
"PassMode {:?} invalid for entry point return type", "entry point should return `()`, not `{}`",
fn_abi.ret.mode fn_abi.ret.layout.ty
), ),
); );
} }
// let execution_model = entry.execution_model; // let execution_model = entry.execution_model;
let fn_id = self.shader_entry_stub( let fn_id = self.shader_entry_stub(
span, span,
@ -168,7 +177,7 @@ impl<'tcx> CodegenCx<'tcx> {
// FIXME(eddyb) also check the type for compatibility with being // FIXME(eddyb) also check the type for compatibility with being
// part of the interface, including potentially `Sync`ness etc. // part of the interface, including potentially `Sync`ness etc.
let (value_ty, mutbl, is_ref) = match *layout.ty.kind() { 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), _ => (layout.ty, hir::Mutability::Not, false),
}; };
let spirv_ty = self.layout_of(value_ty).spirv_type(hir_param.ty_span, self); 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, // Compute call argument(s) to match what the Rust entry `fn` expects,
// starting from the `value_ptr` pointing to a `value_spirv_type` // 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). // (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); call_args.push(value_ptr);
match entry_arg_abi.mode { match entry_arg_abi.mode {
PassMode::Direct(_) => assert_eq!(value_len, None), PassMode::Direct(_) => assert_eq!(value_len, None),
@ -405,16 +414,14 @@ impl<'tcx> CodegenCx<'tcx> {
} }
} else { } else {
assert_eq!(storage_class, StorageClass::Input); assert_eq!(storage_class, StorageClass::Input);
assert_matches!(entry_arg_abi.mode, PassMode::Direct(_));
call_args.push(match entry_arg_abi.mode { let value = bx.load(
PassMode::Indirect { .. } => value_ptr,
PassMode::Direct(_) => bx.load(
entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx), entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx),
value_ptr, value_ptr,
entry_arg_abi.layout.align.abi, entry_arg_abi.layout.align.abi,
), );
_ => unreachable!(), call_args.push(value);
});
assert_eq!(value_len, None); assert_eq!(value_len, None);
} }

View File

@ -72,7 +72,10 @@ impl<'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'tcx> {
} }
fn cast_backend_type(&self, ty: &CastTarget) -> Self::Type { 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 { 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 { 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 { fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Self::Type {