-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Emit error when calling/declaring functions with unavailable vectors.
On some architectures, vector types may have a different ABI when relevant target features are enabled. As discussed in rust-lang/lang-team#235, this turns out to very easily lead to unsound code. This commit makes it an error to declare or call functions using those vector types in a context in which the corresponding target features are disabled, if using an ABI for which the difference is relevant.
- Loading branch information
Showing
16 changed files
with
278 additions
and
20 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
use rustc_abi::Abi; | ||
use rustc_middle::ty::{self, Instance, InstanceKind, ParamEnv, Ty, TyCtxt}; | ||
use rustc_span::def_id::DefId; | ||
use rustc_span::{Span, Symbol}; | ||
use rustc_target::abi::call::{FnAbi, PassMode}; | ||
|
||
use crate::errors::{AbiErrorDisabledVectorTypeCall, AbiErrorDisabledVectorTypeDef}; | ||
|
||
// Represents the least-constraining feature that is required for vector types up to a certain size | ||
// to have their "proper" ABI. | ||
const X86_VECTOR_FEATURES: &'static [(u64, &'static str)] = | ||
&[(128, "sse"), (256, "avx"), (512, "avx512f")]; | ||
|
||
fn do_check_abi<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
abi: &FnAbi<'tcx, Ty<'tcx>>, | ||
target_feature_def: DefId, | ||
emit_err: impl Fn(&'static str), | ||
) { | ||
let feature_def = if tcx.sess.target.arch == "x86" || tcx.sess.target.arch == "x86_64" { | ||
X86_VECTOR_FEATURES | ||
} else if tcx.sess.target.arch == "aarch64" { | ||
// ABI on aarch64 does not depend on target features. | ||
return; | ||
} else { | ||
// FIXME: add support for non-tier1 architectures | ||
return; | ||
}; | ||
let codegen_attrs = tcx.codegen_fn_attrs(target_feature_def); | ||
for arg_abi in abi.args.iter().chain(std::iter::once(&abi.ret)) { | ||
let size = arg_abi.layout.size; | ||
if matches!(arg_abi.layout.abi, Abi::Vector { .. }) | ||
&& !matches!(arg_abi.mode, PassMode::Indirect { .. }) | ||
{ | ||
let feature = match feature_def.iter().find(|(bits, _)| size.bits() <= *bits) { | ||
Some((_, feature)) => feature, | ||
None => panic!("Unknown vector size: {}; arg = {:?}", size.bits(), arg_abi), | ||
}; | ||
let feature_sym = Symbol::intern(feature); | ||
if !tcx.sess.unstable_target_features.contains(&feature_sym) | ||
&& !codegen_attrs.target_features.iter().any(|x| x.name == feature_sym) | ||
{ | ||
emit_err(feature); | ||
} | ||
} | ||
} | ||
} | ||
|
||
/// Checks that the ABI of a given instance of a function does not contain vector-passed arguments | ||
/// or return values for which the corresponding target feature is not enabled. | ||
pub fn check_instance_abi<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { | ||
let param_env = ParamEnv::reveal_all(); | ||
let Ok(abi) = tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) else { | ||
// An error will be reported during codegen if we cannot determine the ABI of this | ||
// function. | ||
return; | ||
}; | ||
do_check_abi(tcx, abi, instance.def_id(), |required_feature| { | ||
tcx.dcx().emit_err(AbiErrorDisabledVectorTypeDef { | ||
span: tcx.def_span(instance.def_id()), | ||
required_feature, | ||
}); | ||
}) | ||
} | ||
|
||
/// Checks that a call expression does not try to pass a vector-passed argument which requires a | ||
/// target feature that the caller does not have, as doing so causes UB because of ABI mismatch. | ||
pub fn check_call_site_abi<'tcx>( | ||
tcx: TyCtxt<'tcx>, | ||
ty: Ty<'tcx>, | ||
span: Span, | ||
caller: InstanceKind<'tcx>, | ||
) { | ||
let param_env = ParamEnv::reveal_all(); | ||
let callee_abi = match *ty.kind() { | ||
ty::FnPtr(..) => tcx.fn_abi_of_fn_ptr(param_env.and((ty.fn_sig(tcx), ty::List::empty()))), | ||
ty::FnDef(def_id, args) => { | ||
// Intrinsics are handled separately by the compiler. | ||
if tcx.intrinsic(def_id).is_some() { | ||
return; | ||
} | ||
let instance = ty::Instance::expect_resolve(tcx, param_env, def_id, args, span); | ||
tcx.fn_abi_of_instance(param_env.and((instance, ty::List::empty()))) | ||
} | ||
_ => { | ||
panic!("Invalid function call"); | ||
} | ||
}; | ||
|
||
let Ok(callee_abi) = callee_abi else { | ||
// ABI failed to compute; this will not get through codegen. | ||
return; | ||
}; | ||
do_check_abi(tcx, callee_abi, caller.def_id(), |required_feature| { | ||
tcx.dcx().emit_err(AbiErrorDisabledVectorTypeCall { span, required_feature }); | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
//@ only-x86_64 | ||
//@ build-fail | ||
|
||
#![feature(avx512_target_feature)] | ||
#![feature(portable_simd)] | ||
#![allow(improper_ctypes_definitions)] | ||
|
||
use std::arch::x86_64::*; | ||
|
||
#[repr(transparent)] | ||
struct Wrapper(__m256); | ||
|
||
unsafe extern "C" fn w(_: Wrapper) { | ||
//~^ ABI error: this function definition uses a avx vector type, which is not enabled | ||
todo!() | ||
} | ||
|
||
unsafe extern "C" fn f(_: __m256) { | ||
//~^ ABI error: this function definition uses a avx vector type, which is not enabled | ||
todo!() | ||
} | ||
|
||
unsafe extern "C" fn g() -> __m256 { | ||
//~^ ABI error: this function definition uses a avx vector type, which is not enabled | ||
todo!() | ||
} | ||
|
||
#[target_feature(enable = "avx2")] | ||
unsafe extern "C" fn favx(_: __m256) { | ||
todo!() | ||
} | ||
|
||
#[target_feature(enable = "avx")] | ||
unsafe extern "C" fn gavx() -> __m256 { | ||
todo!() | ||
} | ||
|
||
fn as_f64x8(d: __m512d) -> std::simd::f64x8 { | ||
unsafe { std::mem::transmute(d) } | ||
} | ||
|
||
unsafe fn test() { | ||
let arg = std::mem::transmute([0.0f64; 8]); | ||
as_f64x8(arg); | ||
} | ||
|
||
fn main() { | ||
unsafe { | ||
f(g()); | ||
//~^ ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
//~| ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
} | ||
|
||
unsafe { | ||
favx(gavx()); | ||
//~^ ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
//~| ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
} | ||
|
||
unsafe { | ||
test(); | ||
} | ||
|
||
unsafe { | ||
w(Wrapper(g())); | ||
//~^ ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
//~| ERROR ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:49:11 | ||
| | ||
LL | f(g()); | ||
| ^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:49:9 | ||
| | ||
LL | f(g()); | ||
| ^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:55:14 | ||
| | ||
LL | favx(gavx()); | ||
| ^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:55:9 | ||
| | ||
LL | favx(gavx()); | ||
| ^^^^^^^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:65:19 | ||
| | ||
LL | w(Wrapper(g())); | ||
| ^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function call uses a avx vector type, which is not enabled in the caller | ||
--> $DIR/simd-abi-checks.rs:65:9 | ||
| | ||
LL | w(Wrapper(g())); | ||
| ^^^^^^^^^^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function definition uses a avx vector type, which is not enabled | ||
--> $DIR/simd-abi-checks.rs:23:1 | ||
| | ||
LL | unsafe extern "C" fn g() -> __m256 { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function definition uses a avx vector type, which is not enabled | ||
--> $DIR/simd-abi-checks.rs:18:1 | ||
| | ||
LL | unsafe extern "C" fn f(_: __m256) { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: ABI error: this function definition uses a avx vector type, which is not enabled | ||
--> $DIR/simd-abi-checks.rs:13:1 | ||
| | ||
LL | unsafe extern "C" fn w(_: Wrapper) { | ||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
| | ||
= help: consider enabling it globally (-C target-feature=+avx) or locally (#[target_feature(enable="avx")]) | ||
|
||
error: aborting due to 9 previous errors | ||
|