98 SmallVectorImpl<GlobalVariable *> &globalsToErase) {
99 if (g.hasInitializer()) {
100 if (
auto CA = dyn_cast<ConstantAggregate>(g.getInitializer())) {
101 if (CA->getNumOperands() < numargs) {
102 llvm::errs() << M <<
"\n";
103 llvm::errs() <<
"Use of " << handlername
105 "constant of size at least "
106 << numargs <<
" " << g <<
"\n";
107 llvm_unreachable(handlername);
109 Function *Fs[numargs];
110 for (
size_t i = 0; i < numargs; i++) {
111 Value *V = CA->getOperand(i);
112 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
113 V = CE->getOperand(0);
115 if (
auto CA = dyn_cast<ConstantAggregate>(V))
116 V = CA->getOperand(0);
117 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
118 V = CE->getOperand(0);
120 if (
auto F = dyn_cast<Function>(V)) {
123 llvm::errs() << M <<
"\n";
124 llvm::errs() <<
"Param of " << handlername
129 llvm_unreachable(handlername);
133 SmallSet<size_t, 1> byref;
136 assert(numargs >= 3);
137 for (
size_t i = numargs; i < CA->getNumOperands(); i++) {
138 Value *V = CA->getOperand(i);
139 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
140 V = CE->getOperand(0);
142 if (
auto CA = dyn_cast<ConstantAggregate>(V))
143 V = CA->getOperand(0);
144 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
145 V = CE->getOperand(0);
147 if (
auto GV = dyn_cast<GlobalVariable>(V)) {
148 if (GV->isConstant())
149 if (
auto C = GV->getInitializer())
150 if (
auto CA = dyn_cast<ConstantDataArray>(C))
151 if (CA->getType()->getElementType()->isIntegerTy(8) &&
154 auto str = CA->getAsCString();
158 for (
size_t i =
str.size() - 1, len = strlen(
"byref_");
161 if (c <
'0' || c >
'9') {
170 byref.insert(argnum);
175 llvm::errs() << M <<
"\n";
176 llvm::errs() <<
"Use of " << handlername
177 <<
" possible post args include 'byref_ret'"
179 llvm_unreachable(handlername);
183 for (
size_t fn = 1; fn <= 2; fn++) {
184 Function *F = Fs[fn];
186 size_t nonSRetSize = 0;
187 for (
size_t i = 0; i < F->arg_size(); i++)
188 if (!F->hasParamAttribute(i, Attribute::StructRet))
196 SmallVector<Type *, 3> args;
197 Type *sretTy =
nullptr;
200 for (
auto &arg : F->args()) {
201 if (!F->hasParamAttribute(i, Attribute::StructRet)) {
202 if (!byref.count(realidx))
203 args.push_back(arg.getType());
206 Type *subTy =
nullptr;
207#if LLVM_VERSION_MAJOR < 17
208 subTy = arg.getType()->getPointerElementType();
211 args.push_back(subTy);
215 llvm::Type *T =
nullptr;
216#if LLVM_VERSION_MAJOR > 12
217 T = F->getParamAttribute(i, Attribute::StructRet)
220 T = arg.getType()->getPointerElementType();
226 Type *RT = F->getReturnType();
228 assert(RT->isVoidTy());
232 FunctionType::get(RT, args, F->getFunctionType()->isVarArg());
234 Function::Create(FTy, Function::LinkageTypes::InternalLinkage,
235 "fixbyval_" + F->getName(), F->getParent());
237 AllocaInst *AI =
nullptr;
239 BasicBlock::Create(NewF->getContext(),
"entry", NewF);
242 AI = bb.CreateAlloca(sretTy);
243 SmallVector<Value *, 3> argVs;
244 auto arg = NewF->arg_begin();
246 for (
size_t i = 0; i < F->arg_size(); i++) {
247 if (!F->hasParamAttribute(i, Attribute::StructRet)) {
248 arg->setName(
"arg" + Twine(realidx));
249 if (!byref.count(realidx))
250 argVs.push_back(arg);
252 auto A = bb.CreateAlloca(arg->getType());
253 bb.CreateStore(arg, A);
262 auto cal = bb.CreateCall(F, argVs);
263 cal->setCallingConv(F->getCallingConv());
266 Value *res = bb.CreateLoad(sretTy, AI);
268 }
else if (!RT->isVoidTy()) {
279 llvm::MDTuple::get(Fs[0]->getContext(),
280 {llvm::ValueAsMetadata::get(Fs[1])}));
284 llvm::MDTuple::get(Fs[0]->getContext(),
285 {llvm::ValueAsMetadata::get(Fs[2])}));
287 assert(numargs == 2);
291 llvm::MDTuple::get(Fs[0]->getContext(),
292 {llvm::ValueAsMetadata::get(Fs[1])}));
294 assert(numargs == 3);
298 llvm::MDTuple::get(Fs[0]->getContext(),
299 {llvm::ValueAsMetadata::get(Fs[1])}));
302 "enzyme_splitderivative",
303 llvm::MDTuple::get(Fs[0]->getContext(),
304 {llvm::ValueAsMetadata::get(Fs[2])}));
306 assert(
"Unknown mode");
309 llvm::errs() << M <<
"\n";
310 llvm::errs() <<
"Use of " << handlername
312 "constant aggregate "
314 llvm_unreachable(handlername);
317 llvm::errs() << M <<
"\n";
318 llvm::errs() <<
"Use of " << handlername
320 "constant array of size "
321 << numargs <<
" " << g <<
"\n";
322 llvm_unreachable(handlername);
324 globalsToErase.push_back(&g);
328 bool changed =
false;
329 constexpr static const char gradient_handler_name[] =
330 "__enzyme_register_gradient";
331 constexpr static const char derivative_handler_name[] =
332 "__enzyme_register_derivative";
333 constexpr static const char splitderivative_handler_name[] =
334 "__enzyme_register_splitderivative";
337 if (GlobalVariable *GA = M.getGlobalVariable(
"llvm.global.annotations")) {
338 if (GA->hasInitializer()) {
339 auto AOp = GA->getInitializer();
341 if (ConstantArray *CA = dyn_cast<ConstantArray>(AOp)) {
343 SmallVector<Constant *, 1> replacements;
344 for (Value *CAOp : CA->operands()) {
347 ConstantStruct *CS = dyn_cast<ConstantStruct>(CAOp);
351 if (CS->getNumOperands() < 2)
356 GlobalVariable *GAnn =
357 dyn_cast<GlobalVariable>(CS->getOperand(1)->getOperand(0));
359 ConstantDataArray *A =
nullptr;
362 A = dyn_cast<ConstantDataArray>(GAnn->getOperand(0));
364 A = dyn_cast<ConstantDataArray>(CS->getOperand(1)->getOperand(0));
371 StringRef AS = A->getAsCString();
373 Constant *Val = cast<Constant>(CS->getOperand(0));
374 while (
auto CE = dyn_cast<ConstantExpr>(Val))
375 Val = CE->getOperand(0);
377 Function *Func = dyn_cast<Function>(Val);
378 GlobalVariable *Glob = dyn_cast<GlobalVariable>(Val);
380 if (AS ==
"enzyme_inactive" && Func) {
382 AttributeList::FunctionIndex,
383 Attribute::get(Func->getContext(),
"enzyme_inactive"));
386 replacements.push_back(Constant::getNullValue(CAOp->getType()));
390 if (AS ==
"enzyme_elementwise_read" && Func) {
391 Func->addAttribute(AttributeList::FunctionIndex,
392 Attribute::get(Func->getContext(),
393 "enzyme_elementwise_read"));
395 replacements.push_back(Constant::getNullValue(CAOp->getType()));
399 if (AS ==
"enzyme_shouldrecompute" && Func) {
401 AttributeList::FunctionIndex,
402 Attribute::get(Func->getContext(),
"enzyme_shouldrecompute"));
404 replacements.push_back(Constant::getNullValue(CAOp->getType()));
408 if (AS ==
"enzyme_inactive" && Glob) {
409 Glob->setMetadata(
"enzyme_inactive",
410 MDNode::get(Glob->getContext(), {}));
412 replacements.push_back(Constant::getNullValue(CAOp->getType()));
416 if (AS ==
"enzyme_nofree" && Func) {
418 AttributeList::FunctionIndex,
419 Attribute::get(Func->getContext(), Attribute::NoFree));
422 replacements.push_back(Constant::getNullValue(CAOp->getType()));
426 if (
startsWith(AS,
"enzyme_function_like") && Func) {
427 auto val = AS.substr(1 + AS.find(
'='));
429 AttributeList::FunctionIndex,
430 Attribute::get(Func->getContext(),
"enzyme_math", val));
433 replacements.push_back(Constant::getNullValue(CAOp->getType()));
437 if (AS ==
"enzyme_sparse_accumulate" && Func) {
438 Func->addAttribute(AttributeList::FunctionIndex,
439 Attribute::get(Func->getContext(),
440 "enzyme_sparse_accumulate"));
443 replacements.push_back(Constant::getNullValue(CAOp->getType()));
446 replacements.push_back(cast<Constant>(CAOp));
448 GA->setInitializer(ConstantArray::get(CA->getType(), replacements));
453 for (GlobalVariable &g : M.globals()) {
454 if (g.getName().contains(gradient_handler_name) ||
455 g.getName().contains(derivative_handler_name) ||
456 g.getName().contains(splitderivative_handler_name) ||
457 g.getName().contains(
"__enzyme_nofree") ||
458 g.getName().contains(
"__enzyme_inactivefn") ||
459 g.getName().contains(
"__enzyme_sparse_accumulate") ||
460 g.getName().contains(
"__enzyme_function_like") ||
461 g.getName().contains(
"__enzyme_allocation_like")) {
462 if (g.hasInitializer()) {
463 Value *V = g.getInitializer();
465 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
466 V = CE->getOperand(0);
469 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
470 V = CA->getOperand(0);
475 if (
auto F = dyn_cast<Function>(V))
480 SmallVector<GlobalVariable *, 1> toErase;
481 for (GlobalVariable &g : M.globals()) {
482 if (g.getName().contains(gradient_handler_name)) {
487 }
else if (g.getName().contains(derivative_handler_name)) {
491 }
else if (g.getName().contains(splitderivative_handler_name)) {
497 if (g.getName().contains(
"__enzyme_inactive_global")) {
498 if (g.hasInitializer()) {
499 Value *V = g.getInitializer();
501 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
502 V = CE->getOperand(0);
505 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
506 V = CA->getOperand(0);
511 if (
auto GV = cast<GlobalVariable>(V)) {
512 GV->setMetadata(
"enzyme_inactive", MDNode::get(g.getContext(), {}));
513 toErase.push_back(&g);
516 llvm::errs() <<
"Param of __enzyme_inactive_global must be a "
520 llvm_unreachable(
"__enzyme_inactive_global");
524 if (g.getName().contains(
"__enzyme_inactivefn")) {
525 if (g.hasInitializer()) {
526 Value *V = g.getInitializer();
528 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
529 V = CE->getOperand(0);
532 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
533 V = CA->getOperand(0);
538 if (
auto F = cast<Function>(V)) {
539 F->addAttribute(AttributeList::FunctionIndex,
540 Attribute::get(g.getContext(),
"enzyme_inactive"));
541 toErase.push_back(&g);
544 llvm::errs() <<
"Param of __enzyme_inactivefn must be a "
548 llvm_unreachable(
"__enzyme_inactivefn");
552 if (g.getName().contains(
"__enzyme_sparse_accumulate")) {
553 if (g.hasInitializer()) {
554 Value *V = g.getInitializer();
556 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
557 V = CE->getOperand(0);
560 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
561 V = CA->getOperand(0);
566 if (
auto F = cast<Function>(V)) {
568 AttributeList::FunctionIndex,
569 Attribute::get(g.getContext(),
"enzyme_sparse_accumulate"));
570 toErase.push_back(&g);
573 llvm::errs() <<
"Param of __enzyme_sparse_accumulate must be a "
577 llvm_unreachable(
"__enzyme_sparse_accumulate");
581 if (g.getName().contains(
"__enzyme_nofree")) {
582 if (g.hasInitializer()) {
583 Value *V = g.getInitializer();
585 if (
auto CE = dyn_cast<ConstantExpr>(V)) {
586 V = CE->getOperand(0);
589 if (
auto CA = dyn_cast<ConstantAggregate>(V)) {
590 V = CA->getOperand(0);
595 if (
auto F = cast<Function>(V)) {
596 F->addAttribute(AttributeList::FunctionIndex,
597 Attribute::get(g.getContext(), Attribute::NoFree));
598 toErase.push_back(&g);
601 llvm::errs() <<
"Param of __enzyme_nofree must be a "
605 llvm_unreachable(
"__enzyme_nofree");
609 if (g.getName().contains(
"__enzyme_function_like")) {
610 if (g.hasInitializer()) {
611 auto CA = dyn_cast<ConstantAggregate>(g.getInitializer());
612 if (!CA || CA->getNumOperands() < 2) {
613 llvm::errs() <<
"Use of "
614 <<
"enzyme_function_like"
616 "constant of size at least "
617 << 2 <<
" " << g <<
"\n";
618 llvm_unreachable(
"enzyme_function_like");
620 Value *V = CA->getOperand(0);
621 Value *name = CA->getOperand(1);
622 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
623 V = CE->getOperand(0);
625 while (
auto CE = dyn_cast<ConstantExpr>(name)) {
626 name = CE->getOperand(0);
629 if (
auto GV = dyn_cast<GlobalVariable>(name))
630 if (GV->isConstant())
631 if (
auto C = GV->getInitializer())
632 if (
auto CA = dyn_cast<ConstantDataArray>(C))
633 if (CA->getType()->getElementType()->isIntegerTy(8) &&
635 nameVal = CA->getAsCString();
638 llvm::errs() << *name <<
"\n";
639 llvm::errs() <<
"Use of "
640 <<
"enzyme_function_like"
641 <<
"requires a non-empty function name"
643 llvm_unreachable(
"enzyme_function_like");
645 if (
auto F = cast<Function>(V)) {
647 AttributeList::FunctionIndex,
648 Attribute::get(g.getContext(),
"enzyme_math", nameVal));
649 toErase.push_back(&g);
652 llvm::errs() <<
"Param of __enzyme_function_like must be a "
656 llvm_unreachable(
"__enzyme_function_like");
660 if (g.getName().contains(
"__enzyme_allocation_like")) {
661 if (g.hasInitializer()) {
662 auto CA = dyn_cast<ConstantAggregate>(g.getInitializer());
663 if (!CA || CA->getNumOperands() != 4) {
664 llvm::errs() <<
"Use of "
665 <<
"enzyme_allocation_like"
667 "constant of size at least "
668 << 4 <<
" " << g <<
"\n";
669 llvm_unreachable(
"enzyme_allocation_like");
671 Value *V = CA->getOperand(0);
672 Value *name = CA->getOperand(1);
673 while (
auto CE = dyn_cast<ConstantExpr>(V)) {
674 V = CE->getOperand(0);
676 while (
auto CE = dyn_cast<ConstantExpr>(name)) {
677 name = CE->getOperand(0);
679 Value *deallocind = CA->getOperand(2);
680 while (
auto CE = dyn_cast<ConstantExpr>(deallocind)) {
681 deallocind = CE->getOperand(0);
683 Value *deallocfn = CA->getOperand(3);
684 while (
auto CE = dyn_cast<ConstantExpr>(deallocfn)) {
685 deallocfn = CE->getOperand(0);
688 if (isa<ConstantPointerNull>(name)) {
691 }
else if (
auto CI = dyn_cast<ConstantInt>(name)) {
692 index = CI->getZExtValue();
694 llvm::errs() << *name <<
"\n";
695 llvm::errs() <<
"Use of "
696 <<
"enzyme_allocation_like"
697 <<
"requires an integer index"
699 llvm_unreachable(
"enzyme_allocation_like");
702 StringRef deallocIndStr;
703 bool foundInd =
false;
704 if (
auto GV = dyn_cast<GlobalVariable>(deallocind))
705 if (GV->isConstant())
706 if (
auto C = GV->getInitializer())
707 if (
auto CA = dyn_cast<ConstantDataArray>(C))
708 if (CA->getType()->getElementType()->isIntegerTy(8) &&
710 deallocIndStr = CA->getAsCString();
715 llvm::errs() << *deallocind <<
"\n";
716 llvm::errs() <<
"Use of "
717 <<
"enzyme_allocation_like"
718 <<
"requires a deallocation index string"
720 llvm_unreachable(
"enzyme_allocation_like");
722 if (
auto F = dyn_cast<Function>(V)) {
723 F->addAttribute(AttributeList::FunctionIndex,
724 Attribute::get(g.getContext(),
"enzyme_allocator",
725 std::to_string(index)));
727 llvm::errs() <<
"Param of __enzyme_allocation_like must be a "
731 llvm_unreachable(
"__enzyme_allocation_like");
733 cast<Function>(V)->addAttribute(AttributeList::FunctionIndex,
734 Attribute::get(g.getContext(),
735 "enzyme_deallocator",
738 if (
auto F = dyn_cast<Function>(deallocfn)) {
739 cast<Function>(V)->setMetadata(
740 "enzyme_deallocator_fn",
741 llvm::MDTuple::get(F->getContext(),
742 {llvm::ValueAsMetadata::get(F)}));
745 llvm::errs() <<
"Free fn of __enzyme_allocation_like must be a "
748 << *deallocfn <<
"\n";
749 llvm_unreachable(
"__enzyme_allocation_like");
751 toErase.push_back(&g);
757 for (
auto G : toErase) {
758 for (
auto name : {
"llvm.used",
"llvm.compiler.used"}) {
759 if (
auto V = M.getGlobalVariable(name)) {
760 auto C = cast<ConstantArray>(V->getInitializer());
761 SmallVector<Constant *, 1> toKeep;
763 for (
unsigned i = 0; i < C->getNumOperands(); i++) {
764 Value *Op = C->getOperand(i)->stripPointerCasts();
768 toKeep.push_back(C->getOperand(i));
772 auto CA = ConstantArray::get(
773 ArrayType::get(C->getType()->getElementType(), toKeep.size()),
775 GlobalVariable *NGV =
new GlobalVariable(
776 CA->getType(), V->isConstant(), V->getLinkage(), CA,
"",
777 V->getThreadLocalMode());
778#if LLVM_VERSION_MAJOR > 16
779 V->getParent()->insertGlobalVariable(V->getIterator(), NGV);
781 V->getParent()->getGlobalList().insert(V->getIterator(), NGV);
786 if (!V->use_empty()) {
788 if (VV->getType() != V->getType())
789 VV = ConstantExpr::getBitCast(VV, V->getType());
790 V->replaceAllUsesWith(VV);
793 V->eraseFromParent();
798 G->replaceAllUsesWith(ConstantPointerNull::get(G->getType()));
799 G->eraseFromParent();
802 StringMap<std::pair<std::string, std::string>> Implements;
803 for (std::string T : {
"",
"f"}) {
806 for (std::string name :
807 {
"sin",
"cos",
"tan",
"log2",
"exp",
"exp2",
808 "exp10",
"cosh",
"sinh",
"tanh",
"atan2",
"atan",
809 "asin",
"acos",
"log",
"log10",
"log1p",
"acosh",
810 "asinh",
"atanh",
"expm1",
"hypot",
"rhypot",
"norm3d",
811 "rnorm3d",
"norm4d",
"rnorm4d",
"norm",
"rnorm",
"cbrt",
812 "rcbrt",
"j0",
"j1",
"y0",
"y1",
"yn",
813 "jn",
"erf",
"erfinv",
"erfc",
"erfcx",
"erfcinv",
814 "normcdfinv",
"normcdf",
"lgamma",
"ldexp",
"scalbn",
"frexp",
815 "modf",
"fmod",
"remainder",
"remquo",
"powi",
"tgamma",
816 "round",
"fdim",
"ilogb",
"logb",
"isinf",
"pow",
817 "sqrt",
"finite",
"fabs",
"fmax"}) {
818 std::string nvname =
"__nv_" + name;
819 std::string llname =
"llvm." + name +
".";
820 std::string mathname = name;
830 Implements[nvname] = std::make_pair(mathname, llname);
834 for (std::string name : {
"acos",
"acosh",
"asin",
835 "asinh",
"atan2",
"atan",
836 "atanh",
"cbrt",
"ceil",
837 "copysign",
"cos",
"native_cos",
838 "cosh",
"cospi",
"i0",
839 "i1",
"erfc",
"erfcinv",
840 "erfcx",
"erf",
"erfinv",
841 "exp10",
"native_exp10",
"exp2",
842 "exp",
"native_exp",
"expm1",
843 "fabs",
"fdim",
"floor",
844 "fma",
"fmax",
"fmin",
845 "fmod",
"frexp",
"hypot",
846 "ilogb",
"isfinite",
"isinf",
848 "ldexp",
"lgamma",
"log10",
849 "native_log10",
"log1p",
"log2",
850 "log2",
"logb",
"log",
851 "native_log",
"modf",
"nearbyint",
852 "nextafter",
"len3",
"len4",
853 "ncdf",
"ncdfinv",
"pow",
854 "pown",
"rcbrt",
"remainder",
855 "remquo",
"rhypot",
"rint",
856 "rlen3",
"rlen4",
"round",
857 "rsqrt",
"scalb",
"scalbn",
858 "signbit",
"sincos",
"sincospi",
859 "sin",
"native_sin",
"sinh",
860 "sinpi",
"sqrt",
"native_sqrt",
861 "tan",
"tanh",
"tgamma",
862 "trunc",
"y0",
"y1"}) {
863 std::string nvname =
"__ocml_" + name +
"_";
864 std::string llname =
"llvm." + name +
".";
865 std::string mathname = name;
876 Implements[nvname] = std::make_pair(mathname, llname);
879#if ENZYME_ENABLE_NVVM_ATTRIBUTION
880 for (
auto &F : llvm::make_early_inc_range(M)) {
887 auto found = Implements.find(F.getName());
888 if (found != Implements.end()) {
893 F.addFnAttr(
"implements", found->second.second);
894 F.addFnAttr(
"implements2", found->second.first);
895 F.addFnAttr(
"enzyme_math", found->second.first);
898 }
else if (F.getName() ==
"_ZL21__internal_float2halffRjS_" ||
899 F.getName() ==
"_ZL4hlog6__half" ||
900 F.getName() ==
"_ZL6__hdiv6__halfS_" ||
901 F.getName() ==
"_ZL12__half2float6__half" ||
902 F.getName() ==
"_ZL6__habs6__half" ||
903 F.getName() ==
"_ZL5__hlt6__halfS_" ||
904 F.getName() ==
"_ZL6__hmul6__halfS_" ||
905 F.getName() ==
"_ZL6__hadd6__halfS_" ||
906 F.getName() ==
"_ZL5hsqrt6__half" ||
907 F.getName() ==
"_ZL6__hsub6__halfS_" ||
908 F.getName() ==
"_ZL4hexp6__half" ||
909 F.getName() ==
"_ZL6__hneg6__half" ||
910 F.getName() ==
"_ZL22__internal_device_hdiv13__nv_bfloat16S_" ||
912 "_ZL27__internal_sm80_device_hmul13__nv_bfloat16S_" ||
913 F.getName() ==
"_ZL22__internal_device_hadd13__nv_bfloat16S_" ||
915 "_ZL27__internal_sm80_device_hsub13__nv_bfloat16S_" ||
916 F.getName() ==
"_ZL22__internal_device_hneg13__nv_bfloat16" ||
917 F.getName() ==
"_ZL16__float2bfloat16f" ||
918 F.getName() ==
"_ZL25__internal_bfloat162floatt" ||
919 F.getName() ==
"_ZL32__internal_device_bfloat162floatt") {
925 if (!Begin && F.hasFnAttribute(
"prev_fixup")) {
927 F.removeFnAttr(
"prev_fixup");
928 if (F.hasFnAttribute(
"prev_always_inline")) {
929 F.addFnAttr(Attribute::AlwaysInline);
930 F.removeFnAttr(
"prev_always_inline");
932 if (F.hasFnAttribute(
"prev_no_inline")) {
933 F.removeFnAttr(
"prev_no_inline");
935 F.removeFnAttr(Attribute::NoInline);
938 F.getFnAttribute(
"prev_linkage").getValueAsString().getAsInteger(10, val);
939 F.setLinkage((Function::LinkageTypes)val);