rustc_monomorphize/mono_checks/
abi_check.rs1use rustc_abi::{BackendRepr, RegKind};
4use rustc_hir::CRATE_HIR_ID;
5use rustc_middle::mir::{self, traversal};
6use rustc_middle::ty::{self, Instance, InstanceKind, Ty, TyCtxt};
7use rustc_session::lint::builtin::ABI_UNSUPPORTED_VECTOR_TYPES;
8use rustc_span::def_id::DefId;
9use rustc_span::{DUMMY_SP, Span, Symbol, sym};
10use rustc_target::callconv::{Conv, FnAbi, PassMode};
11
12use crate::errors;
13
14fn uses_vector_registers(mode: &PassMode, repr: &BackendRepr) -> bool {
15 match mode {
16 PassMode::Ignore | PassMode::Indirect { .. } => false,
17 PassMode::Cast { pad_i32: _, cast } => {
18 cast.prefix.iter().any(|r| r.is_some_and(|x| x.kind == RegKind::Vector))
19 || cast.rest.unit.kind == RegKind::Vector
20 }
21 PassMode::Direct(..) | PassMode::Pair(..) => matches!(repr, BackendRepr::SimdVector { .. }),
22 }
23}
24
25fn do_check_abi<'tcx>(
30 tcx: TyCtxt<'tcx>,
31 abi: &FnAbi<'tcx, Ty<'tcx>>,
32 def_id: DefId,
33 is_call: bool,
34 span: impl Fn() -> Span,
35) {
36 let feature_def = tcx.sess.target.features_for_correct_vector_abi();
37 let codegen_attrs = tcx.codegen_fn_attrs(def_id);
38 let have_feature = |feat: Symbol| {
39 tcx.sess.unstable_target_features.contains(&feat)
40 || codegen_attrs.target_features.iter().any(|x| x.name == feat)
41 };
42 for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) {
43 let size = arg_abi.layout.size;
44 if uses_vector_registers(&arg_abi.mode, &arg_abi.layout.backend_repr) {
45 let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) {
47 Some((_, feature)) => feature,
48 None => {
49 let span = span();
50 tcx.emit_node_span_lint(
51 ABI_UNSUPPORTED_VECTOR_TYPES,
52 CRATE_HIR_ID,
53 span,
54 errors::AbiErrorUnsupportedVectorType {
55 span,
56 ty: arg_abi.layout.ty,
57 is_call,
58 },
59 );
60 continue;
61 }
62 };
63 if !have_feature(Symbol::intern(feature)) {
64 let span = span();
66 tcx.emit_node_span_lint(
67 ABI_UNSUPPORTED_VECTOR_TYPES,
68 CRATE_HIR_ID,
69 span,
70 errors::AbiErrorDisabledVectorType {
71 span,
72 required_feature: feature,
73 ty: arg_abi.layout.ty,
74 is_call,
75 },
76 );
77 }
78 }
79 }
80 if abi.conv == Conv::X86VectorCall && !have_feature(sym::sse2) {
82 tcx.dcx().emit_err(errors::AbiRequiredTargetFeature {
83 span: span(),
84 required_feature: "sse2",
85 abi: "vectorcall",
86 is_call,
87 });
88 }
89}
90
91fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) {
94 let typing_env = ty::TypingEnv::fully_monomorphized();
95 let Ok(abi) = tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
96 else {
97 return;
100 };
101 do_check_abi(
102 tcx,
103 abi,
104 instance.def_id(),
105 false,
106 || tcx.def_span(instance.def_id()),
107 )
108}
109
110fn check_call_site_abi<'tcx>(
113 tcx: TyCtxt<'tcx>,
114 callee: Ty<'tcx>,
115 span: Span,
116 caller: InstanceKind<'tcx>,
117) {
118 if callee.fn_sig(tcx).abi().is_rustic_abi() {
119 return;
121 }
122 let typing_env = ty::TypingEnv::fully_monomorphized();
123 let callee_abi = match *callee.kind() {
124 ty::FnPtr(..) => {
125 tcx.fn_abi_of_fn_ptr(typing_env.as_query_input((callee.fn_sig(tcx), ty::List::empty())))
126 }
127 ty::FnDef(def_id, args) => {
128 if tcx.intrinsic(def_id).is_some() {
130 return;
131 }
132 let instance = ty::Instance::expect_resolve(tcx, typing_env, def_id, args, DUMMY_SP);
133 tcx.fn_abi_of_instance(typing_env.as_query_input((instance, ty::List::empty())))
134 }
135 _ => {
136 panic!("Invalid function call");
137 }
138 };
139
140 let Ok(callee_abi) = callee_abi else {
141 return;
143 };
144 do_check_abi(tcx, callee_abi, caller.def_id(), true, || span);
145}
146
147fn check_callees_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>, body: &mir::Body<'tcx>) {
148 for (bb, _data) in traversal::mono_reachable(body, tcx, instance) {
150 let terminator = body.basic_blocks[bb].terminator();
151 match terminator.kind {
152 mir::TerminatorKind::Call { ref func, ref fn_span, .. }
153 | mir::TerminatorKind::TailCall { ref func, ref fn_span, .. } => {
154 let callee_ty = func.ty(body, tcx);
155 let callee_ty = instance.instantiate_mir_and_normalize_erasing_regions(
156 tcx,
157 ty::TypingEnv::fully_monomorphized(),
158 ty::EarlyBinder::bind(callee_ty),
159 );
160 check_call_site_abi(tcx, callee_ty, *fn_span, body.source.instance);
161 }
162 _ => {}
163 }
164 }
165}
166
167pub(crate) fn check_feature_dependent_abi<'tcx>(
168 tcx: TyCtxt<'tcx>,
169 instance: Instance<'tcx>,
170 body: &'tcx mir::Body<'tcx>,
171) {
172 check_instance_abi(tcx, instance);
173 check_callees_abi(tcx, instance, body);
174}