Skip to content

Commit 5e0b4a1

Browse files
committed
verify rule validity
1 parent dd63a4e commit 5e0b4a1

5 files changed

Lines changed: 139 additions & 19 deletions

File tree

enzyme/Enzyme/MLIR/Dialect/EnzymeOps.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,11 @@ def CustomReverseRuleOp : Enzyme_Op<"custom_reverse_rule", [IsolatedFromAbove, S
206206
let assemblyFormat = [{
207207
$sym_name $body attr-dict-with-keyword
208208
}];
209+
210+
let extraClassDeclaration = [{
211+
llvm::LogicalResult activityMatch(llvm::ArrayRef<enzyme::Activity> ArgActivity,
212+
llvm::ArrayRef<enzyme::Activity> RetActivity);
213+
}];
209214
}
210215

211216
def CustomReverseRuleAugmentedPrimalOp : Enzyme_Op<"custom_reverse_rule.augmented_primal", [

enzyme/Enzyme/MLIR/Dialect/Ops.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -913,6 +913,39 @@ static void printAugmentedFn(OpAsmPrinter &p, FunctionType fnType,
913913
/*printBlockTerminators*/ true);
914914
}
915915

916+
//===----------------------------------------------------------------------===//
917+
// CustomReverseRuleOp
918+
//===----------------------------------------------------------------------===//
919+
920+
llvm::LogicalResult CustomReverseRuleOp::activityMatch(
921+
llvm::ArrayRef<enzyme::Activity> argActivity,
922+
llvm::ArrayRef<enzyme::Activity> retActivity) {
923+
auto selfArgActivity = getActivity();
924+
auto selfRetActivity = getRetActivity();
925+
926+
if (selfArgActivity.size() != argActivity.size() ||
927+
selfRetActivity.size() != retActivity.size())
928+
return failure();
929+
930+
for (auto [attr, act] : llvm::zip_equal(selfArgActivity, argActivity)) {
931+
auto iattr = cast<ActivityAttr>(attr);
932+
auto val = iattr.getValue();
933+
934+
if (val == Activity::enzyme_const && act != Activity::enzyme_const)
935+
return failure();
936+
}
937+
938+
for (auto [attr, act] : llvm::zip_equal(selfRetActivity, retActivity)) {
939+
auto iattr = cast<ActivityAttr>(attr);
940+
auto val = iattr.getValue();
941+
942+
if (val == Activity::enzyme_const && act != Activity::enzyme_const)
943+
return failure();
944+
}
945+
946+
return success();
947+
}
948+
916949
//===----------------------------------------------------------------------===//
917950
// CustomReverseRuleAugmentedPrimalOp
918951
//===----------------------------------------------------------------------===//

enzyme/Enzyme/MLIR/Implementations/CoreDialectsAutoDiffImplementations.cpp

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,33 @@ static LogicalResult callReverseHandlerSplit(Operation *orig,
692692
// point it at the rule the callee named.
693693
cr = cast<CustomReverseRuleOp>(crOp);
694694
primalCall = cast<CallAugmentedPrimalOp>(gutils->getNewFromOriginal(orig));
695+
696+
auto diffeTypeToActivity = [](DIFFE_TYPE act) {
697+
switch (act) {
698+
case DIFFE_TYPE::CONSTANT:
699+
return Activity::enzyme_const;
700+
case DIFFE_TYPE::OUT_DIFF:
701+
return Activity::enzyme_active;
702+
case DIFFE_TYPE::DUP_ARG:
703+
return Activity::enzyme_dup;
704+
case DIFFE_TYPE::DUP_NONEED:
705+
return Activity::enzyme_dupnoneed;
706+
default:
707+
llvm_unreachable("cannot handle act");
708+
}
709+
};
710+
711+
SmallVector<enzyme::Activity> ArgActivityAct =
712+
llvm::map_to_vector(ArgActivity, diffeTypeToActivity);
713+
SmallVector<enzyme::Activity> RetActivityAct =
714+
llvm::map_to_vector(RetActivity, diffeTypeToActivity);
715+
716+
if (failed(cr.activityMatch(ArgActivityAct, RetActivityAct)))
717+
return orig->emitError()
718+
<< "could not find a rule with the right activity (rule activity="
719+
<< cr.getActivity() << ", ret_activity=" << cr.getRetActivity()
720+
<< ")";
721+
695722
} else {
696723
std::vector<bool> overwritten_args(narg, true);
697724
std::vector<bool> returnShadow(nret, false);

enzyme/Enzyme/MLIR/Interfaces/EnzymeLogicReverse.cpp

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -331,13 +331,41 @@ FlatSymbolRefAttr MEnzymeLogic::CreateSplitModeDiff(
331331

332332
SymbolTable symbolTable(SymbolTable::getNearestSymbolTable(fn));
333333

334+
SmallVector<mlir::Attribute> argAttrs;
335+
if (auto prevArgAttrs = fn.getAllArgAttrs())
336+
argAttrs.assign(prevArgAttrs.begin(), prevArgAttrs.end());
337+
338+
SmallVector<Attribute> argActivityAttrs;
339+
for (auto [i, act] : llvm::enumerate(constants)) {
340+
argActivityAttrs.push_back(activityFromDiffeType(fn.getContext(), act));
341+
342+
if (!argAttrs.empty() && act == DIFFE_TYPE::DUP_ARG)
343+
argAttrs.insert(argAttrs.begin() + i + 1 -
344+
(argAttrs.size() - fn.getNumArguments()),
345+
nullptr);
346+
}
347+
348+
SmallVector<Attribute> retActivityAttrs;
349+
for (auto act : retType)
350+
retActivityAttrs.push_back(activityFromDiffeType(fn.getContext(), act));
351+
334352
if (auto existingCustomRule =
335353
fn->getAttrOfType<FlatSymbolRefAttr>("enzyme.custom_rule")) {
336354
auto CR = symbolTable.lookup<enzyme::CustomReverseRuleOp>(
337355
existingCustomRule.getValue());
338356

339357
if (CR) {
340-
return existingCustomRule;
358+
auto getAttrActivity = [](auto attr) {
359+
return cast<ActivityAttr>(attr).getValue();
360+
};
361+
362+
SmallVector<Activity> ArgActivity =
363+
llvm::map_to_vector(argActivityAttrs, getAttrActivity);
364+
SmallVector<Activity> RetActivity =
365+
llvm::map_to_vector(retActivityAttrs, getAttrActivity);
366+
367+
if (!failed(CR.activityMatch(ArgActivity, RetActivity)))
368+
return existingCustomRule;
341369
}
342370
}
343371

@@ -360,24 +388,6 @@ FlatSymbolRefAttr MEnzymeLogic::CreateSplitModeDiff(
360388

361389
auto name = fn.getName();
362390

363-
SmallVector<mlir::Attribute> argAttrs;
364-
if (auto prevArgAttrs = fn.getAllArgAttrs())
365-
argAttrs.assign(prevArgAttrs.begin(), prevArgAttrs.end());
366-
367-
SmallVector<Attribute> argActivityAttrs;
368-
for (auto [i, act] : llvm::enumerate(constants)) {
369-
argActivityAttrs.push_back(activityFromDiffeType(fn.getContext(), act));
370-
371-
if (!argAttrs.empty() && act == DIFFE_TYPE::DUP_ARG)
372-
argAttrs.insert(argAttrs.begin() + i + 1 -
373-
(argAttrs.size() - fn.getNumArguments()),
374-
nullptr);
375-
}
376-
377-
SmallVector<Attribute> retActivityAttrs;
378-
for (auto act : retType)
379-
retActivityAttrs.push_back(activityFromDiffeType(fn.getContext(), act));
380-
381391
auto argActivityAttr = ArrayAttr::get(fn.getContext(), argActivityAttrs);
382392
auto retActivityAttr = ArrayAttr::get(fn.getContext(), retActivityAttrs);
383393

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// RUN: %eopt %s --enzyme-wrap="infn=main outfn= argTys=enzyme_active,enzyme_active retTys=enzyme_active mode=ReverseModeCombined" --verify-diagnostics
2+
3+
module {
4+
enzyme.custom_reverse_rule @reverse_f {
5+
%cache_exp = "enzyme.init"() : () -> !enzyme.Cache<f32>
6+
%cache_arg1 = "enzyme.init"() : () -> !enzyme.Cache<f32>
7+
8+
enzyme.custom_reverse_rule.augmented_primal (%arg0: f32, %arg1: f32) -> f32 {
9+
"enzyme.push"(%cache_arg1, %arg1) : (!enzyme.Cache<f32>, f32) -> ()
10+
%0 = math.exp %arg0 : f32
11+
"enzyme.push"(%cache_exp, %0) : (!enzyme.Cache<f32>, f32) -> ()
12+
%1 = arith.mulf %arg1, %arg0 : f32
13+
enzyme.yield %1 : f32
14+
}
15+
16+
enzyme.custom_reverse_rule.augmented_primal (%dres: f32) -> f32 {
17+
%exp = "enzyme.pop"(%cache_exp) : (!enzyme.Cache<f32>) -> f32
18+
%arg1 = "enzyme.pop"(%cache_exp) : (!enzyme.Cache<f32>) -> f32
19+
%d1 = arith.mulf %dres, %arg1 : f32
20+
%darg0 = arith.mulf %exp, %d1 : f32
21+
enzyme.yield %darg0 : f32
22+
}
23+
24+
enzyme.yield
25+
} attributes {
26+
activity=[#enzyme<activity enzyme_active>,
27+
#enzyme<activity enzyme_const>],
28+
ret_activity=[#enzyme<activity enzyme_active>],
29+
function_type = (f32, f32) -> f32
30+
}
31+
32+
func.func @f(%arg0:f32, %arg1: f32) -> f32 attributes {enzyme.custom_rule = @reverse_f} {
33+
%0 = math.exp %arg0 : f32
34+
%1 = arith.mulf %arg1, %arg0 : f32
35+
return %1 : f32
36+
}
37+
38+
func.func @main(%arg0: f32, %arg1: f32) -> f32 {
39+
40+
// expected-error @below {{could not find a rule with the right activity (rule activity=[#enzyme<activity enzyme_active>, #enzyme<activity enzyme_const>], ret_activity=[#enzyme<activity enzyme_active>])}}
41+
%0 = func.call @f( %arg0, %arg1 ) : (f32, f32) -> f32
42+
43+
return %0 : f32
44+
}
45+
}

0 commit comments

Comments
 (0)