Skip to main content

rustc_target/callconv/
nvptx64.rs

1use arrayvec::ArrayVec;
2use rustc_abi::{HasDataLayout, Reg, Size, TyAbiInterface};
3
4use super::CastTarget;
5use crate::callconv::{ArgAbi, FnAbi, Uniform};
6
7fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) {
8    if ret.layout.is_aggregate() && ret.layout.is_sized() {
9        classify_aggregate(ret)
10    } else if ret.layout.size.bits() < 32 && ret.layout.is_sized() {
11        ret.extend_integer_width_to(32);
12    }
13}
14
15fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
16where
17    Ty: TyAbiInterface<'a, C> + Copy,
18{
19    if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
20        arg.make_indirect();
21        return;
22    }
23    if arg.layout.is_aggregate() && arg.layout.is_sized() {
24        classify_aggregate(arg)
25    } else if arg.layout.size.bits() < 32 && arg.layout.is_sized() {
26        arg.extend_integer_width_to(32);
27    }
28}
29
30/// the pass mode used for aggregates in arg and ret position
31fn classify_aggregate<Ty>(arg: &mut ArgAbi<'_, Ty>) {
32    let align_bytes = arg.layout.align.bytes();
33    let size = arg.layout.size;
34
35    let reg = match align_bytes {
36        1 => Reg::i8(),
37        2 => Reg::i16(),
38        4 => Reg::i32(),
39        8 => Reg::i64(),
40        16 => Reg::i128(),
41        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Align is given as power of 2 no larger than 16 bytes")));
}unreachable!("Align is given as power of 2 no larger than 16 bytes"),
42    };
43
44    if align_bytes == size.bytes() {
45        let mut prefix = ArrayVec::new();
46        prefix.push(reg);
47        arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(Reg::i8(), Size::ZERO)));
48    } else {
49        arg.cast_to(Uniform::new(reg, size));
50    }
51}
52
53fn classify_arg_kernel<'a, Ty, C>(_cx: &C, arg: &mut ArgAbi<'a, Ty>)
54where
55    Ty: TyAbiInterface<'a, C> + Copy,
56    C: HasDataLayout,
57{
58    match arg.mode {
59        super::PassMode::Ignore | super::PassMode::Direct(_) => return,
60        super::PassMode::Pair(_, _) => {}
61        super::PassMode::Cast { .. } => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
62        super::PassMode::Indirect { .. } => {}
63    }
64
65    // FIXME only allow structs and wide pointers here
66    // panic!(
67    //     "`extern \"ptx-kernel\"` doesn't allow passing types other than primitives and structs"
68    // );
69
70    let align_bytes = arg.layout.align.bytes();
71
72    let unit = match align_bytes {
73        1 => Reg::i8(),
74        2 => Reg::i16(),
75        4 => Reg::i32(),
76        8 => Reg::i64(),
77        16 => Reg::i128(),
78        _ => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("Align is given as power of 2 no larger than 16 bytes")));
}unreachable!("Align is given as power of 2 no larger than 16 bytes"),
79    };
80    if arg.layout.size.bytes() / align_bytes == 1 {
81        // Make sure we pass the struct as array at the LLVM IR level and not as a single integer.
82        let mut prefix = ArrayVec::new();
83        prefix.push(unit);
84        arg.cast_to(CastTarget::prefixed(prefix, Uniform::new(unit, Size::ZERO)));
85    } else {
86        arg.cast_to(Uniform::new(unit, arg.layout.size));
87    }
88}
89
90pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
91where
92    Ty: TyAbiInterface<'a, C> + Copy,
93{
94    if !fn_abi.ret.is_ignore() {
95        classify_ret(&mut fn_abi.ret);
96    }
97
98    for arg in fn_abi.args.iter_mut() {
99        if arg.is_ignore() {
100            continue;
101        }
102        classify_arg(cx, arg);
103    }
104}
105
106pub(crate) fn compute_ptx_kernel_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
107where
108    Ty: TyAbiInterface<'a, C> + Copy,
109    C: HasDataLayout,
110{
111    if !fn_abi.ret.layout.is_unit() && !fn_abi.ret.layout.is_never() {
112        {
    ::core::panicking::panic_fmt(format_args!("Kernels should not return anything other than () or !"));
};panic!("Kernels should not return anything other than () or !");
113    }
114
115    for arg in fn_abi.args.iter_mut() {
116        if arg.is_ignore() {
117            continue;
118        }
119        classify_arg_kernel(cx, arg);
120    }
121}