mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-22 06:45:13 +00:00
Simplify FnAbi
handling for the fewer PassMode
s possible now.
This commit is contained in:
parent
6d43d60142
commit
2dc88f26ac
@ -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);
|
||||
}
|
||||
|
@ -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,17 +101,10 @@ 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)
|
||||
}
|
||||
}
|
||||
|
||||
sym::prefetch_read_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 let PassMode::Cast(_ty) = fn_abi.ret.mode {
|
||||
self.fatal("TODO: PassMode::Cast not implemented yet in intrinsics");
|
||||
} else {
|
||||
assert_matches!(fn_abi.ret.mode, PassMode::Direct(_) | PassMode::Pair(..));
|
||||
OperandRef::from_immediate_or_packed_pair(self, value, result.layout)
|
||||
.val
|
||||
.store(self, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn abort(&mut self) {
|
||||
// HACK(eddyb) there is no `abort` or `trap` instruction in SPIR-V,
|
||||
|
@ -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,21 +308,17 @@ 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 {
|
||||
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
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn arg_memory_ty(&self, arg_abi: &ArgAbi<'tcx, Ty<'tcx>>) -> Self::Type {
|
||||
|
@ -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!("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 {
|
||||
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(
|
||||
let value = bx.load(
|
||||
entry_arg_abi.layout.spirv_type(hir_param.ty_span, bx),
|
||||
value_ptr,
|
||||
entry_arg_abi.layout.align.abi,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
);
|
||||
call_args.push(value);
|
||||
assert_eq!(value_len, None);
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user