about summary refs log tree commit diff
path: root/compiler/rustc_codegen_ssa/src
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs22
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs56
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(