Auto merge of #138791 - matthiaskrgr:rollup-ev46cqr, r=matthiaskrgr
Rollup of 9 pull requests Successful merges: - #138364 (ports the compiler test cases to new rust_intrinsic format) - #138570 (add `naked_functions_target_feature` unstable feature) - #138623 ([bootstrap] Use llvm_runtimes for compiler-rt) - #138627 (Autodiff cleanups) - #138669 (tests: accept some noise from LLVM 21 in symbols-all-mangled) - #138706 (Improve bootstrap git modified path handling) - #138709 (Update GCC submodule) - #138717 (Add an attribute that makes the spans from a macro edition 2021, and fix pin on edition 2024 with it) - #138721 (Use explicit cpu in some asm and codegen tests.) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
be73c1f461
42 changed files with 458 additions and 305 deletions
|
|
@ -191,6 +191,7 @@ pub enum AttributeKind {
|
|||
},
|
||||
MacroTransparency(Transparency),
|
||||
Repr(ThinVec<(ReprAttr, Span)>),
|
||||
RustcMacroEdition2021,
|
||||
Stability {
|
||||
stability: Stability,
|
||||
/// Span of the `#[stable(...)]` or `#[unstable(...)]` attribute
|
||||
|
|
|
|||
|
|
@ -182,21 +182,18 @@ macro_rules! find_attr {
|
|||
}};
|
||||
|
||||
($attributes_list: expr, $pattern: pat $(if $guard: expr)? => $e: expr) => {{
|
||||
fn check_attribute_iterator<'a>(_: &'_ impl IntoIterator<Item = &'a rustc_hir::Attribute>) {}
|
||||
check_attribute_iterator(&$attributes_list);
|
||||
|
||||
let find_attribute = |iter| {
|
||||
'done: {
|
||||
for i in $attributes_list {
|
||||
let i: &rustc_hir::Attribute = i;
|
||||
match i {
|
||||
rustc_hir::Attribute::Parsed($pattern) $(if $guard)? => {
|
||||
return Some($e);
|
||||
break 'done Some($e);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
};
|
||||
find_attribute($attributes_list)
|
||||
}
|
||||
}};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ pub(crate) mod cfg;
|
|||
pub(crate) mod confusables;
|
||||
pub(crate) mod deprecation;
|
||||
pub(crate) mod repr;
|
||||
pub(crate) mod rustc;
|
||||
pub(crate) mod stability;
|
||||
pub(crate) mod transparency;
|
||||
pub(crate) mod util;
|
||||
|
|
|
|||
19
compiler/rustc_attr_parsing/src/attributes/rustc.rs
Normal file
19
compiler/rustc_attr_parsing/src/attributes/rustc.rs
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
use rustc_attr_data_structures::AttributeKind;
|
||||
use rustc_span::sym;
|
||||
|
||||
use super::{AcceptContext, SingleAttributeParser};
|
||||
use crate::parser::ArgParser;
|
||||
|
||||
pub(crate) struct RustcMacroEdition2021Parser;
|
||||
|
||||
// FIXME(jdonszelmann): make these proper diagnostics
|
||||
impl SingleAttributeParser for RustcMacroEdition2021Parser {
|
||||
const PATH: &'static [rustc_span::Symbol] = &[sym::rustc_macro_edition_2021];
|
||||
|
||||
fn on_duplicate(_cx: &crate::context::AcceptContext<'_>, _first_span: rustc_span::Span) {}
|
||||
|
||||
fn convert(_cx: &AcceptContext<'_>, args: &ArgParser<'_>) -> Option<AttributeKind> {
|
||||
assert!(args.no_args());
|
||||
Some(AttributeKind::RustcMacroEdition2021)
|
||||
}
|
||||
}
|
||||
|
|
@ -15,6 +15,7 @@ use crate::attributes::allow_unstable::{AllowConstFnUnstableParser, AllowInterna
|
|||
use crate::attributes::confusables::ConfusablesParser;
|
||||
use crate::attributes::deprecation::DeprecationParser;
|
||||
use crate::attributes::repr::ReprParser;
|
||||
use crate::attributes::rustc::RustcMacroEdition2021Parser;
|
||||
use crate::attributes::stability::{
|
||||
BodyStabilityParser, ConstStabilityIndirectParser, ConstStabilityParser, StabilityParser,
|
||||
};
|
||||
|
|
@ -76,6 +77,7 @@ attribute_groups!(
|
|||
// tidy-alphabetical-start
|
||||
Single<ConstStabilityIndirectParser>,
|
||||
Single<DeprecationParser>,
|
||||
Single<RustcMacroEdition2021Parser>,
|
||||
Single<TransparencyParser>,
|
||||
// tidy-alphabetical-end
|
||||
];
|
||||
|
|
|
|||
|
|
@ -26,6 +26,16 @@ mod llvm_enzyme {
|
|||
|
||||
use crate::errors;
|
||||
|
||||
pub(crate) fn outer_normal_attr(
|
||||
kind: &P<rustc_ast::NormalAttr>,
|
||||
id: rustc_ast::AttrId,
|
||||
span: Span,
|
||||
) -> rustc_ast::Attribute {
|
||||
let style = rustc_ast::AttrStyle::Outer;
|
||||
let kind = rustc_ast::AttrKind::Normal(kind.clone());
|
||||
rustc_ast::Attribute { kind, id, style, span }
|
||||
}
|
||||
|
||||
// If we have a default `()` return type or explicitley `()` return type,
|
||||
// then we often can skip doing some work.
|
||||
fn has_ret(ty: &FnRetTy) -> bool {
|
||||
|
|
@ -224,20 +234,8 @@ mod llvm_enzyme {
|
|||
.filter(|a| **a == DiffActivity::Active || **a == DiffActivity::ActiveOnly)
|
||||
.count() as u32;
|
||||
let (d_sig, new_args, idents, errored) = gen_enzyme_decl(ecx, &sig, &x, span);
|
||||
let new_decl_span = d_sig.span;
|
||||
let d_body = gen_enzyme_body(
|
||||
ecx,
|
||||
&x,
|
||||
n_active,
|
||||
&sig,
|
||||
&d_sig,
|
||||
primal,
|
||||
&new_args,
|
||||
span,
|
||||
sig_span,
|
||||
new_decl_span,
|
||||
idents,
|
||||
errored,
|
||||
ecx, &x, n_active, &sig, &d_sig, primal, &new_args, span, sig_span, idents, errored,
|
||||
);
|
||||
let d_ident = first_ident(&meta_item_vec[0]);
|
||||
|
||||
|
|
@ -270,36 +268,39 @@ mod llvm_enzyme {
|
|||
};
|
||||
let inline_never_attr = P(ast::NormalAttr { item: inline_item, tokens: None });
|
||||
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
|
||||
let attr: ast::Attribute = ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(rustc_ad_attr.clone()),
|
||||
id: new_id,
|
||||
style: ast::AttrStyle::Outer,
|
||||
span,
|
||||
};
|
||||
let attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
let new_id = ecx.sess.psess.attr_id_generator.mk_attr_id();
|
||||
let inline_never: ast::Attribute = ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(inline_never_attr),
|
||||
id: new_id,
|
||||
style: ast::AttrStyle::Outer,
|
||||
span,
|
||||
};
|
||||
let inline_never = outer_normal_attr(&inline_never_attr, new_id, span);
|
||||
|
||||
// We're avoid duplicating the attributes `#[rustc_autodiff]` and `#[inline(never)]`.
|
||||
fn same_attribute(attr: &ast::AttrKind, item: &ast::AttrKind) -> bool {
|
||||
match (attr, item) {
|
||||
(ast::AttrKind::Normal(a), ast::AttrKind::Normal(b)) => {
|
||||
let a = &a.item.path;
|
||||
let b = &b.item.path;
|
||||
a.segments.len() == b.segments.len()
|
||||
&& a.segments.iter().zip(b.segments.iter()).all(|(a, b)| a.ident == b.ident)
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add it multiple times:
|
||||
let orig_annotatable: Annotatable = match item {
|
||||
Annotatable::Item(ref mut iitem) => {
|
||||
if !iitem.attrs.iter().any(|a| a.id == attr.id) {
|
||||
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
|
||||
iitem.attrs.push(attr);
|
||||
}
|
||||
if !iitem.attrs.iter().any(|a| a.id == inline_never.id) {
|
||||
if !iitem.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
|
||||
iitem.attrs.push(inline_never.clone());
|
||||
}
|
||||
Annotatable::Item(iitem.clone())
|
||||
}
|
||||
Annotatable::AssocItem(ref mut assoc_item, i @ Impl) => {
|
||||
if !assoc_item.attrs.iter().any(|a| a.id == attr.id) {
|
||||
if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
|
||||
assoc_item.attrs.push(attr);
|
||||
}
|
||||
if !assoc_item.attrs.iter().any(|a| a.id == inline_never.id) {
|
||||
if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
|
||||
assoc_item.attrs.push(inline_never.clone());
|
||||
}
|
||||
Annotatable::AssocItem(assoc_item.clone(), i)
|
||||
|
|
@ -314,13 +315,7 @@ mod llvm_enzyme {
|
|||
delim: rustc_ast::token::Delimiter::Parenthesis,
|
||||
tokens: ts,
|
||||
});
|
||||
let d_attr: ast::Attribute = ast::Attribute {
|
||||
kind: ast::AttrKind::Normal(rustc_ad_attr.clone()),
|
||||
id: new_id,
|
||||
style: ast::AttrStyle::Outer,
|
||||
span,
|
||||
};
|
||||
|
||||
let d_attr = outer_normal_attr(&rustc_ad_attr, new_id, span);
|
||||
let d_annotatable = if is_impl {
|
||||
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(asdf);
|
||||
let d_fn = P(ast::AssocItem {
|
||||
|
|
@ -361,30 +356,27 @@ mod llvm_enzyme {
|
|||
ty
|
||||
}
|
||||
|
||||
/// We only want this function to type-check, since we will replace the body
|
||||
/// later on llvm level. Using `loop {}` does not cover all return types anymore,
|
||||
/// so instead we build something that should pass. We also add a inline_asm
|
||||
/// line, as one more barrier for rustc to prevent inlining of this function.
|
||||
/// FIXME(ZuseZ4): We still have cases of incorrect inlining across modules, see
|
||||
/// <https://github.com/EnzymeAD/rust/issues/173>, so this isn't sufficient.
|
||||
/// It also triggers an Enzyme crash if we due to a bug ever try to differentiate
|
||||
/// this function (which should never happen, since it is only a placeholder).
|
||||
/// Finally, we also add back_box usages of all input arguments, to prevent rustc
|
||||
/// from optimizing any arguments away.
|
||||
fn gen_enzyme_body(
|
||||
// Will generate a body of the type:
|
||||
// ```
|
||||
// {
|
||||
// unsafe {
|
||||
// asm!("NOP");
|
||||
// }
|
||||
// ::core::hint::black_box(primal(args));
|
||||
// ::core::hint::black_box((args, ret));
|
||||
// <This part remains to be done by following function>
|
||||
// }
|
||||
// ```
|
||||
fn init_body_helper(
|
||||
ecx: &ExtCtxt<'_>,
|
||||
x: &AutoDiffAttrs,
|
||||
n_active: u32,
|
||||
sig: &ast::FnSig,
|
||||
d_sig: &ast::FnSig,
|
||||
span: Span,
|
||||
primal: Ident,
|
||||
new_names: &[String],
|
||||
span: Span,
|
||||
sig_span: Span,
|
||||
new_decl_span: Span,
|
||||
idents: Vec<Ident>,
|
||||
idents: &[Ident],
|
||||
errored: bool,
|
||||
) -> P<ast::Block> {
|
||||
) -> (P<ast::Block>, P<ast::Expr>, P<ast::Expr>, P<ast::Expr>) {
|
||||
let blackbox_path = ecx.std_path(&[sym::hint, sym::black_box]);
|
||||
let noop = ast::InlineAsm {
|
||||
asm_macro: ast::AsmMacro::Asm,
|
||||
|
|
@ -433,6 +425,51 @@ mod llvm_enzyme {
|
|||
}
|
||||
body.stmts.push(ecx.stmt_semi(black_box_remaining_args));
|
||||
|
||||
(body, primal_call, black_box_primal_call, blackbox_call_expr)
|
||||
}
|
||||
|
||||
/// We only want this function to type-check, since we will replace the body
|
||||
/// later on llvm level. Using `loop {}` does not cover all return types anymore,
|
||||
/// so instead we manually build something that should pass the type checker.
|
||||
/// We also add a inline_asm line, as one more barrier for rustc to prevent inlining
|
||||
/// or const propagation. inline_asm will also triggers an Enzyme crash if due to another
|
||||
/// bug would ever try to accidentially differentiate this placeholder function body.
|
||||
/// Finally, we also add back_box usages of all input arguments, to prevent rustc
|
||||
/// from optimizing any arguments away.
|
||||
fn gen_enzyme_body(
|
||||
ecx: &ExtCtxt<'_>,
|
||||
x: &AutoDiffAttrs,
|
||||
n_active: u32,
|
||||
sig: &ast::FnSig,
|
||||
d_sig: &ast::FnSig,
|
||||
primal: Ident,
|
||||
new_names: &[String],
|
||||
span: Span,
|
||||
sig_span: Span,
|
||||
idents: Vec<Ident>,
|
||||
errored: bool,
|
||||
) -> P<ast::Block> {
|
||||
let new_decl_span = d_sig.span;
|
||||
|
||||
// Just adding some default inline-asm and black_box usages to prevent early inlining
|
||||
// and optimizations which alter the function signature.
|
||||
//
|
||||
// The bb_primal_call is the black_box call of the primal function. We keep it around,
|
||||
// since it has the convenient property of returning the type of the primal function,
|
||||
// Remember, we only care to match types here.
|
||||
// No matter which return we pick, we always wrap it into a std::hint::black_box call,
|
||||
// to prevent rustc from propagating it into the caller.
|
||||
let (mut body, primal_call, bb_primal_call, bb_call_expr) = init_body_helper(
|
||||
ecx,
|
||||
span,
|
||||
primal,
|
||||
new_names,
|
||||
sig_span,
|
||||
new_decl_span,
|
||||
&idents,
|
||||
errored,
|
||||
);
|
||||
|
||||
if !has_ret(&d_sig.decl.output) {
|
||||
// there is no return type that we have to match, () works fine.
|
||||
return body;
|
||||
|
|
@ -444,7 +481,7 @@ mod llvm_enzyme {
|
|||
|
||||
if primal_ret && n_active == 0 && x.mode.is_rev() {
|
||||
// We only have the primal ret.
|
||||
body.stmts.push(ecx.stmt_expr(black_box_primal_call));
|
||||
body.stmts.push(ecx.stmt_expr(bb_primal_call));
|
||||
return body;
|
||||
}
|
||||
|
||||
|
|
@ -536,11 +573,11 @@ mod llvm_enzyme {
|
|||
return body;
|
||||
}
|
||||
[arg] => {
|
||||
ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![arg.clone()]);
|
||||
ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![arg.clone()]);
|
||||
}
|
||||
args => {
|
||||
let ret_tuple: P<ast::Expr> = ecx.expr_tuple(span, args.into());
|
||||
ret = ecx.expr_call(new_decl_span, blackbox_call_expr, thin_vec![ret_tuple]);
|
||||
ret = ecx.expr_call(new_decl_span, bb_call_expr, thin_vec![ret_tuple]);
|
||||
}
|
||||
}
|
||||
assert!(has_ret(&d_sig.decl.output));
|
||||
|
|
@ -553,7 +590,7 @@ mod llvm_enzyme {
|
|||
ecx: &ExtCtxt<'_>,
|
||||
span: Span,
|
||||
primal: Ident,
|
||||
idents: Vec<Ident>,
|
||||
idents: &[Ident],
|
||||
) -> P<ast::Expr> {
|
||||
let has_self = idents.len() > 0 && idents[0].name == kw::SelfLower;
|
||||
if has_self {
|
||||
|
|
|
|||
|
|
@ -28,6 +28,113 @@ fn get_params(fnc: &Value) -> Vec<&Value> {
|
|||
}
|
||||
}
|
||||
|
||||
fn match_args_from_caller_to_enzyme<'ll>(
|
||||
cx: &SimpleCx<'ll>,
|
||||
args: &mut Vec<&'ll llvm::Value>,
|
||||
inputs: &[DiffActivity],
|
||||
outer_args: &[&'ll llvm::Value],
|
||||
) {
|
||||
debug!("matching autodiff arguments");
|
||||
// We now handle the issue that Rust level arguments not always match the llvm-ir level
|
||||
// arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on
|
||||
// llvm-ir level. The number of activities matches the number of Rust level arguments, so we
|
||||
// need to match those.
|
||||
// FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it
|
||||
// using iterators and peek()?
|
||||
let mut outer_pos: usize = 0;
|
||||
let mut activity_pos = 0;
|
||||
|
||||
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
|
||||
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
|
||||
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
|
||||
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
|
||||
|
||||
while activity_pos < inputs.len() {
|
||||
let diff_activity = inputs[activity_pos as usize];
|
||||
// Duplicated arguments received a shadow argument, into which enzyme will write the
|
||||
// gradient.
|
||||
let (activity, duplicated): (&Metadata, bool) = match diff_activity {
|
||||
DiffActivity::None => panic!("not a valid input activity"),
|
||||
DiffActivity::Const => (enzyme_const, false),
|
||||
DiffActivity::Active => (enzyme_out, false),
|
||||
DiffActivity::ActiveOnly => (enzyme_out, false),
|
||||
DiffActivity::Dual => (enzyme_dup, true),
|
||||
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::Duplicated => (enzyme_dup, true),
|
||||
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::FakeActivitySize => (enzyme_const, false),
|
||||
};
|
||||
let outer_arg = outer_args[outer_pos];
|
||||
args.push(cx.get_metadata_value(activity));
|
||||
args.push(outer_arg);
|
||||
if duplicated {
|
||||
// We know that duplicated args by construction have a following argument,
|
||||
// so this can not be out of bounds.
|
||||
let next_outer_arg = outer_args[outer_pos + 1];
|
||||
let next_outer_ty = cx.val_ty(next_outer_arg);
|
||||
// FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since
|
||||
// vectors behind references (&Vec<T>) are already supported. Users can not pass a
|
||||
// Vec by value for reverse mode, so this would only help forward mode autodiff.
|
||||
let slice = {
|
||||
if activity_pos + 1 >= inputs.len() {
|
||||
// If there is no arg following our ptr, it also can't be a slice,
|
||||
// since that would lead to a ptr, int pair.
|
||||
false
|
||||
} else {
|
||||
let next_activity = inputs[activity_pos + 1];
|
||||
// We analyze the MIR types and add this dummy activity if we visit a slice.
|
||||
next_activity == DiffActivity::FakeActivitySize
|
||||
}
|
||||
};
|
||||
if slice {
|
||||
// A duplicated slice will have the following two outer_fn arguments:
|
||||
// (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, int1, ...).
|
||||
// FIXME(ZuseZ4): We will upstream a safety check later which asserts that
|
||||
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
|
||||
assert!(unsafe {
|
||||
llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer
|
||||
});
|
||||
let next_outer_arg2 = outer_args[outer_pos + 2];
|
||||
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
|
||||
assert!(unsafe {
|
||||
llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer
|
||||
});
|
||||
let next_outer_arg3 = outer_args[outer_pos + 3];
|
||||
let next_outer_ty3 = cx.val_ty(next_outer_arg3);
|
||||
assert!(unsafe {
|
||||
llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer
|
||||
});
|
||||
args.push(next_outer_arg2);
|
||||
args.push(cx.get_metadata_value(enzyme_const));
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 4;
|
||||
activity_pos += 2;
|
||||
} else {
|
||||
// A duplicated pointer will have the following two outer_fn arguments:
|
||||
// (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, ...).
|
||||
if matches!(diff_activity, DiffActivity::Duplicated | DiffActivity::DuplicatedOnly)
|
||||
{
|
||||
assert!(
|
||||
unsafe { llvm::LLVMRustGetTypeKind(next_outer_ty) }
|
||||
== llvm::TypeKind::Pointer
|
||||
);
|
||||
}
|
||||
// In the case of Dual we don't have assumptions, e.g. f32 would be valid.
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 2;
|
||||
activity_pos += 1;
|
||||
}
|
||||
} else {
|
||||
// We do not differentiate with resprect to this argument.
|
||||
// We already added the metadata and argument above, so just increase the counters.
|
||||
outer_pos += 1;
|
||||
activity_pos += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// When differentiating `fn_to_diff`, take a `outer_fn` and generate another
|
||||
/// function with expected naming and calling conventions[^1] which will be
|
||||
/// discovered by the enzyme LLVM pass and its body populated with the differentiated
|
||||
|
|
@ -43,9 +150,6 @@ fn generate_enzyme_call<'ll>(
|
|||
outer_fn: &'ll Value,
|
||||
attrs: AutoDiffAttrs,
|
||||
) {
|
||||
let inputs = attrs.input_activity;
|
||||
let output = attrs.ret_activity;
|
||||
|
||||
// We have to pick the name depending on whether we want forward or reverse mode autodiff.
|
||||
let mut ad_name: String = match attrs.mode {
|
||||
DiffMode::Forward => "__enzyme_fwddiff",
|
||||
|
|
@ -132,111 +236,13 @@ fn generate_enzyme_call<'ll>(
|
|||
let mut args = Vec::with_capacity(num_args as usize + 1);
|
||||
args.push(fn_to_diff);
|
||||
|
||||
let enzyme_const = cx.create_metadata("enzyme_const".to_string()).unwrap();
|
||||
let enzyme_out = cx.create_metadata("enzyme_out".to_string()).unwrap();
|
||||
let enzyme_dup = cx.create_metadata("enzyme_dup".to_string()).unwrap();
|
||||
let enzyme_dupnoneed = cx.create_metadata("enzyme_dupnoneed".to_string()).unwrap();
|
||||
let enzyme_primal_ret = cx.create_metadata("enzyme_primal_return".to_string()).unwrap();
|
||||
|
||||
match output {
|
||||
DiffActivity::Dual => {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
DiffActivity::Active => {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
_ => {}
|
||||
if matches!(attrs.ret_activity, DiffActivity::Dual | DiffActivity::Active) {
|
||||
args.push(cx.get_metadata_value(enzyme_primal_ret));
|
||||
}
|
||||
|
||||
debug!("matching autodiff arguments");
|
||||
// We now handle the issue that Rust level arguments not always match the llvm-ir level
|
||||
// arguments. A slice, `&[f32]`, for example, is represented as a pointer and a length on
|
||||
// llvm-ir level. The number of activities matches the number of Rust level arguments, so we
|
||||
// need to match those.
|
||||
// FIXME(ZuseZ4): This logic is a bit more complicated than it should be, can we simplify it
|
||||
// using iterators and peek()?
|
||||
let mut outer_pos: usize = 0;
|
||||
let mut activity_pos = 0;
|
||||
let outer_args: Vec<&llvm::Value> = get_params(outer_fn);
|
||||
while activity_pos < inputs.len() {
|
||||
let diff_activity = inputs[activity_pos as usize];
|
||||
// Duplicated arguments received a shadow argument, into which enzyme will write the
|
||||
// gradient.
|
||||
let (activity, duplicated): (&Metadata, bool) = match diff_activity {
|
||||
DiffActivity::None => panic!("not a valid input activity"),
|
||||
DiffActivity::Const => (enzyme_const, false),
|
||||
DiffActivity::Active => (enzyme_out, false),
|
||||
DiffActivity::ActiveOnly => (enzyme_out, false),
|
||||
DiffActivity::Dual => (enzyme_dup, true),
|
||||
DiffActivity::DualOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::Duplicated => (enzyme_dup, true),
|
||||
DiffActivity::DuplicatedOnly => (enzyme_dupnoneed, true),
|
||||
DiffActivity::FakeActivitySize => (enzyme_const, false),
|
||||
};
|
||||
let outer_arg = outer_args[outer_pos];
|
||||
args.push(cx.get_metadata_value(activity));
|
||||
args.push(outer_arg);
|
||||
if duplicated {
|
||||
// We know that duplicated args by construction have a following argument,
|
||||
// so this can not be out of bounds.
|
||||
let next_outer_arg = outer_args[outer_pos + 1];
|
||||
let next_outer_ty = cx.val_ty(next_outer_arg);
|
||||
// FIXME(ZuseZ4): We should add support for Vec here too, but it's less urgent since
|
||||
// vectors behind references (&Vec<T>) are already supported. Users can not pass a
|
||||
// Vec by value for reverse mode, so this would only help forward mode autodiff.
|
||||
let slice = {
|
||||
if activity_pos + 1 >= inputs.len() {
|
||||
// If there is no arg following our ptr, it also can't be a slice,
|
||||
// since that would lead to a ptr, int pair.
|
||||
false
|
||||
} else {
|
||||
let next_activity = inputs[activity_pos + 1];
|
||||
// We analyze the MIR types and add this dummy activity if we visit a slice.
|
||||
next_activity == DiffActivity::FakeActivitySize
|
||||
}
|
||||
};
|
||||
if slice {
|
||||
// A duplicated slice will have the following two outer_fn arguments:
|
||||
// (..., ptr1, int1, ptr2, int2, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, int1, ...).
|
||||
// FIXME(ZuseZ4): We will upstream a safety check later which asserts that
|
||||
// int2 >= int1, which means the shadow vector is large enough to store the gradient.
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Integer);
|
||||
let next_outer_arg2 = outer_args[outer_pos + 2];
|
||||
let next_outer_ty2 = cx.val_ty(next_outer_arg2);
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty2) == llvm::TypeKind::Pointer);
|
||||
let next_outer_arg3 = outer_args[outer_pos + 3];
|
||||
let next_outer_ty3 = cx.val_ty(next_outer_arg3);
|
||||
assert!(llvm::LLVMRustGetTypeKind(next_outer_ty3) == llvm::TypeKind::Integer);
|
||||
args.push(next_outer_arg2);
|
||||
args.push(cx.get_metadata_value(enzyme_const));
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 4;
|
||||
activity_pos += 2;
|
||||
} else {
|
||||
// A duplicated pointer will have the following two outer_fn arguments:
|
||||
// (..., ptr, ptr, ...). We add the following llvm-ir to our __enzyme call:
|
||||
// (..., metadata! enzyme_dup, ptr, ptr, ...).
|
||||
if matches!(
|
||||
diff_activity,
|
||||
DiffActivity::Duplicated | DiffActivity::DuplicatedOnly
|
||||
) {
|
||||
assert!(
|
||||
llvm::LLVMRustGetTypeKind(next_outer_ty) == llvm::TypeKind::Pointer
|
||||
);
|
||||
}
|
||||
// In the case of Dual we don't have assumptions, e.g. f32 would be valid.
|
||||
args.push(next_outer_arg);
|
||||
outer_pos += 2;
|
||||
activity_pos += 1;
|
||||
}
|
||||
} else {
|
||||
// We do not differentiate with resprect to this argument.
|
||||
// We already added the metadata and argument above, so just increase the counters.
|
||||
outer_pos += 1;
|
||||
activity_pos += 1;
|
||||
}
|
||||
}
|
||||
match_args_from_caller_to_enzyme(&cx, &mut args, &attrs.input_activity, &outer_args);
|
||||
|
||||
let call = builder.call(enzyme_ty, ad_fn, &args, None);
|
||||
|
||||
|
|
|
|||
|
|
@ -790,16 +790,10 @@ fn autodiff_attrs(tcx: TyCtxt<'_>, id: DefId) -> Option<AutoDiffAttrs> {
|
|||
|
||||
// check for exactly one autodiff attribute on placeholder functions.
|
||||
// There should only be one, since we generate a new placeholder per ad macro.
|
||||
// FIXME(ZuseZ4): re-enable this check. Currently we add multiple, which doesn't cause harm but
|
||||
// looks strange e.g. under cargo-expand.
|
||||
let attr = match &attrs[..] {
|
||||
[] => return None,
|
||||
[attr] => attr,
|
||||
// These two attributes are the same and unfortunately duplicated due to a previous bug.
|
||||
[attr, _attr2] => attr,
|
||||
_ => {
|
||||
//FIXME(ZuseZ4): Once we fixed our parser, we should also prohibit the two-attribute
|
||||
//branch above.
|
||||
span_bug!(attrs[1].span(), "cg_ssa: rustc_autodiff should only exist once per source");
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,10 +6,9 @@ Erroneous code example:
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn atomic_foo(); // error: unrecognized atomic operation
|
||||
// function
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn atomic_foo(); // error: unrecognized atomic operation
|
||||
// function
|
||||
```
|
||||
|
||||
Please check you didn't make a mistake in the function's name. All intrinsic
|
||||
|
|
@ -20,7 +19,6 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn atomic_fence_seqcst(); // ok!
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn atomic_fence_seqcst(); // ok!
|
||||
```
|
||||
|
|
|
|||
|
|
@ -6,9 +6,8 @@ Erroneous code example:
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn foo(); // error: unrecognized intrinsic function: `foo`
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn foo(); // error: unrecognized intrinsic function: `foo`
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
@ -25,9 +24,8 @@ functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn atomic_fence_seqcst(); // ok!
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn atomic_fence_seqcst(); // ok!
|
||||
|
||||
fn main() {
|
||||
unsafe {
|
||||
|
|
|
|||
|
|
@ -7,9 +7,8 @@ used. Erroneous code examples:
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn unreachable(); // error: intrinsic has wrong type
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn unreachable(); // error: intrinsic has wrong type
|
||||
|
||||
// or:
|
||||
|
||||
|
|
@ -43,9 +42,8 @@ For the first code example, please check the function definition. Example:
|
|||
#![feature(intrinsics)]
|
||||
#![allow(internal_features)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn unreachable() -> !; // ok!
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn unreachable() -> !; // ok!
|
||||
```
|
||||
|
||||
The second case example is a bit particular: the main function must always
|
||||
|
|
|
|||
|
|
@ -5,9 +5,8 @@ Erroneous code example:
|
|||
```compile_fail,E0511
|
||||
#![feature(intrinsics)]
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_add<T>(a: T, b: T) -> T;
|
||||
|
||||
fn main() {
|
||||
unsafe { simd_add(0, 1); }
|
||||
|
|
@ -25,9 +24,8 @@ The generic type has to be a SIMD type. Example:
|
|||
#[derive(Copy, Clone)]
|
||||
struct i32x2([i32; 2]);
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn simd_add<T>(a: T, b: T) -> T;
|
||||
}
|
||||
#[rustc_intrinsic]
|
||||
unsafe fn simd_add<T>(a: T, b: T) -> T;
|
||||
|
||||
unsafe { simd_add(i32x2([0, 0]), i32x2([1, 2])); } // ok!
|
||||
```
|
||||
|
|
|
|||
|
|
@ -661,6 +661,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
|
|||
"`rustc_never_type_options` is used to experiment with never type fallback and work on \
|
||||
never type stabilization, and will never be stable"
|
||||
),
|
||||
rustc_attr!(
|
||||
rustc_macro_edition_2021,
|
||||
Normal,
|
||||
template!(Word),
|
||||
ErrorFollowing,
|
||||
EncodeCrossCrate::No,
|
||||
"makes spans in this macro edition 2021"
|
||||
),
|
||||
|
||||
// ==========================================================================
|
||||
// Internal attributes: Runtime related:
|
||||
|
|
|
|||
|
|
@ -566,6 +566,8 @@ declare_features! (
|
|||
(incomplete, mut_ref, "1.79.0", Some(123076)),
|
||||
/// Allows using `#[naked]` on functions.
|
||||
(unstable, naked_functions, "1.9.0", Some(90957)),
|
||||
/// Allows using `#[target_feature(enable = "...")]` on `#[naked]` on functions.
|
||||
(unstable, naked_functions_target_feature, "1.86.0", Some(138568)),
|
||||
/// Allows specifying the as-needed link modifier
|
||||
(unstable, native_link_modifiers_as_needed, "1.53.0", Some(81490)),
|
||||
/// Allow negative trait implementations.
|
||||
|
|
|
|||
|
|
@ -600,7 +600,6 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
sym::repr,
|
||||
// code generation
|
||||
sym::cold,
|
||||
sym::target_feature,
|
||||
// documentation
|
||||
sym::doc,
|
||||
];
|
||||
|
|
@ -626,6 +625,21 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
if other_attr.has_name(sym::target_feature) {
|
||||
if !self.tcx.features().naked_functions_target_feature() {
|
||||
feature_err(
|
||||
&self.tcx.sess,
|
||||
sym::naked_functions_target_feature,
|
||||
other_attr.span(),
|
||||
"`#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions",
|
||||
).emit();
|
||||
|
||||
return;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if !ALLOW_LIST.iter().any(|name| other_attr.has_name(*name)) {
|
||||
self.dcx().emit_err(errors::NakedFunctionIncompatibleAttribute {
|
||||
span: other_attr.span(),
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::sync::Arc;
|
|||
use rustc_ast::expand::StrippedCfgItem;
|
||||
use rustc_ast::{self as ast, Crate, NodeId, attr};
|
||||
use rustc_ast_pretty::pprust;
|
||||
use rustc_attr_parsing::StabilityLevel;
|
||||
use rustc_attr_parsing::{AttributeKind, StabilityLevel, find_attr};
|
||||
use rustc_data_structures::intern::Interned;
|
||||
use rustc_errors::{Applicability, StashKey};
|
||||
use rustc_expand::base::{
|
||||
|
|
@ -1125,6 +1125,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
|
|||
edition,
|
||||
);
|
||||
|
||||
// The #[rustc_macro_edition_2021] attribute is used by the pin!() macro
|
||||
// as a temporary workaround for a regression in expressiveness in Rust 2024.
|
||||
// See https://github.com/rust-lang/rust/issues/138718.
|
||||
if find_attr!(attrs.iter(), AttributeKind::RustcMacroEdition2021) {
|
||||
ext.edition = Edition::Edition2021;
|
||||
}
|
||||
|
||||
if let Some(builtin_name) = ext.builtin_name {
|
||||
// The macro was marked with `#[rustc_builtin_macro]`.
|
||||
if let Some(builtin_ext_kind) = self.builtin_macros.get(&builtin_name) {
|
||||
|
|
|
|||
|
|
@ -1376,6 +1376,7 @@ symbols! {
|
|||
naked,
|
||||
naked_asm,
|
||||
naked_functions,
|
||||
naked_functions_target_feature,
|
||||
name,
|
||||
names,
|
||||
native_link_modifiers,
|
||||
|
|
@ -1794,6 +1795,7 @@ symbols! {
|
|||
rustc_lint_opt_ty,
|
||||
rustc_lint_query_instability,
|
||||
rustc_lint_untracked_query_information,
|
||||
rustc_macro_edition_2021,
|
||||
rustc_macro_transparency,
|
||||
rustc_main,
|
||||
rustc_mir,
|
||||
|
|
|
|||
|
|
@ -1943,6 +1943,7 @@ unsafe impl<T: ?Sized> PinCoerceUnsized for *mut T {}
|
|||
#[stable(feature = "pin_macro", since = "1.68.0")]
|
||||
#[rustc_macro_transparency = "semitransparent"]
|
||||
#[allow_internal_unstable(unsafe_pin_internals)]
|
||||
#[cfg_attr(not(bootstrap), rustc_macro_edition_2021)]
|
||||
pub macro pin($value:expr $(,)?) {
|
||||
// This is `Pin::new_unchecked(&mut { $value })`, so, for starters, let's
|
||||
// review such a hypothetical macro (that any user-code could define):
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ fn pin_const() {
|
|||
}
|
||||
|
||||
pin_mut_const();
|
||||
|
||||
// Check that we accept a Rust 2024 $expr.
|
||||
std::pin::pin!(const { 1 });
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
@ -81,3 +84,14 @@ mod pin_coerce_unsized {
|
|||
arg
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(not(bootstrap))]
|
||||
fn temp_lifetime() {
|
||||
// Check that temporary lifetimes work as in Rust 2021.
|
||||
// Regression test for https://github.com/rust-lang/rust/issues/138596
|
||||
match std::pin::pin!(foo(&mut 0)) {
|
||||
_ => {}
|
||||
}
|
||||
async fn foo(_: &mut usize) {}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ fn get_modified_rs_files(build: &Builder<'_>) -> Result<Option<Vec<String>>, Str
|
|||
return Ok(None);
|
||||
}
|
||||
|
||||
get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"])
|
||||
get_git_modified_files(&build.config.git_config(), Some(&build.config.src), &["rs"]).map(Some)
|
||||
}
|
||||
|
||||
#[derive(serde_derive::Deserialize)]
|
||||
|
|
|
|||
|
|
@ -444,7 +444,6 @@ impl Step for Llvm {
|
|||
|
||||
if helpers::forcing_clang_based_tests() {
|
||||
enabled_llvm_projects.push("clang");
|
||||
enabled_llvm_projects.push("compiler-rt");
|
||||
}
|
||||
|
||||
if builder.config.llvm_polly {
|
||||
|
|
@ -467,6 +466,10 @@ impl Step for Llvm {
|
|||
|
||||
let mut enabled_llvm_runtimes = Vec::new();
|
||||
|
||||
if helpers::forcing_clang_based_tests() {
|
||||
enabled_llvm_runtimes.push("compiler-rt");
|
||||
}
|
||||
|
||||
if builder.config.llvm_offload {
|
||||
enabled_llvm_runtimes.push("offload");
|
||||
//FIXME(ZuseZ4): LLVM intends to drop the offload dependency on openmp.
|
||||
|
|
|
|||
|
|
@ -1429,52 +1429,56 @@ impl Config {
|
|||
|
||||
// Infer the rest of the configuration.
|
||||
|
||||
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
|
||||
// running on a completely different machine from where it was compiled.
|
||||
let mut cmd = helpers::git(None);
|
||||
// NOTE: we cannot support running from outside the repository because the only other path we have available
|
||||
// is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
|
||||
// We still support running outside the repository if we find we aren't in a git directory.
|
||||
|
||||
// NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
|
||||
// and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
|
||||
// has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
|
||||
cmd.arg("rev-parse").arg("--show-cdup");
|
||||
// Discard stderr because we expect this to fail when building from a tarball.
|
||||
let output = cmd
|
||||
.as_command_mut()
|
||||
.stderr(std::process::Stdio::null())
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|output| if output.status.success() { Some(output) } else { None });
|
||||
if let Some(output) = output {
|
||||
let git_root_relative = String::from_utf8(output.stdout).unwrap();
|
||||
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
|
||||
// and to resolve any relative components.
|
||||
let git_root = env::current_dir()
|
||||
.unwrap()
|
||||
.join(PathBuf::from(git_root_relative.trim()))
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let s = git_root.to_str().unwrap();
|
||||
|
||||
// Bootstrap is quite bad at handling /? in front of paths
|
||||
let git_root = match s.strip_prefix("\\\\?\\") {
|
||||
Some(p) => PathBuf::from(p),
|
||||
None => git_root,
|
||||
};
|
||||
// If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
|
||||
// for example, the build directory is inside of another unrelated git directory.
|
||||
// In that case keep the original `CARGO_MANIFEST_DIR` handling.
|
||||
//
|
||||
// NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
|
||||
// the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
|
||||
if git_root.join("src").join("stage0").exists() {
|
||||
config.src = git_root;
|
||||
}
|
||||
if let Some(src) = flags.src {
|
||||
config.src = src
|
||||
} else {
|
||||
// We're building from a tarball, not git sources.
|
||||
// We don't support pre-downloaded bootstrap in this case.
|
||||
// Infer the source directory. This is non-trivial because we want to support a downloaded bootstrap binary,
|
||||
// running on a completely different machine from where it was compiled.
|
||||
let mut cmd = helpers::git(None);
|
||||
// NOTE: we cannot support running from outside the repository because the only other path we have available
|
||||
// is set at compile time, which can be wrong if bootstrap was downloaded rather than compiled locally.
|
||||
// We still support running outside the repository if we find we aren't in a git directory.
|
||||
|
||||
// NOTE: We get a relative path from git to work around an issue on MSYS/mingw. If we used an absolute path,
|
||||
// and end up using MSYS's git rather than git-for-windows, we would get a unix-y MSYS path. But as bootstrap
|
||||
// has already been (kinda-cross-)compiled to Windows land, we require a normal Windows path.
|
||||
cmd.arg("rev-parse").arg("--show-cdup");
|
||||
// Discard stderr because we expect this to fail when building from a tarball.
|
||||
let output = cmd
|
||||
.as_command_mut()
|
||||
.stderr(std::process::Stdio::null())
|
||||
.output()
|
||||
.ok()
|
||||
.and_then(|output| if output.status.success() { Some(output) } else { None });
|
||||
if let Some(output) = output {
|
||||
let git_root_relative = String::from_utf8(output.stdout).unwrap();
|
||||
// We need to canonicalize this path to make sure it uses backslashes instead of forward slashes,
|
||||
// and to resolve any relative components.
|
||||
let git_root = env::current_dir()
|
||||
.unwrap()
|
||||
.join(PathBuf::from(git_root_relative.trim()))
|
||||
.canonicalize()
|
||||
.unwrap();
|
||||
let s = git_root.to_str().unwrap();
|
||||
|
||||
// Bootstrap is quite bad at handling /? in front of paths
|
||||
let git_root = match s.strip_prefix("\\\\?\\") {
|
||||
Some(p) => PathBuf::from(p),
|
||||
None => git_root,
|
||||
};
|
||||
// If this doesn't have at least `stage0`, we guessed wrong. This can happen when,
|
||||
// for example, the build directory is inside of another unrelated git directory.
|
||||
// In that case keep the original `CARGO_MANIFEST_DIR` handling.
|
||||
//
|
||||
// NOTE: this implies that downloadable bootstrap isn't supported when the build directory is outside
|
||||
// the source directory. We could fix that by setting a variable from all three of python, ./x, and x.ps1.
|
||||
if git_root.join("src").join("stage0").exists() {
|
||||
config.src = git_root;
|
||||
}
|
||||
} else {
|
||||
// We're building from a tarball, not git sources.
|
||||
// We don't support pre-downloaded bootstrap in this case.
|
||||
}
|
||||
}
|
||||
|
||||
if cfg!(test) {
|
||||
|
|
|
|||
|
|
@ -173,7 +173,7 @@ pub fn get_git_modified_files(
|
|||
config: &GitConfig<'_>,
|
||||
git_dir: Option<&Path>,
|
||||
extensions: &[&str],
|
||||
) -> Result<Option<Vec<String>>, String> {
|
||||
) -> Result<Vec<String>, String> {
|
||||
let merge_base = get_closest_merge_commit(git_dir, config, &[])?;
|
||||
|
||||
let mut git = Command::new("git");
|
||||
|
|
@ -186,7 +186,10 @@ pub fn get_git_modified_files(
|
|||
let (status, name) = f.trim().split_once(char::is_whitespace).unwrap();
|
||||
if status == "D" {
|
||||
None
|
||||
} else if Path::new(name).extension().map_or(false, |ext| {
|
||||
} else if Path::new(name).extension().map_or(extensions.is_empty(), |ext| {
|
||||
// If there is no extension, we allow the path if `extensions` is empty
|
||||
// If there is an extension, we allow it if `extension` is empty or it contains the
|
||||
// extension.
|
||||
extensions.is_empty() || extensions.contains(&ext.to_str().unwrap())
|
||||
}) {
|
||||
Some(name.to_owned())
|
||||
|
|
@ -195,7 +198,7 @@ pub fn get_git_modified_files(
|
|||
}
|
||||
})
|
||||
.collect();
|
||||
Ok(Some(files))
|
||||
Ok(files)
|
||||
}
|
||||
|
||||
/// Returns the files that haven't been added to git yet.
|
||||
|
|
|
|||
2
src/gcc
2
src/gcc
|
|
@ -1 +1 @@
|
|||
Subproject commit 48664a6cab29d48138ffa004b7978d52ef73e3ac
|
||||
Subproject commit 13cc8243226a9028bb08ab6c5e1c5fe6d533bcdf
|
||||
|
|
@ -747,8 +747,7 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
|
|||
}
|
||||
|
||||
let files =
|
||||
get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?
|
||||
.unwrap_or(vec![]);
|
||||
get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?;
|
||||
// Add new test cases to the list, it will be convenient in daily development.
|
||||
let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]);
|
||||
|
||||
|
|
|
|||
|
|
@ -14,11 +14,7 @@ fn main() -> ExitCode {
|
|||
&Vec::new(),
|
||||
);
|
||||
let modified_files = match modified_files {
|
||||
Ok(Some(files)) => files,
|
||||
Ok(None) => {
|
||||
eprintln!("git error");
|
||||
return ExitCode::FAILURE;
|
||||
}
|
||||
Ok(files) => files,
|
||||
Err(err) => {
|
||||
eprintln!("Could not get modified files from git: \"{err}\"");
|
||||
return ExitCode::FAILURE;
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
//@[elfv1-be] needs-llvm-components: powerpc
|
||||
//@[elfv2-be] compile-flags: --target powerpc64-unknown-linux-musl
|
||||
//@[elfv2-be] needs-llvm-components: powerpc
|
||||
//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu
|
||||
//@[elfv2-le] compile-flags: --target powerpc64le-unknown-linux-gnu -C target-cpu=pwr8
|
||||
//@[elfv2-le] needs-llvm-components: powerpc
|
||||
//@[aix] compile-flags: --target powerpc64-ibm-aix
|
||||
//@[aix] needs-llvm-components: powerpc
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
// ignore-tidy-linelength
|
||||
//@ assembly-output: emit-asm
|
||||
//@ compile-flags: -Copt-level=3 -Z merge-functions=disabled
|
||||
//@[z10] compile-flags: --target s390x-unknown-linux-gnu --cfg no_vector
|
||||
//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 --cfg no_vector
|
||||
//@[z10] needs-llvm-components: systemz
|
||||
//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-feature=+vector
|
||||
//@[z10_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10 -C target-feature=+vector
|
||||
//@[z10_vector] needs-llvm-components: systemz
|
||||
//@[z13] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13
|
||||
//@[z13] needs-llvm-components: systemz
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: s390x
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[s390x] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10
|
||||
//@[s390x] needs-llvm-components: systemz
|
||||
|
||||
#![crate_type = "rlib"]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
//@ only-x86_64
|
||||
//@ compile-flags: -C opt-level=3
|
||||
//@ compile-flags: -C opt-level=3 -C target-cpu=x86-64
|
||||
#![crate_type = "lib"]
|
||||
|
||||
/// Check that the fast-path of `is_ascii` uses a `pmovmskb` instruction.
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ pub fn df2(x: &[f64], bx: &[f64], y: f64) -> f64 {
|
|||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
::core::panicking::panic("not implemented")
|
||||
}
|
||||
#[rustc_autodiff(ForwardFirst, Dual, Const, Const,)]
|
||||
#[rustc_autodiff(Forward, Dual, Const, Const,)]
|
||||
#[inline(never)]
|
||||
pub fn df3(x: &[f64], bx: &[f64], y: f64) -> f64 {
|
||||
unsafe { asm!("NOP", options(pure, nomem)); };
|
||||
|
|
@ -73,10 +73,6 @@ pub fn df4() {
|
|||
}
|
||||
#[rustc_autodiff]
|
||||
#[inline(never)]
|
||||
#[rustc_autodiff]
|
||||
#[inline(never)]
|
||||
#[rustc_autodiff]
|
||||
#[inline(never)]
|
||||
pub fn f5(x: &[f64], y: f64) -> f64 {
|
||||
::core::panicking::panic("not implemented")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ pub fn f2(x: &[f64], y: f64) -> f64 {
|
|||
unimplemented!()
|
||||
}
|
||||
|
||||
#[autodiff(df3, ForwardFirst, Dual, Const, Const)]
|
||||
#[autodiff(df3, Forward, Dual, Const, Const)]
|
||||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ pub fn df2() {
|
|||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
::core::panicking::panic("not implemented")
|
||||
}
|
||||
#[rustc_autodiff(ReverseFirst, Duplicated, Const, Active,)]
|
||||
#[rustc_autodiff(Reverse, Duplicated, Const, Active,)]
|
||||
#[inline(never)]
|
||||
pub fn df3(x: &[f64], dx: &mut [f64], y: f64, dret: f64) -> f64 {
|
||||
unsafe { asm!("NOP", options(pure, nomem)); };
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ pub fn f1(x: &[f64], y: f64) -> f64 {
|
|||
#[autodiff(df2, Reverse)]
|
||||
pub fn f2() {}
|
||||
|
||||
#[autodiff(df3, ReverseFirst, Duplicated, Const, Active)]
|
||||
#[autodiff(df3, Reverse, Duplicated, Const, Active)]
|
||||
pub fn f3(x: &[f64], y: f64) -> f64 {
|
||||
unimplemented!()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,7 +41,13 @@ fn symbols_check_archive(path: &str) {
|
|||
continue; // Unfortunately LLVM doesn't allow us to mangle this symbol
|
||||
}
|
||||
|
||||
panic!("Unmangled symbol found: {name}");
|
||||
if name.contains(".llvm.") {
|
||||
// Starting in LLVM 21 we get various implementation-detail functions which
|
||||
// contain .llvm. that are not a problem.
|
||||
continue;
|
||||
}
|
||||
|
||||
panic!("Unmangled symbol found in {path}: {name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,7 +81,13 @@ fn symbols_check(path: &str) {
|
|||
continue; // Unfortunately LLVM doesn't allow us to mangle this symbol
|
||||
}
|
||||
|
||||
panic!("Unmangled symbol found: {name}");
|
||||
if name.contains(".llvm.") {
|
||||
// Starting in LLVM 21 we get various implementation-detail functions which
|
||||
// contain .llvm. that are not a problem.
|
||||
continue;
|
||||
}
|
||||
|
||||
panic!("Unmangled symbol found in {path}: {name}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
//@ only-x86_64
|
||||
//@ build-pass
|
||||
//@ ignore-pass (test emits codegen-time warnings)
|
||||
//@ compile-flags: -C target-feature=-avx
|
||||
|
||||
#![feature(avx512_target_feature)]
|
||||
#![feature(portable_simd)]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:64:11
|
||||
--> $DIR/simd-abi-checks-avx.rs:65:11
|
||||
|
|
||||
LL | f(g());
|
||||
| ^^^ function called here
|
||||
|
|
@ -10,7 +10,7 @@ LL | f(g());
|
|||
= note: `#[warn(abi_unsupported_vector_types)]` on by default
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:64:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:65:9
|
||||
|
|
||||
LL | f(g());
|
||||
| ^^^^^^ function called here
|
||||
|
|
@ -20,7 +20,7 @@ LL | f(g());
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:72:14
|
||||
--> $DIR/simd-abi-checks-avx.rs:73:14
|
||||
|
|
||||
LL | gavx(favx());
|
||||
| ^^^^^^ function called here
|
||||
|
|
@ -30,7 +30,7 @@ LL | gavx(favx());
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:72:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:73:9
|
||||
|
|
||||
LL | gavx(favx());
|
||||
| ^^^^^^^^^^^^ function called here
|
||||
|
|
@ -40,7 +40,7 @@ LL | gavx(favx());
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:84:19
|
||||
--> $DIR/simd-abi-checks-avx.rs:85:19
|
||||
|
|
||||
LL | w(Wrapper(g()));
|
||||
| ^^^ function called here
|
||||
|
|
@ -50,7 +50,7 @@ LL | w(Wrapper(g()));
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:84:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:85:9
|
||||
|
|
||||
LL | w(Wrapper(g()));
|
||||
| ^^^^^^^^^^^^^^^ function called here
|
||||
|
|
@ -60,7 +60,7 @@ LL | w(Wrapper(g()));
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:100:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:101:9
|
||||
|
|
||||
LL | some_extern();
|
||||
| ^^^^^^^^^^^^^ function called here
|
||||
|
|
@ -70,7 +70,7 @@ LL | some_extern();
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:27:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:28:1
|
||||
|
|
||||
LL | unsafe extern "C" fn g() -> __m256 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -80,7 +80,7 @@ LL | unsafe extern "C" fn g() -> __m256 {
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:21:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:22:1
|
||||
|
|
||||
LL | unsafe extern "C" fn f(_: __m256) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -90,7 +90,7 @@ LL | unsafe extern "C" fn f(_: __m256) {
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:15:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:16:1
|
||||
|
|
||||
LL | unsafe extern "C" fn w(_: Wrapper) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -100,7 +100,7 @@ LL | unsafe extern "C" fn w(_: Wrapper) {
|
|||
= help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
|
||||
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:57:8
|
||||
--> $DIR/simd-abi-checks-avx.rs:58:8
|
||||
|
|
||||
LL | || g()
|
||||
| ^^^ function called here
|
||||
|
|
@ -113,7 +113,7 @@ warning: 11 warnings emitted
|
|||
|
||||
Future incompatibility report: Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:64:11
|
||||
--> $DIR/simd-abi-checks-avx.rs:65:11
|
||||
|
|
||||
LL | f(g());
|
||||
| ^^^ function called here
|
||||
|
|
@ -125,7 +125,7 @@ LL | f(g());
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:64:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:65:9
|
||||
|
|
||||
LL | f(g());
|
||||
| ^^^^^^ function called here
|
||||
|
|
@ -137,7 +137,7 @@ LL | f(g());
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:72:14
|
||||
--> $DIR/simd-abi-checks-avx.rs:73:14
|
||||
|
|
||||
LL | gavx(favx());
|
||||
| ^^^^^^ function called here
|
||||
|
|
@ -149,7 +149,7 @@ LL | gavx(favx());
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:72:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:73:9
|
||||
|
|
||||
LL | gavx(favx());
|
||||
| ^^^^^^^^^^^^ function called here
|
||||
|
|
@ -161,7 +161,7 @@ LL | gavx(favx());
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:84:19
|
||||
--> $DIR/simd-abi-checks-avx.rs:85:19
|
||||
|
|
||||
LL | w(Wrapper(g()));
|
||||
| ^^^ function called here
|
||||
|
|
@ -173,7 +173,7 @@ LL | w(Wrapper(g()));
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:84:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:85:9
|
||||
|
|
||||
LL | w(Wrapper(g()));
|
||||
| ^^^^^^^^^^^^^^^ function called here
|
||||
|
|
@ -185,7 +185,7 @@ LL | w(Wrapper(g()));
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:100:9
|
||||
--> $DIR/simd-abi-checks-avx.rs:101:9
|
||||
|
|
||||
LL | some_extern();
|
||||
| ^^^^^^^^^^^^^ function called here
|
||||
|
|
@ -197,7 +197,7 @@ LL | some_extern();
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:27:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:28:1
|
||||
|
|
||||
LL | unsafe extern "C" fn g() -> __m256 {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -209,7 +209,7 @@ LL | unsafe extern "C" fn g() -> __m256 {
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function definition uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:21:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:22:1
|
||||
|
|
||||
LL | unsafe extern "C" fn f(_: __m256) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -221,7 +221,7 @@ LL | unsafe extern "C" fn f(_: __m256) {
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function definition uses SIMD vector type `Wrapper` which (with the chosen ABI) requires the `avx` target feature, which is not enabled
|
||||
--> $DIR/simd-abi-checks-avx.rs:15:1
|
||||
--> $DIR/simd-abi-checks-avx.rs:16:1
|
||||
|
|
||||
LL | unsafe extern "C" fn w(_: Wrapper) {
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function defined here
|
||||
|
|
@ -233,7 +233,7 @@ LL | unsafe extern "C" fn w(_: Wrapper) {
|
|||
|
||||
Future breakage diagnostic:
|
||||
warning: this function call uses SIMD vector type `std::arch::x86_64::__m256` which (with the chosen ABI) requires the `avx` target feature, which is not enabled in the caller
|
||||
--> $DIR/simd-abi-checks-avx.rs:57:8
|
||||
--> $DIR/simd-abi-checks-avx.rs:58:8
|
||||
|
|
||||
LL | || g()
|
||||
| ^^^ function called here
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//@ add-core-stubs
|
||||
//@ revisions: z10 z13_no_vector z13_soft_float
|
||||
//@ build-fail
|
||||
//@[z10] compile-flags: --target s390x-unknown-linux-gnu
|
||||
//@[z10] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z10
|
||||
//@[z10] needs-llvm-components: systemz
|
||||
//@[z13_no_vector] compile-flags: --target s390x-unknown-linux-gnu -C target-cpu=z13 -C target-feature=-vector
|
||||
//@[z13_no_vector] needs-llvm-components: systemz
|
||||
|
|
|
|||
21
tests/ui/asm/naked-functions-target-feature.rs
Normal file
21
tests/ui/asm/naked-functions-target-feature.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
//@ build-pass
|
||||
//@ needs-asm-support
|
||||
|
||||
#![feature(naked_functions, naked_functions_target_feature)]
|
||||
#![crate_type = "lib"]
|
||||
|
||||
use std::arch::{asm, naked_asm};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "sse2")]
|
||||
#[naked]
|
||||
pub unsafe extern "C" fn compatible_target_feature() {
|
||||
naked_asm!("");
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[target_feature(enable = "neon")]
|
||||
#[naked]
|
||||
pub unsafe extern "C" fn compatible_target_feature() {
|
||||
naked_asm!("");
|
||||
}
|
||||
|
|
@ -230,13 +230,6 @@ pub unsafe extern "C" fn compatible_codegen_attributes() {
|
|||
naked_asm!("", options(raw));
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[target_feature(enable = "sse2")]
|
||||
#[naked]
|
||||
pub unsafe extern "C" fn compatible_target_feature() {
|
||||
naked_asm!("");
|
||||
}
|
||||
|
||||
#[doc = "foo bar baz"]
|
||||
/// a doc comment
|
||||
// a normal comment
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
//@ needs-asm-support
|
||||
//@ only-x86_64
|
||||
|
||||
#![feature(naked_functions)]
|
||||
|
||||
use std::arch::naked_asm;
|
||||
|
||||
#[naked]
|
||||
#[target_feature(enable = "avx2")]
|
||||
//~^ ERROR: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions
|
||||
extern "C" fn naked() {
|
||||
unsafe { naked_asm!("") }
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
error[E0658]: `#[target_feature(/* ... */)]` is currently unstable on `#[naked]` functions
|
||||
--> $DIR/feature-gate-naked_functions_target_feature.rs:9:1
|
||||
|
|
||||
LL | #[target_feature(enable = "avx2")]
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: see issue #138568 <https://github.com/rust-lang/rust/issues/138568> for more information
|
||||
= help: add `#![feature(naked_functions_target_feature)]` to the crate attributes to enable
|
||||
= note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
|
||||
|
||||
error: aborting due to 1 previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0658`.
|
||||
Loading…
Add table
Add a link
Reference in a new issue