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::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);
}

View File

@ -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);
}
}

View File

@ -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
),
}
}

View File

@ -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);
}

View File

@ -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 {