Skip to content

Commit a9b4849

Browse files
Rollup merge of rust-lang#154245 - ZuseZ4:autodiff-trait-support, r=JonathanBrouwer,jdonszelmann
Allow applying autodiff macros to trait functions. It will use enzyme to generate a default derivative implementation, which can be overwritten by the user. closes: rust-lang#153329 r? @JonathanBrouwer
2 parents d7beee5 + 26c9f72 commit a9b4849

5 files changed

Lines changed: 94 additions & 16 deletions

File tree

compiler/rustc_attr_parsing/src/attributes/autodiff.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ impl<S: Stage> SingleAttributeParser<S> for RustcAutodiffParser {
2323
Allow(Target::Fn),
2424
Allow(Target::Method(MethodKind::Inherent)),
2525
Allow(Target::Method(MethodKind::Trait { body: true })),
26+
Allow(Target::Method(MethodKind::Trait { body: false })),
2627
Allow(Target::Method(MethodKind::TraitImpl)),
2728
]);
2829
const TEMPLATE: AttributeTemplate = template!(

compiler/rustc_builtin_macros/src/autodiff.rs

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,18 @@ mod llvm_enzyme {
224224
}
225225
_ => None,
226226
},
227-
Annotatable::AssocItem(assoc_item, Impl { of_trait: _ }) => match &assoc_item.kind {
228-
ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some((
229-
assoc_item.vis.clone(),
230-
sig.clone(),
231-
ident.clone(),
232-
generics.clone(),
233-
true,
234-
)),
235-
_ => None,
236-
},
227+
Annotatable::AssocItem(assoc_item, _ctxt @ (Impl { of_trait: _ } | Trait)) => {
228+
match &assoc_item.kind {
229+
ast::AssocItemKind::Fn(box ast::Fn { sig, ident, generics, .. }) => Some((
230+
assoc_item.vis.clone(),
231+
sig.clone(),
232+
ident.clone(),
233+
generics.clone(),
234+
true,
235+
)),
236+
_ => None,
237+
}
238+
}
237239
_ => None,
238240
}) else {
239241
dcx.emit_err(errors::AutoDiffInvalidApplication { span: item.span() });
@@ -393,14 +395,14 @@ mod llvm_enzyme {
393395
}
394396
Annotatable::Item(iitem.clone())
395397
}
396-
Annotatable::AssocItem(ref mut assoc_item, i @ Impl { .. }) => {
398+
Annotatable::AssocItem(ref mut assoc_item, ctxt @ (Impl { .. } | Trait)) => {
397399
if !assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &attr.kind)) {
398400
assoc_item.attrs.push(attr);
399401
}
400402
if assoc_item.attrs.iter().any(|a| same_attribute(&a.kind, &inline_never.kind)) {
401403
has_inline_never = true;
402404
}
403-
Annotatable::AssocItem(assoc_item.clone(), i)
405+
Annotatable::AssocItem(assoc_item.clone(), ctxt)
404406
}
405407
Annotatable::Stmt(ref mut stmt) => {
406408
match stmt.kind {
@@ -441,7 +443,7 @@ mod llvm_enzyme {
441443
}
442444

443445
let d_annotatable = match &item {
444-
Annotatable::AssocItem(_, _) => {
446+
Annotatable::AssocItem(_, ctxt) => {
445447
let assoc_item: AssocItemKind = ast::AssocItemKind::Fn(d_fn);
446448
let d_fn = Box::new(ast::AssocItem {
447449
attrs: d_attrs,
@@ -451,7 +453,7 @@ mod llvm_enzyme {
451453
kind: assoc_item,
452454
tokens: None,
453455
});
454-
Annotatable::AssocItem(d_fn, Impl { of_trait: false })
456+
Annotatable::AssocItem(d_fn, *ctxt)
455457
}
456458
Annotatable::Item(_) => {
457459
let mut d_fn = ecx.item(span, d_attrs, ItemKind::Fn(d_fn));

compiler/rustc_expand/src/base.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -149,14 +149,14 @@ impl Annotatable {
149149
pub fn expect_trait_item(self) -> Box<ast::AssocItem> {
150150
match self {
151151
Annotatable::AssocItem(i, AssocCtxt::Trait) => i,
152-
_ => panic!("expected Item"),
152+
_ => panic!("expected trait item"),
153153
}
154154
}
155155

156156
pub fn expect_impl_item(self) -> Box<ast::AssocItem> {
157157
match self {
158158
Annotatable::AssocItem(i, AssocCtxt::Impl { .. }) => i,
159-
_ => panic!("expected Item"),
159+
_ => panic!("expected impl item"),
160160
}
161161
}
162162

tests/pretty/autodiff/trait.pp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat
2+
//@ no-prefer-dynamic
3+
//@ needs-enzyme
4+
5+
// Just check it does not crash for now
6+
// CHECK: ;
7+
#![feature(autodiff)]
8+
#![feature(core_intrinsics)]
9+
#![feature(rustc_attrs)]
10+
11+
use std::autodiff::autodiff_reverse;
12+
13+
struct Foo {
14+
a: f64,
15+
}
16+
17+
trait MyTrait {
18+
#[rustc_autodiff]
19+
fn f(&self, x: f64) -> f64;
20+
#[rustc_autodiff(Reverse, 1, Const, Active, Active)]
21+
fn df(&self, x: f64, seed: f64) -> (f64, f64) {
22+
std::hint::black_box(seed);
23+
std::hint::black_box(x);
24+
::std::intrinsics::autodiff(
25+
Self::f as for<'a> fn(&'a Self, _: f64) -> f64,
26+
Self::df,
27+
(self, x, seed),
28+
)
29+
30+
}
31+
}
32+
33+
impl MyTrait for Foo {
34+
fn f(&self, x: f64) -> f64 {
35+
x.sin()
36+
}
37+
}
38+
39+
fn main() {
40+
let foo = Foo { a: 3.0f64 };
41+
dbg!(foo.df(2.0, 1.0));
42+
dbg!(2.0_f64.cos());
43+
}

tests/pretty/autodiff/trait.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//@ compile-flags: -Zautodiff=Enable -Zautodiff=NoPostopt -C opt-level=3 -Clto=fat
2+
//@ no-prefer-dynamic
3+
//@ needs-enzyme
4+
5+
// Just check it does not crash for now
6+
// CHECK: ;
7+
#![feature(autodiff)]
8+
#![feature(core_intrinsics)]
9+
#![feature(rustc_attrs)]
10+
11+
use std::autodiff::autodiff_reverse;
12+
13+
struct Foo {
14+
a: f64,
15+
}
16+
17+
trait MyTrait {
18+
#[autodiff_reverse(df, Const, Active, Active)]
19+
fn f(&self, x: f64) -> f64;
20+
}
21+
22+
impl MyTrait for Foo {
23+
fn f(&self, x: f64) -> f64 {
24+
x.sin()
25+
}
26+
}
27+
28+
fn main() {
29+
let foo = Foo { a: 3.0f64 };
30+
dbg!(foo.df(2.0, 1.0));
31+
dbg!(2.0_f64.cos());
32+
}

0 commit comments

Comments
 (0)