1
Fork 0

inline: re-introduce some callee body checks

This commit is contained in:
David Wood 2024-12-10 12:06:57 +00:00
parent 450793923e
commit e4bae91be1
No known key found for this signature in database
3 changed files with 131 additions and 2 deletions

View file

@ -195,10 +195,37 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
&self, &self,
_: &CallSite<'tcx>, _: &CallSite<'tcx>,
callee_body: &Body<'tcx>, callee_body: &Body<'tcx>,
_: &CodegenFnAttrs, callee_attrs: &CodegenFnAttrs,
_: bool, _: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
if let Some(_) = callee_body.tainted_by_errors { Err("body has errors") } else { Ok(()) } if callee_body.tainted_by_errors.is_some() {
return Err("body has errors");
}
let caller_attrs = self.tcx().codegen_fn_attrs(self.caller_def_id());
if callee_attrs.instruction_set != caller_attrs.instruction_set
&& callee_body
.basic_blocks
.iter()
.any(|bb| matches!(bb.terminator().kind, TerminatorKind::InlineAsm { .. }))
{
// During the attribute checking stage we allow a callee with no
// instruction_set assigned to count as compatible with a function that does
// assign one. However, during this stage we require an exact match when any
// inline-asm is detected. LLVM will still possibly do an inline later on
// if the no-attribute function ends up with the same instruction set anyway.
Err("cannot move inline-asm across instruction sets")
} else if callee_body
.basic_blocks
.iter()
.any(|bb| matches!(bb.terminator().kind, TerminatorKind::TailCall { .. }))
{
// FIXME(explicit_tail_calls): figure out how exactly functions containing tail
// calls can be inlined (and if they even should)
Err("can't inline functions with tail calls")
} else {
Ok(())
}
} }
fn inline_limit_for_block(&self) -> Option<usize> { fn inline_limit_for_block(&self) -> Option<usize> {

View file

@ -0,0 +1,68 @@
//@ build-fail
//@ compile-flags: --crate-type=lib --target thumbv4t-none-eabi
//@ needs-llvm-components: arm
// Checks that forced inlining won't mix asm with incompatible instruction sets.
#![crate_type = "lib"]
#![feature(rustc_attrs)]
#![feature(no_core, lang_items)]
#![no_core]
#[lang = "sized"]
pub trait Sized {}
#[lang = "copy"]
pub trait Copy {}
#[lang = "freeze"]
pub unsafe trait Freeze {}
#[lang = "start"]
fn start<T>(_main: fn() -> T, _argc: isize, _argv: *const *const u8, _sigpipe: u8) -> isize {
0
}
#[rustc_builtin_macro]
#[macro_export]
macro_rules! asm {
("assembly template",
$(operands,)*
$(options($(option),*))?
) => {
/* compiler built-in */
};
}
#[instruction_set(arm::a32)]
#[rustc_force_inline]
fn instruction_set_a32() {}
#[instruction_set(arm::t32)]
#[rustc_force_inline]
fn instruction_set_t32() {}
#[rustc_force_inline]
fn instruction_set_default() {}
#[rustc_force_inline]
fn inline_always_and_using_inline_asm() {
unsafe { asm!("/* do nothing */") };
}
#[instruction_set(arm::t32)]
pub fn t32() {
instruction_set_a32();
//~^ ERROR `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
instruction_set_t32();
instruction_set_default();
inline_always_and_using_inline_asm();
//~^ ERROR `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
}
pub fn default() {
instruction_set_a32();
//~^ ERROR `instruction_set_a32` could not be inlined into `default` but is required to be inlined
instruction_set_t32();
//~^ ERROR `instruction_set_t32` could not be inlined into `default` but is required to be inlined
instruction_set_default();
inline_always_and_using_inline_asm();
}

View file

@ -0,0 +1,34 @@
error: `instruction_set_a32` could not be inlined into `t32` but is required to be inlined
--> $DIR/asm.rs:53:5
|
LL | instruction_set_a32();
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
|
= note: could not be inlined due to: incompatible instruction set
error: `inline_always_and_using_inline_asm` could not be inlined into `t32` but is required to be inlined
--> $DIR/asm.rs:57:5
|
LL | inline_always_and_using_inline_asm();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...`inline_always_and_using_inline_asm` called here
|
= note: could not be inlined due to: cannot move inline-asm across instruction sets
error: `instruction_set_a32` could not be inlined into `default` but is required to be inlined
--> $DIR/asm.rs:62:5
|
LL | instruction_set_a32();
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_a32` called here
|
= note: could not be inlined due to: incompatible instruction set
error: `instruction_set_t32` could not be inlined into `default` but is required to be inlined
--> $DIR/asm.rs:64:5
|
LL | instruction_set_t32();
| ^^^^^^^^^^^^^^^^^^^^^ ...`instruction_set_t32` called here
|
= note: could not be inlined due to: incompatible instruction set
error: aborting due to 4 previous errors