inline: re-introduce some callee body checks
This commit is contained in:
parent
450793923e
commit
e4bae91be1
3 changed files with 131 additions and 2 deletions
|
@ -195,10 +195,37 @@ impl<'tcx> Inliner<'tcx> for ForceInliner<'tcx> {
|
|||
&self,
|
||||
_: &CallSite<'tcx>,
|
||||
callee_body: &Body<'tcx>,
|
||||
_: &CodegenFnAttrs,
|
||||
callee_attrs: &CodegenFnAttrs,
|
||||
_: bool,
|
||||
) -> 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> {
|
||||
|
|
68
tests/ui/force-inlining/asm.rs
Normal file
68
tests/ui/force-inlining/asm.rs
Normal 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();
|
||||
}
|
34
tests/ui/force-inlining/asm.stderr
Normal file
34
tests/ui/force-inlining/asm.stderr
Normal 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
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue