diff options
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/errors.rs | 22 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/block.rs | 56 |
2 files changed, 77 insertions, 1 deletions
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index e9d31db9254..13a2dce3e69 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1033,3 +1033,25 @@ pub struct CompilerBuiltinsCannotCall { pub caller: String, pub callee: String, } + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cmse_call_inputs_stack_spill, code = E0798)] +#[note] +pub struct CmseCallInputsStackSpill { + #[primary_span] + #[label(codegen_ssa_call)] + pub span: Span, + #[label] + pub func_span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cmse_call_output_stack_spill, code = E0798)] +#[note] +pub struct CmseCallOutputStackSpill { + #[primary_span] + #[label(codegen_ssa_call)] + pub span: Span, + #[label] + pub func_span: Span, +} diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 6a5525dc2b3..8011604d576 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -5,7 +5,9 @@ use super::{CachedLlbb, FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; -use crate::errors::CompilerBuiltinsCannotCall; +use crate::errors::{ + CmseCallInputsStackSpill, CmseCallOutputStackSpill, CompilerBuiltinsCannotCall, +}; use crate::meth; use crate::traits::*; use crate::MemFlags; @@ -834,6 +836,58 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(bx, func); + let fn_sig = callee.layout.ty.fn_sig(bx.tcx()).skip_binder(); + + if let rustc_target::spec::abi::Abi::CCmseNonSecureCall = fn_sig.abi { + let mut accum = 0u64; + + for arg_def in fn_sig.inputs().iter() { + let layout = bx.layout_of(*arg_def); + + let align = layout.layout.align().abi.bytes(); + let size = layout.layout.size().bytes(); + + accum += size; + accum = accum.next_multiple_of(Ord::max(4, align)); + } + + // the available argument space is 16 bytes (4 32-bit registers) in total + let available_space = 16; + + if accum > available_space { + let err = CmseCallInputsStackSpill { span, func_span: func.span(self.mir) }; + bx.tcx().dcx().emit_err(err); + } + + let mut ret_layout = bx.layout_of(fn_sig.output()); + + // unwrap any `repr(transparent)` wrappers + loop { + if ret_layout.is_transparent::<Bx>() { + match ret_layout.non_1zst_field(bx) { + None => break, + Some((_, layout)) => ret_layout = layout, + } + } else { + break; + } + } + + let valid_2register_return_types = + [bx.tcx().types.i64, bx.tcx().types.u64, bx.tcx().types.f64]; + + // A Composite Type larger than 4 bytes is stored in memory at an address + // passed as an extra argument when the function was called. That is not allowed + // for cmse_nonsecure_entry functions. + let is_valid_output = ret_layout.layout.size().bytes() <= 4 + || valid_2register_return_types.contains(&ret_layout.ty); + + if !is_valid_output { + let err = CmseCallOutputStackSpill { span, func_span: func.span(self.mir) }; + bx.tcx().dcx().emit_err(err); + } + } + let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, args) => ( Some( |
