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,
|
&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> {
|
||||||
|
|
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