1use rustc_abi::{
2AddressSpace, BackendRepr, CanonAbi, HasDataLayout, Reg, RegKind, TyAbiInterface, TyAndLayout,
3};
45use crate::callconv::{FnAbi, Uniform};
67// For reference, see llvm-project/clang/lib/CodeGen/Targets/AMDGPU.cpp
89/// If the given type is a (potentially nested) struct containing a single scalar, return
10/// a `Uniform` for the contained, single element.
11fn single_element_struct_to_reg<'a, Ty, C>(cx: &C, ty: TyAndLayout<'a, Ty>) -> Option<Uniform>
12where
13Ty: TyAbiInterface<'a, C> + Copy,
14 C: HasDataLayout,
15{
16if !ty.is_aggregate() {
{
::core::panicking::panic_fmt(format_args!("Only handles aggregate types"));
}
};assert!(ty.is_aggregate(), "Only handles aggregate types");
17if ty.layout.fields.count() != 1 {
18return None;
19 }
20let field = ty.field(cx, 0);
21match field.backend_repr {
22 BackendRepr::SimdScalableVector { .. } => {
::core::panicking::panic_fmt(format_args!("scalable vectors are unsupported"));
}panic!("scalable vectors are unsupported"),
23 BackendRepr::Scalar(_) => {
24// Check that the size is the same as the size for ty, so no extra padding
25let size = field.layout.size.bytes();
26if ty.layout.size.bytes() != size {
27return None;
28 }
2930// clang passes the inner type directly, we emulate it with fitting integer types
31match size {
321 => Some(Uniform::new(Reg::i8(), field.layout.size)),
332 => Some(Uniform::new(Reg::i16(), field.layout.size)),
344 => Some(Uniform::new(Reg::i32(), field.layout.size)),
358 => Some(Uniform::new(Reg::i64(), field.layout.size)),
3616 => Some(Uniform::new(Reg::i128(), field.layout.size)),
37 s => {
::core::panicking::panic_fmt(format_args!("Unhandled scalar of size {0} in amdgpu gpu-kernel ABI",
s));
}panic!("Unhandled scalar of size {s} in amdgpu gpu-kernel ABI"),
38 }
39 }
40 BackendRepr::SimdVector { element, .. } => {
41// Check that the size is the same as the size for ty, so no extra padding
42let size = field.layout.size.bytes();
43if ty.layout.size.bytes() != size {
44return None;
45 }
4647// clang passes the inner type directly, we emulate it with a vector of the same type.
48 // The size is rounded up to the size of the complete type (including alignment).
49let reg = Reg {
50 kind: RegKind::Vector { hint_vector_elem: element.primitive() },
51 size: field.layout.size,
52 };
53Some(Uniform::new(reg, field.layout.size))
54 }
55 BackendRepr::Memory { .. } => single_element_struct_to_reg(cx, field),
56 BackendRepr::ScalarPair { .. } => None,
57 }
58}
5960pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
61where
62Ty: TyAbiInterface<'a, C> + Copy,
63 C: HasDataLayout,
64{
65// Kernels cannot return values, so do not handle return types
6667 // Try to fill first registers with values and pass by_ref pointers for later indirect arguments
68for arg in fn_abi.args.iter_mut() {
69if arg.is_ignore() {
70continue;
71 }
72if fn_abi.conv == CanonAbi::GpuKernel {
73if arg.layout.is_aggregate() {
74if let Some(uniform) = single_element_struct_to_reg(cx, arg.layout) {
75// Single element structs are passed directly as the inner type
76arg.cast_to(uniform);
77 } else {
78// All other aggregates are passed as by_ref pointer in the constant address space
79arg.pass_amdgpu_kernel_arg(Some(AddressSpace::GPU_CONSTANT));
80 }
81 }
82 } else {
83// FIXME: C ABI is not yet implemented
84}
85 }
86}