245 SmallVectorImpl<GlobalVariable *> &globalsToErase,
246 bool PreserveCustomRuleLinkage) {
247 if (g.hasInitializer()) {
248 if (
auto CA = dyn_cast<ConstantAggregate>(g.getInitializer())) {
249 if (CA->getNumOperands() < numargs) {
250 llvm::errs() << M <<
"\n";
251 llvm::errs() <<
"Use of " << handlername
253 "constant of size at least "
254 << numargs <<
" " << g <<
"\n";
255 llvm_unreachable(handlername);
257 Function *Fs[numargs];
258 for (
size_t i = 0; i < numargs; i++) {
259 Value *V = CA->getOperand(i);
260 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
261 V = CE->getOperand(0);
263 if (
auto CA = dyn_cast<ConstantAggregate>(V))
264 V = CA->getOperand(0);
265 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
266 V = CE->getOperand(0);
268 if (
auto F = dyn_cast<Function>(V)) {
271 llvm::errs() << M <<
"\n";
272 llvm::errs() <<
"Param of " << handlername
277 llvm_unreachable(handlername);
281 SmallSet<size_t, 1> byref;
284 assert(numargs >= 3);
285 for (
size_t i = numargs; i < CA->getNumOperands(); i++) {
286 Value *V = CA->getOperand(i);
287 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
288 V = CE->getOperand(0);
290 if (
auto CA = dyn_cast<ConstantAggregate>(V))
291 V = CA->getOperand(0);
292 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
293 V = CE->getOperand(0);
295 if (
auto GV = dyn_cast<GlobalVariable>(V)) {
296 if (GV->isConstant())
297 if (
auto C = GV->getInitializer())
298 if (
auto CA = dyn_cast<ConstantDataArray>(C))
299 if (CA->getType()->getElementType()->isIntegerTy(8) &&
302 auto str = CA->getAsCString();
306 for (
size_t i =
str.size() - 1, len = strlen(
"byref_");
309 if (c <
'0' || c >
'9') {
318 byref.insert(argnum);
323 llvm::errs() << M <<
"\n";
324 llvm::errs() <<
"Use of " << handlername
325 <<
" possible post args include 'byref_ret'"
327 llvm_unreachable(handlername);
331 for (
size_t fn = 1; fn <= 2; fn++) {
332 Function *F = Fs[fn];
334 size_t nonSRetSize = 0;
335 for (
size_t i = 0; i < F->arg_size(); i++)
336 if (!F->hasParamAttribute(i, Attribute::StructRet))
344 SmallVector<Type *, 3> args;
345 Type *sretTy =
nullptr;
348 for (
auto &arg : F->args()) {
349 if (!F->hasParamAttribute(i, Attribute::StructRet)) {
350 if (!byref.count(realidx))
351 args.push_back(arg.getType());
354 Type *subTy =
nullptr;
355#if LLVM_VERSION_MAJOR < 17
356 subTy = arg.getType()->getPointerElementType();
359 args.push_back(subTy);
363 llvm::Type *T =
nullptr;
364#if LLVM_VERSION_MAJOR > 12
365 T = F->getParamAttribute(i, Attribute::StructRet)
368 T = arg.getType()->getPointerElementType();
374 Type *RT = F->getReturnType();
376 assert(RT->isVoidTy());
380 FunctionType::get(RT, args, F->getFunctionType()->isVarArg());
382 Function::Create(FTy, Function::LinkageTypes::InternalLinkage,
383 "fixbyval_" + F->getName(), F->getParent());
385 AllocaInst *AI =
nullptr;
387 BasicBlock::Create(NewF->getContext(),
"entry", NewF);
390 AI = bb.CreateAlloca(sretTy);
391 SmallVector<Value *, 3> argVs;
392 auto arg = NewF->arg_begin();
394 for (
size_t i = 0; i < F->arg_size(); i++) {
395 if (!F->hasParamAttribute(i, Attribute::StructRet)) {
396 arg->setName(
"arg" + Twine(realidx));
397 if (!byref.count(realidx))
398 argVs.push_back(arg);
400 auto A = bb.CreateAlloca(arg->getType());
401 bb.CreateStore(arg, A);
410 auto cal = bb.CreateCall(F, argVs);
411 cal->setCallingConv(F->getCallingConv());
414 Value *res = bb.CreateLoad(sretTy, AI);
416 }
else if (!RT->isVoidTy()) {
424 if (PreserveCustomRuleLinkage)
428 llvm::MDTuple::get(Fs[0]->getContext(),
429 {llvm::ValueAsMetadata::get(Fs[1])}));
430 if (PreserveCustomRuleLinkage)
434 llvm::MDTuple::get(Fs[0]->getContext(),
435 {llvm::ValueAsMetadata::get(Fs[2])}));
437 assert(numargs == 2);
438 if (PreserveCustomRuleLinkage)
442 llvm::MDTuple::get(Fs[0]->getContext(),
443 {llvm::ValueAsMetadata::get(Fs[1])}));
445 assert(numargs == 3);
446 if (PreserveCustomRuleLinkage)
450 llvm::MDTuple::get(Fs[0]->getContext(),
451 {llvm::ValueAsMetadata::get(Fs[1])}));
452 if (PreserveCustomRuleLinkage)
455 "enzyme_splitderivative",
456 llvm::MDTuple::get(Fs[0]->getContext(),
457 {llvm::ValueAsMetadata::get(Fs[2])}));
459 assert(
"Unknown mode");
462 llvm::errs() << M <<
"\n";
463 llvm::errs() <<
"Use of " << handlername
465 "constant aggregate "
467 llvm_unreachable(handlername);
470 llvm::errs() << M <<
"\n";
471 llvm::errs() <<
"Use of " << handlername
473 "constant array of size "
474 << numargs <<
" " << g <<
"\n";
475 llvm_unreachable(handlername);
477 globalsToErase.push_back(&g);
481 bool PreserveCustomRuleLinkage =
true) {
482 bool changed =
false;
483 constexpr static const char gradient_handler_name[] =
484 "__enzyme_register_gradient";
485 constexpr static const char derivative_handler_name[] =
486 "__enzyme_register_derivative";
487 constexpr static const char splitderivative_handler_name[] =
488 "__enzyme_register_splitderivative";
494 SmallVector<CallInst *, 4> functionLikeCalls;
495 for (Function &Caller : M) {
496 for (BasicBlock &BB : Caller) {
497 for (Instruction &I : BB) {
498 auto *
Call = dyn_cast<CallInst>(&I);
503 dyn_cast<Function>(
Call->getCalledOperand()->stripPointerCasts());
504 if (!Hook || !
startsWith(Hook->getName(),
"f__enzyme_function_like"))
507 if (
Call->arg_size() != 2) {
508 errs() <<
"Fortran enzyme_function_like requires exactly a "
509 "function and a function name\n"
511 llvm_unreachable(
"invalid Fortran enzyme_function_like call");
514 auto *NameGlobal = dyn_cast<GlobalVariable>(
515 Call->getArgOperand(1)->stripPointerCasts());
517 errs() <<
"Second argument of Fortran enzyme_function_like must "
518 "be an enzyme_math_* function name\n"
519 << *
Call->getArgOperand(1) <<
"\n";
521 "invalid Fortran enzyme_function_like function name");
524 StringRef FunctionName = NameGlobal->getName();
525 if (!FunctionName.consume_front(
"enzyme_math_")) {
526 errs() <<
"Fortran enzyme_function_like function name must use "
527 "the enzyme_math_* BIND(C) naming convention\n"
528 << *NameGlobal <<
"\n";
530 "invalid Fortran enzyme_function_like function name");
534 functionLikeCalls.push_back(
Call);
539 for (CallInst *
Call : functionLikeCalls)
540 Call->eraseFromParent();
544 if (GlobalVariable *GA = M.getGlobalVariable(
"llvm.global.annotations")) {
545 if (GA->hasInitializer()) {
546 auto AOp = GA->getInitializer();
548 if (ConstantArray *CA = dyn_cast<ConstantArray>(AOp)) {
550 SmallVector<Constant *, 1> replacements;
551 for (Value *CAOp : CA->operands()) {
554 ConstantStruct *CS = dyn_cast<ConstantStruct>(CAOp);
558 if (CS->getNumOperands() < 2)
563 GlobalVariable *GAnn =
564 dyn_cast<GlobalVariable>(CS->getOperand(1)->getOperand(0));
566 ConstantDataArray *A =
nullptr;
569 A = dyn_cast<ConstantDataArray>(GAnn->getOperand(0));
571 A = dyn_cast<ConstantDataArray>(CS->getOperand(1)->getOperand(0));
578 StringRef AS = A->getAsCString();
580 Constant *Val = cast<Constant>(CS->getOperand(0));
581 while (
auto CE = dyn_cast<ConstantExpr>(Val))
582 Val = CE->getOperand(0);
584 Function *Func = dyn_cast<Function>(Val);
585 GlobalVariable *Glob = dyn_cast<GlobalVariable>(Val);
587 if (AS ==
"enzyme_inactive" && Func) {
589 AttributeList::FunctionIndex,
590 Attribute::get(Func->getContext(),
"enzyme_inactive"));
593 replacements.push_back(Constant::getNullValue(CAOp->getType()));
603 if ((AS ==
"enzyme_inactivefn" ||
604 AS ==
"enzyme_inactivenoblockfn") &&
609 replacements.push_back(Constant::getNullValue(CAOp->getType()));
613 if (AS ==
"enzyme_elementwise_read" && Func) {
614 Func->addAttribute(AttributeList::FunctionIndex,
615 Attribute::get(Func->getContext(),
616 "enzyme_elementwise_read"));
618 replacements.push_back(Constant::getNullValue(CAOp->getType()));
622 if (AS ==
"enzyme_shouldrecompute" && Func) {
624 AttributeList::FunctionIndex,
625 Attribute::get(Func->getContext(),
"enzyme_shouldrecompute"));
627 replacements.push_back(Constant::getNullValue(CAOp->getType()));
631 if (AS ==
"enzyme_inactive" && Glob) {
632 Glob->setMetadata(
"enzyme_inactive",
633 MDNode::get(Glob->getContext(), {}));
635 replacements.push_back(Constant::getNullValue(CAOp->getType()));
639 if (AS ==
"enzyme_nofree" && Func) {
641 AttributeList::FunctionIndex,
642 Attribute::get(Func->getContext(), Attribute::NoFree));
645 replacements.push_back(Constant::getNullValue(CAOp->getType()));
649 if (
startsWith(AS,
"enzyme_function_like") && Func) {
650 auto val = AS.substr(1 + AS.find(
'='));
653 replacements.push_back(Constant::getNullValue(CAOp->getType()));
657 if (AS ==
"enzyme_sparse_accumulate" && Func) {
658 Func->addAttribute(AttributeList::FunctionIndex,
659 Attribute::get(Func->getContext(),
660 "enzyme_sparse_accumulate"));
663 replacements.push_back(Constant::getNullValue(CAOp->getType()));
667 if (AS ==
"enzyme_ta_norecur" && (Glob || Func)) {
669 Glob->setMetadata(
"enzyme_ta_norecur",
670 MDNode::get(Glob->getContext(), {}));
673 AttributeList::FunctionIndex,
674 Attribute::get(Func->getContext(),
"enzyme_ta_norecur"));
677 replacements.push_back(Constant::getNullValue(CAOp->getType()));
681 replacements.push_back(cast<Constant>(CAOp));
683 GA->setInitializer(ConstantArray::get(CA->getType(), replacements));
688 for (GlobalVariable &g : M.globals()) {
689 bool customRule = g.getName().contains(gradient_handler_name) ||
690 g.getName().contains(derivative_handler_name) ||
691 g.getName().contains(splitderivative_handler_name);
692 if (customRule && !PreserveCustomRuleLinkage)
694 if (customRule || g.getName().contains(
"__enzyme_nofree") ||
695 g.getName().contains(
"__enzyme_inactivefn") ||
696 g.getName().contains(
"__enzyme_sparse_accumulate") ||
697 g.getName().contains(
"__enzyme_function_like") ||
698 g.getName().contains(
"__enzyme_allocation_like")) {
699 if (g.hasInitializer()) {
700 Value *V = g.getInitializer();
702 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
703 V = CE->getOperand(0);
706 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
707 V = CA->getOperand(0);
712 if (
auto F = dyn_cast<Function>(V))
717 SmallVector<GlobalVariable *, 1> toErase;
718 for (GlobalVariable &g : M.globals()) {
719 if (g.getName().contains(gradient_handler_name)) {
722 M, g, toErase, PreserveCustomRuleLinkage);
724 }
else if (g.getName().contains(derivative_handler_name)) {
727 M, g, toErase, PreserveCustomRuleLinkage);
729 }
else if (g.getName().contains(splitderivative_handler_name)) {
732 M, g, toErase, PreserveCustomRuleLinkage);
735 if (g.getName().contains(
"__enzyme_inactive_global")) {
736 if (g.hasInitializer()) {
737 Value *V = g.getInitializer();
739 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
740 V = CE->getOperand(0);
743 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
744 V = CA->getOperand(0);
749 if (
auto GV = cast<GlobalVariable>(V)) {
750 GV->setMetadata(
"enzyme_inactive", MDNode::get(g.getContext(), {}));
751 toErase.push_back(&g);
754 llvm::errs() <<
"Param of __enzyme_inactive_global must be a "
758 llvm_unreachable(
"__enzyme_inactive_global");
762 if (g.getName().contains(
"__enzyme_inactivefn") ||
763 g.getName().contains(
"__enzyme_inactivenoblockfn")) {
764 if (g.hasInitializer()) {
765 Value *V = g.getInitializer();
767 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
768 V = CE->getOperand(0);
771 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
772 V = CA->getOperand(0);
777 if (
auto F = cast<Function>(V)) {
779 toErase.push_back(&g);
782 llvm::errs() <<
"Param of __enzyme_inactivefn must be a "
786 llvm_unreachable(
"__enzyme_inactivefn");
790 if (g.getName().contains(
"__enzyme_sparse_accumulate")) {
791 if (g.hasInitializer()) {
792 Value *V = g.getInitializer();
794 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
795 V = CE->getOperand(0);
798 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
799 V = CA->getOperand(0);
804 if (
auto F = cast<Function>(V)) {
806 AttributeList::FunctionIndex,
807 Attribute::get(g.getContext(),
"enzyme_sparse_accumulate"));
808 toErase.push_back(&g);
811 llvm::errs() <<
"Param of __enzyme_sparse_accumulate must be a "
815 llvm_unreachable(
"__enzyme_sparse_accumulate");
819 if (g.getName().contains(
"__enzyme_nofree")) {
820 if (g.hasInitializer()) {
821 Value *V = g.getInitializer();
823 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
824 V = CE->getOperand(0);
827 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
828 V = CA->getOperand(0);
833 if (
auto F = cast<Function>(V)) {
834 F->addAttribute(AttributeList::FunctionIndex,
835 Attribute::get(g.getContext(), Attribute::NoFree));
836 toErase.push_back(&g);
839 llvm::errs() <<
"Param of __enzyme_nofree must be a "
843 llvm_unreachable(
"__enzyme_nofree");
847 if (g.getName().contains(
"__enzyme_function_like")) {
848 if (g.hasInitializer()) {
849 auto CA = dyn_cast<ConstantAggregate>(g.getInitializer());
851 constexpr StringLiteral Marker =
"__enzyme_function_like__";
852 auto MarkerPos = g.getName().rfind(Marker);
853 Value *Target = g.getInitializer()->stripPointerCasts();
856 if (MarkerPos == StringRef::npos || !isa<Function>(Target))
860 g.getName().substr(MarkerPos + Marker.size()));
861 toErase.push_back(&g);
865 if (CA->getNumOperands() < 2) {
866 llvm::errs() <<
"Use of "
867 <<
"enzyme_function_like"
869 "constant of size at least "
870 << 2 <<
" " << g <<
"\n";
871 llvm_unreachable(
"enzyme_function_like");
873 Value *V = CA->getOperand(0);
874 Value *name = CA->getOperand(1);
875 while (
auto CE = dyn_cast<ConstantExpr>(name)) {
876 name = CE->getOperand(0);
879 if (
auto GV = dyn_cast<GlobalVariable>(name))
880 if (GV->isConstant())
881 if (
auto C = GV->getInitializer())
882 if (
auto CA = dyn_cast<ConstantDataArray>(C))
883 if (CA->getType()->getElementType()->isIntegerTy(8) &&
885 nameVal = CA->getAsCString();
888 toErase.push_back(&g);
892 if (g.getName().contains(
"__enzyme_allocation_like")) {
893 if (g.hasInitializer()) {
894 auto CA = dyn_cast<ConstantAggregate>(g.getInitializer());
895 if (!CA || CA->getNumOperands() != 4) {
896 llvm::errs() <<
"Use of "
897 <<
"enzyme_allocation_like"
899 "constant of size at least "
900 << 4 <<
" " << g <<
"\n";
901 llvm_unreachable(
"enzyme_allocation_like");
903 Value *V = CA->getOperand(0);
904 Value *name = CA->getOperand(1);
905 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
906 V = CE->getOperand(0);
908 while (
auto CE = dyn_cast<ConstantExpr>(name)) {
909 name = CE->getOperand(0);
911 Value *deallocind = CA->getOperand(2);
912 while (
auto CE = dyn_cast<ConstantExpr>(deallocind)) {
913 deallocind = CE->getOperand(0);
915 Value *deallocfn = CA->getOperand(3);
916 while (
auto CE = dyn_cast<ConstantExpr>(deallocfn)) {
917 deallocfn = CE->getOperand(0);
920 if (isa<ConstantPointerNull>(name)) {
923 }
else if (
auto CI = dyn_cast<ConstantInt>(name)) {
924 index = CI->getZExtValue();
926 llvm::errs() << *name <<
"\n";
927 llvm::errs() <<
"Use of "
928 <<
"enzyme_allocation_like"
929 <<
"requires an integer index"
931 llvm_unreachable(
"enzyme_allocation_like");
934 StringRef deallocIndStr;
935 bool foundInd =
false;
936 if (
auto GV = dyn_cast<GlobalVariable>(deallocind))
937 if (GV->isConstant())
938 if (
auto C = GV->getInitializer())
939 if (
auto CA = dyn_cast<ConstantDataArray>(C))
940 if (CA->getType()->getElementType()->isIntegerTy(8) &&
942 deallocIndStr = CA->getAsCString();
947 llvm::errs() << *deallocind <<
"\n";
948 llvm::errs() <<
"Use of "
949 <<
"enzyme_allocation_like"
950 <<
"requires a deallocation index string"
952 llvm_unreachable(
"enzyme_allocation_like");
954 if (
auto F = dyn_cast<Function>(V)) {
955 F->addAttribute(AttributeList::FunctionIndex,
956 Attribute::get(g.getContext(),
"enzyme_allocator",
957 std::to_string(index)));
959 llvm::errs() <<
"Param of __enzyme_allocation_like must be a "
963 llvm_unreachable(
"__enzyme_allocation_like");
965 cast<Function>(V)->addAttribute(AttributeList::FunctionIndex,
966 Attribute::get(g.getContext(),
967 "enzyme_deallocator",
970 if (
auto F = dyn_cast<Function>(deallocfn)) {
971 cast<Function>(V)->setMetadata(
972 "enzyme_deallocator_fn",
973 llvm::MDTuple::get(F->getContext(),
974 {llvm::ValueAsMetadata::get(F)}));
977 llvm::errs() <<
"Free fn of __enzyme_allocation_like must be a "
980 << *deallocfn <<
"\n";
981 llvm_unreachable(
"__enzyme_allocation_like");
983 toErase.push_back(&g);
989 for (
auto G : toErase) {
990 for (
auto name : {
"llvm.used",
"llvm.compiler.used"}) {
991 if (
auto V = M.getGlobalVariable(name)) {
992 auto C = cast<ConstantArray>(V->getInitializer());
993 SmallVector<Constant *, 1> toKeep;
995 for (
unsigned i = 0; i < C->getNumOperands(); i++) {
996 Value *Op = C->getOperand(i)->stripPointerCasts();
1000 toKeep.push_back(C->getOperand(i));
1003 if (toKeep.size()) {
1004 auto CA = ConstantArray::get(
1005 ArrayType::get(C->getType()->getElementType(), toKeep.size()),
1007 GlobalVariable *NGV =
new GlobalVariable(
1008 CA->getType(), V->isConstant(), V->getLinkage(), CA,
"",
1009 V->getThreadLocalMode());
1010#if LLVM_VERSION_MAJOR > 16
1011 V->getParent()->insertGlobalVariable(V->getIterator(), NGV);
1013 V->getParent()->getGlobalList().insert(V->getIterator(), NGV);
1018 if (!V->use_empty()) {
1020 if (VV->getType() != V->getType())
1021 VV = ConstantExpr::getBitCast(VV, V->getType());
1022 V->replaceAllUsesWith(VV);
1025 V->eraseFromParent();
1030 G->replaceAllUsesWith(ConstantPointerNull::get(G->getType()));
1031 G->eraseFromParent();
1034 StringMap<std::pair<std::string, std::string>> Implements;
1035 for (std::string T : {
"",
"f"}) {
1038 for (std::string name :
1039 {
"sin",
"cos",
"tan",
"log2",
"exp",
"exp2",
1040 "exp10",
"cosh",
"sinh",
"tanh",
"atan2",
"atan",
1041 "asin",
"acos",
"log",
"log10",
"log1p",
"acosh",
1042 "asinh",
"atanh",
"expm1",
"hypot",
"rhypot",
"norm3d",
1043 "rnorm3d",
"norm4d",
"rnorm4d",
"norm",
"rnorm",
"cbrt",
1044 "rcbrt",
"j0",
"j1",
"y0",
"y1",
"yn",
1045 "jn",
"erf",
"erfinv",
"erfc",
"erfcx",
"erfcinv",
1046 "normcdfinv",
"normcdf",
"lgamma",
"ldexp",
"scalbn",
"frexp",
1047 "modf",
"fmod",
"remainder",
"remquo",
"powi",
"tgamma",
1048 "round",
"fdim",
"ilogb",
"logb",
"isinf",
"pow",
1049 "sqrt",
"finite",
"fabs",
"fmax"}) {
1050 std::string nvname =
"__nv_" + name;
1051 std::string llname =
"llvm." + name +
".";
1052 std::string mathname = name;
1062 Implements[nvname] = std::make_pair(mathname, llname);
1066 for (std::string name : {
"acos",
"acosh",
"asin",
1067 "asinh",
"atan2",
"atan",
1068 "atanh",
"cbrt",
"ceil",
1069 "copysign",
"cos",
"native_cos",
1070 "cosh",
"cospi",
"i0",
1071 "i1",
"erfc",
"erfcinv",
1072 "erfcx",
"erf",
"erfinv",
1073 "exp10",
"native_exp10",
"exp2",
1074 "exp",
"native_exp",
"expm1",
1075 "fabs",
"fdim",
"floor",
1076 "fma",
"fmax",
"fmin",
1077 "fmod",
"frexp",
"hypot",
1078 "ilogb",
"isfinite",
"isinf",
1079 "isnan",
"j0",
"j1",
1080 "ldexp",
"lgamma",
"log10",
1081 "native_log10",
"log1p",
"log2",
1082 "log2",
"logb",
"log",
1083 "native_log",
"modf",
"nearbyint",
1084 "nextafter",
"len3",
"len4",
1085 "ncdf",
"ncdfinv",
"pow",
1086 "pown",
"rcbrt",
"remainder",
1087 "remquo",
"rhypot",
"rint",
1088 "rlen3",
"rlen4",
"round",
1089 "rsqrt",
"scalb",
"scalbn",
1090 "signbit",
"sincos",
"sincospi",
1091 "sin",
"native_sin",
"sinh",
1092 "sinpi",
"sqrt",
"native_sqrt",
1093 "tan",
"tanh",
"tgamma",
1094 "trunc",
"y0",
"y1"}) {
1095 std::string nvname =
"__ocml_" + name +
"_";
1096 std::string llname =
"llvm." + name +
".";
1097 std::string mathname = name;
1108 Implements[nvname] = std::make_pair(mathname, llname);
1119 for (std::string name : {
"sin",
"cos",
"tan",
"asin",
"acos",
"atan",
1120 "atan2",
"exp",
"exp2",
"log",
"log2",
"log10",
1121 "log1p",
"expm1",
"sqrt",
"cbrt",
"pow",
"fma"}) {
1122 std::string airname =
"air." + name + (T ==
"f" ?
".f32" :
".f64");
1123 std::string llname =
"llvm." + name +
"." + (T ==
"f" ?
"f32" :
"f64");
1124 std::string mathname = name + T;
1126 Implements[airname] = std::make_pair(mathname, llname);
1136 for (std::string name :
1137 {
"log",
"exp",
"sin",
"cos",
"tan",
"sqrt",
"asin",
"acos",
"atan",
1138 "atan2",
"acosh",
"asinh"}) {
1139 std::string airname =
"air.fast_" + name +
".f32";
1140 std::string llname =
"llvm." + name +
".f32";
1141 std::string mathname = name + T;
1143 Implements[airname] = std::make_pair(mathname, llname);
1147#if ENZYME_ENABLE_NVVM_ATTRIBUTION
1148 for (
auto &F : llvm::make_early_inc_range(M)) {
1154 SmallPtrSet<Constant *, 4> compilerUsed;
1156 auto found = Implements.find(F.getName());
1157 if (found != Implements.end()) {
1162 F.addFnAttr(
"implements", found->second.second);
1163 F.addFnAttr(
"implements2", found->second.first);
1164 F.addFnAttr(
"enzyme_math", found->second.first);
1167 }
else if (F.getName() ==
"_ZL21__internal_float2halffRjS_" ||
1168 F.getName() ==
"_ZL4hlog6__half" ||
1169 F.getName() ==
"_ZL6__hdiv6__halfS_" ||
1170 F.getName() ==
"_ZL12__half2float6__half" ||
1171 F.getName() ==
"_ZL6__habs6__half" ||
1172 F.getName() ==
"_ZL5__hlt6__halfS_" ||
1173 F.getName() ==
"_ZL6__hmul6__halfS_" ||
1174 F.getName() ==
"_ZL6__hadd6__halfS_" ||
1175 F.getName() ==
"_ZL5hsqrt6__half" ||
1176 F.getName() ==
"_ZL6__hsub6__halfS_" ||
1177 F.getName() ==
"_ZL4hexp6__half" ||
1178 F.getName() ==
"_ZL6__hneg6__half" ||
1179 F.getName() ==
"_ZL22__internal_device_hdiv13__nv_bfloat16S_" ||
1181 "_ZL27__internal_sm80_device_hmul13__nv_bfloat16S_" ||
1182 F.getName() ==
"_ZL22__internal_device_hadd13__nv_bfloat16S_" ||
1184 "_ZL27__internal_sm80_device_hsub13__nv_bfloat16S_" ||
1185 F.getName() ==
"_ZL22__internal_device_hneg13__nv_bfloat16" ||
1186 F.getName() ==
"_ZL16__float2bfloat16f" ||
1187 F.getName() ==
"_ZL25__internal_bfloat162floatt" ||
1188 F.getName() ==
"_ZL32__internal_device_bfloat162floatt") {
1194 if (!Begin && F.hasFnAttribute(
"prev_fixup")) {
1196 if (F.hasFnAttribute(
"prev_compiler_used")) {
1197 F.removeFnAttr(
"prev_compiler_used");
1198 compilerUsed.insert(&F);
1200 F.removeFnAttr(
"prev_fixup");
1201 if (F.hasFnAttribute(
"prev_always_inline")) {
1202 F.addFnAttr(Attribute::AlwaysInline);
1203 F.removeFnAttr(
"prev_always_inline");
1205 if (F.hasFnAttribute(
"prev_no_inline")) {
1206 F.removeFnAttr(
"prev_no_inline");
1208 F.removeFnAttr(Attribute::NoInline);
1211 F.getFnAttribute(
"prev_linkage").getValueAsString().getAsInteger(10, val);
1212 F.setLinkage((Function::LinkageTypes)val);
1215#if LLVM_VERSION_MAJOR >= 20
1217 if (!compilerUsed.empty())
1218 removeFromUsedLists(M, [&](Constant *C) {
return compilerUsed.count(C); });