rustc_target/callconv/
wasm.rs1use rustc_abi::{
2 BackendRepr, Float, HasDataLayout, Integer, Primitive, Reg, RegKind, TagEncoding,
3 TyAbiInterface, TyAndLayout, Variants,
4};
5
6use crate::callconv::{ArgAbi, FnAbi};
7
8fn singleton_scalar<'a, Ty, C>(cx: &C, layout: TyAndLayout<'a, Ty>) -> Option<Reg>
9where
10 Ty: TyAbiInterface<'a, C> + Copy,
11 C: HasDataLayout,
12{
13 if !(layout.is_aggregate() || layout.peel_transparent_wrappers(cx).is_enum()) {
15 let BackendRepr::Scalar(scalar) = layout.backend_repr else {
16 return None;
17 };
18 return Some(Reg { kind: RegKind::from_primitive(scalar.primitive()), size: layout.size });
19 }
20
21 if let Variants::Multiple { tag, tag_encoding: TagEncoding::Direct, variants, .. } =
29 &layout.variants
30 {
31 if variants.iter().all(|x| x.field_offsets.is_empty()) {
32 return Some(Reg { kind: RegKind::from_primitive(tag.primitive()), size: layout.size });
33 }
34 return None;
35 }
36
37 let mut found = None;
38 for i in 0..layout.fields.count() {
39 let field = layout.field(cx, i);
40 if field.is_zst() {
41 continue;
42 }
43 if found.is_some() {
44 return None;
46 }
47 found = Some(singleton_scalar(cx, field)?);
48 }
49
50 found.filter(|scalar| scalar.size == layout.size)
52}
53
54fn is_aggregate_for_abi<'a, Ty, C>(cx: &C, val: &mut ArgAbi<'a, Ty>) -> bool
59where
60 Ty: TyAbiInterface<'a, C> + Copy,
61 C: HasDataLayout,
62{
63 if !(val.layout.is_aggregate() || val.layout.peel_transparent_wrappers(cx).is_enum()) {
66 return false;
67 }
68
69 let Some(scalar) = singleton_scalar(cx, val.layout) else {
70 return true;
71 };
72
73 if !val.layout.is_aggregate() {
75 return false;
76 }
77
78 val.cast_to(scalar);
79 false
80}
81
82fn classify_ret<'a, Ty, C>(cx: &C, ret: &mut ArgAbi<'a, Ty>)
83where
84 Ty: TyAbiInterface<'a, C> + Copy,
85 C: HasDataLayout,
86{
87 if let BackendRepr::Scalar(scalar) = ret.layout.backend_repr
89 && #[allow(non_exhaustive_omitted_patterns)] match scalar.primitive() {
Primitive::Int(Integer::I128, _) | Primitive::Float(Float::F128) => true,
_ => false,
}matches!(
90 scalar.primitive(),
91 Primitive::Int(Integer::I128, _) | Primitive::Float(Float::F128)
92 )
93 {
94 ret.make_indirect();
95 return;
96 }
97
98 ret.extend_integer_width_to(32);
99 if is_aggregate_for_abi(cx, ret) {
100 ret.make_indirect();
101 }
102}
103
104fn classify_arg<'a, Ty, C>(cx: &C, arg: &mut ArgAbi<'a, Ty>)
105where
106 Ty: TyAbiInterface<'a, C> + Copy,
107 C: HasDataLayout,
108{
109 if !arg.layout.is_sized() {
110 return;
112 }
113 if arg.layout.pass_indirectly_in_non_rustic_abis(cx) {
114 arg.make_indirect();
115 return;
116 }
117 arg.extend_integer_width_to(32);
118 if is_aggregate_for_abi(cx, arg) {
119 arg.make_indirect();
120 }
121}
122
123pub(crate) fn compute_abi_info<'a, Ty, C>(cx: &C, fn_abi: &mut FnAbi<'a, Ty>)
125where
126 Ty: TyAbiInterface<'a, C> + Copy,
127 C: HasDataLayout,
128{
129 if !fn_abi.ret.is_ignore() {
130 classify_ret(cx, &mut fn_abi.ret);
131 }
132
133 for arg in fn_abi.args.iter_mut() {
134 if arg.is_ignore() {
135 continue;
136 }
137 classify_arg(cx, arg);
138 }
139}