39 llvm::Type *SRetType =
nullptr,
40 std::set<size_t> *rootingArgs =
nullptr,
41 const std::map<size_t, size_t> *assignedRoots =
nullptr) {
42 auto Attrs = arg->getParent()->getAttributes();
47 .
getAttribute(AttributeList::FirstArgIndex + arg->getArgNo(),
53 if (tracked.
count == 0) {
57 bool hasReturnRootingAfterArg =
false;
58 bool hasUnassignedReturnRootingAfterArg =
false;
59 for (
size_t i = arg->getArgNo() + 1; i < arg->getParent()->arg_size(); i++) {
60 if (Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
61 "enzymejl_returnRoots")) {
62 hasReturnRootingAfterArg =
true;
63 if (!assignedRoots || !assignedRoots->count(i)) {
64 hasUnassignedReturnRootingAfterArg =
true;
71 if (!hasReturnRootingAfterArg) {
75 SmallVector<Value *> storedValues;
77 auto &DL = arg->getParent()->getParent()->getDataLayout();
78 SmallVector<size_t> sret_offsets;
80 std::deque<std::pair<llvm::Type *, std::vector<unsigned>>> todo = {
82 while (!todo.empty()) {
83 auto cur = std::move(todo[0]);
85 auto path = std::move(cur.second);
88 if (
auto PT = dyn_cast<PointerType>(ty)) {
92 SmallVector<Constant *, 1> IdxList;
94 ConstantInt::get(Type::getInt64Ty(PT->getContext()), 0));
98 ConstantInt::get(Type::getInt32Ty(PT->getContext()), v));
99 auto nullp = ConstantPointerNull::get(
getUnqual(SRetType));
100 auto gep = ConstantExpr::getGetElementPtr(SRetType, nullp, IdxList);
102 if (gep == ConstantPointerNull::get(
getUnqual(PT))) {
103 sret_offsets.push_back(0);
106#if LLVM_VERSION_MAJOR >= 20
107 SmallMapVector<Value *, APInt, 4> VariableOffsets;
109 MapVector<Value *, APInt> VariableOffsets;
111 auto width = DL.getPointerSize() * 8;
112 APInt Offset(width, 0);
113 bool success =
collectOffset(cast<GEPOperator>(gep), DL, width,
114 VariableOffsets, Offset);
116 llvm_unreachable(
"Illegal offset collection");
117 sret_offsets.push_back(Offset.getZExtValue());
121 if (
auto AT = dyn_cast<ArrayType>(ty)) {
122 for (
size_t i = 0; i < AT->getNumElements(); i++) {
123 std::vector<unsigned> path2(path);
125 todo.emplace_back(AT->getElementType(), path2);
130 if (
auto VT = dyn_cast<VectorType>(ty)) {
131 for (
size_t i = 0; i < VT->getElementCount().getKnownMinValue(); i++) {
132 std::vector<unsigned> path2(path);
134 todo.emplace_back(VT->getElementType(), path2);
139 if (
auto ST = dyn_cast<StructType>(ty)) {
140 for (
size_t i = 0; i < ST->getNumElements(); i++) {
141 std::vector<unsigned> path2(path);
143 todo.emplace_back(ST->getTypeAtIndex(i), path2);
152 assert(I->getParent()->getParent() == arg->getParent());
154 if (isa<ICmpInst>(I)) {
157 if (isa<LoadInst>(I)) {
160 if (
auto SI = dyn_cast<StoreInst>(I)) {
161 assert(SI->getValueOperand() != cur);
166 storedValues.push_back(SI->getValueOperand());
171 if (isa<MemSetInst>(I))
174 if (
auto MSI = dyn_cast<MemTransferInst>(I)) {
175 if (
auto Len = dyn_cast<ConstantInt>(MSI->getLength())) {
177 for (
auto offset : sret_offsets) {
178 if (byteOffset + Len->getSExtValue() <= offset)
180 if (offset + DL.getPointerSize() <= byteOffset)
191 llvm::raw_string_ostream ss(s);
192 ss <<
"Unknown user of sret-like argument\n";
194 wrap(cur), wrap(arg),
nullptr);
201 while (!storedValues.empty()) {
202 auto sv = storedValues.pop_back_val();
203 if (
auto I = dyn_cast<Instruction>(sv)) {
204 assert(I->getParent()->getParent() == arg->getParent());
206 bool foundUse =
false;
207 for (
auto &U : sv->uses()) {
210 if (
auto I = dyn_cast<Instruction>(U.getUser())) {
211 if (I->getParent()->getParent() != arg->getParent()) {
216 if (
auto SI = dyn_cast<StoreInst>(U.getUser())) {
217 if (SI->getValueOperand() == sv) {
222 if (
auto evi = dyn_cast<ExtractValueInst>(base)) {
223 base = evi->getAggregateOperand();
225 if (
auto arg2 = dyn_cast<Argument>(base)) {
229 "enzymejl_returnRoots")
232 rootingArgs->insert(arg2->getArgNo());
241 if (
auto IVI = dyn_cast<InsertValueInst>(sv)) {
245 bool trivialAggregate =
246 isa<UndefValue>(IVI->getAggregateOperand()) ||
247 isa<PoisonValue>(IVI->getAggregateOperand()) ||
248 isa<ConstantAggregateZero>(IVI->getAggregateOperand());
250 IVI->getInsertedValueOperand()->getType());
251 if (tracked.
count == 0) {
252 if (trivialAggregate)
254 storedValues.push_back(IVI->getAggregateOperand());
257 if (trivialAggregate) {
258 storedValues.push_back(IVI->getInsertedValueOperand());
261 storedValues.push_back(IVI->getAggregateOperand());
262 storedValues.push_back(IVI->getInsertedValueOperand());
265 if (
auto ST = dyn_cast<StructType>(sv->getType())) {
267 for (
size_t i = 0; i < ST->getNumElements(); i++) {
270 if (tracked.
count == 0) {
273 std::map<std::vector<unsigned>,
bool> paths_to_cover;
275 std::deque<std::pair<llvm::Type *, std::vector<unsigned>>> todo =
276 {{ST->getElementType(i), {}}};
277 while (!todo.empty()) {
278 auto cur = std::move(todo[0]);
280 auto path = std::move(cur.second);
283 if (
auto PT = dyn_cast<PointerType>(ty)) {
285 paths_to_cover[path] =
false;
290 if (
auto AT = dyn_cast<ArrayType>(ty)) {
291 for (
size_t k = 0; k < AT->getNumElements(); k++) {
292 std::vector<unsigned> path2(path);
294 todo.emplace_back(AT->getElementType(), path2);
299 if (
auto VT = dyn_cast<VectorType>(ty)) {
301 k < VT->getElementCount().getKnownMinValue(); k++) {
302 std::vector<unsigned> path2(path);
304 todo.emplace_back(VT->getElementType(), path2);
309 if (
auto ST2 = dyn_cast<StructType>(ty)) {
310 for (
size_t k = 0; k < ST2->getNumElements(); k++) {
311 std::vector<unsigned> path2(path);
313 todo.emplace_back(ST2->getTypeAtIndex(k), path2);
320 for (
auto u : sv->users()) {
321 if (
auto ev0 = dyn_cast<ExtractValueInst>(u)) {
322 if (ev0->getIndices()[0] == i) {
323 std::vector<unsigned> extract_path;
324 for (
size_t k = 1; k < ev0->getNumIndices(); ++k) {
325 extract_path.push_back(ev0->getIndices()[k]);
327 storedValues.push_back(ev0);
330 for (
auto &pair : paths_to_cover) {
331 const auto &p = pair.first;
333 if (extract_path.size() > p.size()) {
336 for (
size_t idx = 0; idx < extract_path.size(); ++idx) {
337 if (extract_path[idx] != p[idx]) {
351 bool fullyCovered =
true;
352 for (
const auto &pair : paths_to_cover) {
354 fullyCovered =
false;
360 llvm::errs() <<
" failed to find extracted pointer for " << *sv
361 <<
" at index " << i <<
"\n";
370 if (!isa<PointerType>(sv->getType()) ||
372 llvm::errs() <<
" sf: " << *arg->getParent() <<
"\n";
373 llvm::errs() <<
" arg: " << *arg <<
"\n";
374 llvm::errs() <<
"Pointer of wrong type: " << *sv <<
"\n";
379 bool saw_bitcast =
false;
380 for (
auto u : sv->users()) {
381 if (
auto ev0 = dyn_cast<CastInst>(u)) {
382 auto t2 = ev0->getType();
383 if (isa<PointerType>(t2) &&
isSpecialPtr(cast<PointerType>(t2))) {
385 storedValues.push_back(ev0);
394 if (hasUnassignedReturnRootingAfterArg) {
396 llvm::raw_string_ostream ss(s);
397 ss <<
"Could not find use of stored value\n";
398 ss <<
" sv: " << *sv <<
"\n";
400 nullptr, wrap(arg),
nullptr);
600 auto RT = F->getReturnType();
601 std::set<size_t> srets;
602 std::set<size_t> enzyme_srets;
604 std::set<size_t> reroot_enzyme_srets;
606 std::set<size_t> noroot_enzyme_srets;
608 std::set<size_t> rroots;
610 std::set<size_t> reret_roots;
612 auto FT = F->getFunctionType();
613 auto Attrs = F->getAttributes();
615 std::map<size_t, size_t> selected_roots;
618 std::map<size_t, size_t> srets_without_stores;
620 for (
size_t i = 0, end = FT->getNumParams(); i < end; i++) {
621 if (Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
622 Attribute::StructRet))
624 if (Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
"enzyme_sret")) {
625 bool anyJLStore =
false;
626 std::set<size_t> rootingArgs;
627 enzyme_srets.insert(i);
628 if (
needsReRooting(F->getArg(i), anyJLStore,
nullptr, &rootingArgs,
632 reroot_enzyme_srets.insert(i);
633 }
else if (anyJLStore) {
645 Attrs.getAttribute(AttributeList::FirstArgIndex + i,
"enzyme_sret")
649 bool assigned =
false;
654 if (rootingArgs.size() == 1 && !tracked.
all) {
655 size_t ridx = *rootingArgs.begin();
659 "enzymejl_returnRoots")
660 .getValueAsString());
661 if (ridx > i && !selected_roots.count(ridx) &&
662 rcount == tracked.
count) {
663 selected_roots[ridx] = i;
668 reroot_enzyme_srets.insert(i);
672 Attrs.getAttribute(AttributeList::FirstArgIndex + i,
"enzyme_sret")
676 srets_without_stores[i] = count;
677 noroot_enzyme_srets.insert(i);
682 !Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
"enzyme_sret_v"));
684 if (Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
685 "enzymejl_returnRoots")) {
688 if (selected_roots.count(i)) {
691 srets_without_stores)) {
692 reret_roots.insert(i);
694 selected_roots[i] = sret_idx;
697 assert(!Attrs.hasAttribute(AttributeList::FirstArgIndex + i,
698 "enzymejl_returnRoots_v"));
702 if (srets.size() == 1) {
703 assert(*srets.begin() == 0);
704 assert(enzyme_srets.size() == 0);
705 llvm::Type *SRetType = F->getParamStructRetType(0);
709 if (!tracked.
count) {
713 bool anyJLStore =
false;
714 bool rerooting =
needsReRooting(F->getArg(0), anyJLStore, SRetType);
719 assert(rroots.size() == 1);
720 assert(*rroots.begin() == 1);
723#if LLVM_VERSION_MAJOR >= 16
726 llvm::raw_string_ostream ss(s);
727 ss <<
"Illegal GC setup in which rerooting is required\n";
728 ss <<
" + F: " << *F <<
"\n";
730 nullptr,
nullptr,
nullptr);
738 "enzymejl_returnRoots")
739 .getValueAsString());
741 assert(count == tracked.
count);
743 bool allCallersAlloca =
true;
744 for (
auto U : F->users()) {
745 if (
auto CI = dyn_cast<CallInst>(U)) {
746 if (CI->getCalledFunction() == F) {
747 if (!isa<AllocaInst>(
getBaseObject(CI->getArgOperand(0),
false)) ||
748 !isa<AllocaInst>(
getBaseObject(CI->getArgOperand(1),
false))) {
749 allCallersAlloca =
false;
755 if (allCallersAlloca)
758 F->addParamAttr(0, Attribute::get(F->getContext(),
"enzyme_sret",
760 Attrs = F->getAttributes();
763 enzyme_srets.insert(i);
764 selected_roots[1] = 0;
767 F->addParamAttr(0, Attribute::get(F->getContext(),
"enzyme_sret",
769 Attrs = F->getAttributes();
772 enzyme_srets.insert(i);
774 reroot_enzyme_srets.insert(i);
775 }
else if (anyJLStore) {
778 srets_without_stores[i] = count;
779 noroot_enzyme_srets.insert(i);
783 }
else if (srets.size() == 0 && enzyme_srets.size() == 0 &&
784 rroots.size() == 0) {
792 for (
auto &pair : srets_without_stores) {
794 reroot_enzyme_srets.insert(pair.first);
797 assert(srets.size() == 0);
799 SmallVector<Type *, 1> Types;
800 if (!RT->isVoidTy()) {
804 auto T_jlvalue = StructType::get(F->getContext(), {});
809 for (
auto idx : enzyme_srets) {
811 Attrs.getAttribute(AttributeList::FirstArgIndex + idx,
"enzyme_sret")
814#if LLVM_VERSION_MAJOR < 17
815 if (F->getContext().supportsTypedPointers()) {
816 auto T = FT->getParamType(idx)->getPointerElementType();
819 llvm::raw_string_ostream ss(s);
820 ss <<
"Type mismatch in FixupJuliaCallingConvention:\n";
821 ss <<
" + T: " << *T <<
"\n";
822 ss <<
" + SRetType: " << *SRetType <<
"\n";
823 EmitFailure(
"TypeMismatch", F->getSubprogram(), F, ss.str());
827 Types.push_back(SRetType);
828 if (reroot_enzyme_srets.count(idx)) {
832 for (
auto idx : rroots) {
836 "enzymejl_returnRoots")
837 .getValueAsString());
838 auto T = ArrayType::get(T_prjlvalue, count);
839#if LLVM_VERSION_MAJOR < 17
840 if (F->getContext().supportsTypedPointers()) {
841 auto NT = FT->getParamType(idx)->getPointerElementType();
845 if (reret_roots.count(idx)) {
852 Types.size() <= 1 ? nullptr : StructType::get(F->getContext(), Types);
853 Type *sretTy =
nullptr;
855 sretTy = Types.size() == 1 ? Types[0] : ST;
857 ArrayType *roots_AT =
858 numRooting ? ArrayType::get(T_prjlvalue, numRooting) :
nullptr;
868 reroot_enzyme_srets.clear();
869 }
else if (countF.
count) {
871 llvm::errs() <<
" sretTy: " << *sretTy <<
"\n";
872 llvm::errs() <<
" numRooting: " << numRooting <<
"\n";
873 llvm::errs() <<
" tracked.count: " << countF.
count <<
"\n";
876 if (numRooting != countF.
count) {
878 llvm::raw_string_ostream ss(s);
879 ss <<
"Illegal GC setup in which numRooting (" << numRooting
880 <<
") != tracked.count (" << countF.
count <<
")\n";
881 ss <<
" sretTy: " << *sretTy <<
"\n";
882 ss <<
" Types.size(): " << Types.size() <<
"\n";
883 for (
size_t i = 0; i < Types.size(); i++) {
884 ss <<
" + Types[" << i <<
"] = " << *Types[i] <<
"\n";
886 ss <<
" F: " << *F <<
"\n";
888 nullptr,
nullptr,
nullptr);
890 assert(numRooting == countF.
count);
894 AttributeList NewAttrs;
895 SmallVector<Type *, 1> types;
899 NewAttrs = NewAttrs.addAttribute(
900 F->getContext(), AttributeList::FirstArgIndex + nexti,
901 Attribute::get(F->getContext(), Attribute::StructRet, sretTy));
902 NewAttrs = NewAttrs.addAttribute(F->getContext(),
903 AttributeList::FirstArgIndex + nexti,
908 NewAttrs = NewAttrs.addAttribute(
909 F->getContext(), AttributeList::FirstArgIndex + nexti,
910 "enzymejl_returnRoots", std::to_string(numRooting));
911 NewAttrs = NewAttrs.addAttribute(F->getContext(),
912 AttributeList::FirstArgIndex + nexti,
914 NewAttrs = NewAttrs.addAttribute(F->getContext(),
915 AttributeList::FirstArgIndex + nexti,
916 Attribute::WriteOnly);
921 for (
size_t i = 0, end = FT->getNumParams(); i < end; i++) {
922 if (enzyme_srets.count(i) || rroots.count(i))
925 for (
auto attr : Attrs.getAttributes(AttributeList::FirstArgIndex + i)) {
926 NewAttrs = NewAttrs.addAttribute(
927 F->getContext(), AttributeList::FirstArgIndex + nexti, attr);
929 types.push_back(F->getFunctionType()->getParamType(i));
933 for (
auto attr : Attrs.getAttributes(AttributeList::FunctionIndex))
934 NewAttrs = NewAttrs.addAttribute(F->getContext(),
935 AttributeList::FunctionIndex, attr);
936 if (sretTy || roots_AT)
939 FunctionType *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), types,
943 auto &M = *F->getParent();
944 Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(),
947 ValueToValueMapTy VMap;
949 Function::arg_iterator DestI = NewF->arg_begin();
950 Argument *sret =
nullptr;
955 Argument *roots =
nullptr;
963 std::map<size_t, PHINode *> delArgMap;
964 for (Argument &I : F->args()) {
965 auto i = I.getArgNo();
966 if (enzyme_srets.count(i) || rroots.count(i)) {
967 VMap[&I] = delArgMap[i] = PHINode::Create(I.getType(), 0);
970 assert(DestI != NewF->arg_end());
971 DestI->setName(I.getName());
972 VMap[&I] = &*DestI++;
976 SmallPtrSet<Function *, 1> calls_todo;
979 SmallVector<ReturnInst *, 8> Returns;
980 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,
981 Returns,
"",
nullptr);
984 SmallVector<CallInst *, 1> callers;
985 for (
auto U : F->users()) {
986 auto CI = dyn_cast<CallInst>(U);
988 assert(CI->getCalledFunction() == F);
989 callers.push_back(CI);
993 size_t curOffset = 0;
994 size_t sretCount = 0;
995 if (!RT->isVoidTy()) {
996 for (
auto &RT : Returns) {
998 Value *gep = ST ? B.CreateConstInBoundsGEP2_32(ST, sret, 0, 0) : sret;
999 Value *rval = RT->getReturnValue();
1000 B.CreateStore(rval, gep);
1008 auto NR = B.CreateRetVoid();
1009 RT->eraseFromParent();
1020 for (
size_t i = 0, end = FT->getNumParams(); i < end; i++) {
1022 if (enzyme_srets.count(i)) {
1023 auto argFound = delArgMap.find(i);
1024 assert(argFound != delArgMap.end());
1025 auto arg = argFound->second;
1027 SmallVector<Instruction *, 1> uses;
1028 SmallVector<unsigned, 1> op;
1029 for (
auto &U : arg->uses()) {
1030 auto I = cast<Instruction>(U.getUser());
1032 op.push_back(U.getOperandNo());
1034 IRBuilder<> EB(&NewF->getEntryBlock().front());
1036 ST ? EB.CreateConstInBoundsGEP2_32(ST, sret, 0, sretCount) : sret;
1037 for (
size_t i = 0; i < uses.size(); i++) {
1038 uses[i]->setOperand(op[i], gep);
1041 if (reroot_enzyme_srets.count(i)) {
1044 for (
auto &RT : Returns) {
1046 if (noroot_enzyme_srets.count(i)) {
1047 for (
size_t i = 0; i < cnt; i++) {
1048 B.CreateStore(ConstantPointerNull::get(T_prjlvalue),
1049 B.CreateConstInBoundsGEP2_32(roots_AT, roots, 0,
1067 if (rroots.count(i)) {
1068 auto attr = Attrs.getAttribute(AttributeList::FirstArgIndex + i,
1069 "enzymejl_returnRoots");
1070 auto attrv = attr.getValueAsString();
1071 assert(attrv.size());
1074 auto argFound = delArgMap.find(i);
1075 assert(argFound != delArgMap.end());
1076 auto arg = argFound->second;
1078 SmallVector<Instruction *, 1> uses;
1079 SmallVector<unsigned, 1> op;
1080 for (
auto &U : arg->uses()) {
1081 auto I = cast<Instruction>(U.getUser());
1083 op.push_back(U.getOperandNo());
1085 IRBuilder<> EB(&NewF->getEntryBlock().front());
1087 Value *gep =
nullptr;
1093 if (curOffset != 0) {
1094 gep = EB.CreateConstInBoundsGEP2_32(roots_AT, roots, 0, curOffset);
1096 if (subCount != numRooting) {
1097 gep = EB.CreatePointerCast(
1098 gep,
getUnqual(ArrayType::get(T_prjlvalue, subCount)));
1100 curOffset += subCount;
1101 if (reret_roots.count(i))
1106 ST ? EB.CreateConstInBoundsGEP2_32(ST, sret, 0, sretCount) : sret;
1108 if (!reret_roots.count(i)) {
1111 llvm::raw_string_ostream ss(s);
1112 ss <<
"Illegal GC setup in which there was no roots_AT, but a new "
1114 << *sret <<
"), but no rereturned roots at index i=" << i
1117 nullptr,
nullptr,
nullptr);
1123 for (
size_t i = 0; i < uses.size(); i++) {
1124 uses[i]->setOperand(op[i], gep);
1132 assert(curOffset == numRooting);
1133 assert(sretCount == Types.size());
1136 auto &DL = F->getParent()->getDataLayout();
1139 for (
auto CI : callers) {
1140 auto Attrs = CI->getAttributes();
1141 AttributeList NewAttrs;
1143 IRBuilder<> EB(&CI->getParent()->getParent()->getEntryBlock().front());
1144 SmallVector<Value *, 1> vals;
1146 Value *sret =
nullptr;
1148 sret = EB.CreateAlloca(sretTy, 0,
"stack_sret");
1149 vals.push_back(sret);
1150 NewAttrs = NewAttrs.addAttribute(
1151 F->getContext(), AttributeList::FirstArgIndex + nexti,
1152 Attribute::get(F->getContext(), Attribute::StructRet, sretTy));
1155 AllocaInst *roots =
nullptr;
1157 roots = EB.CreateAlloca(roots_AT, 0,
"stack_roots_AT");
1158 vals.push_back(roots);
1159 NewAttrs = NewAttrs.addAttribute(
1161 F->getContext(), AttributeList::FirstArgIndex + nexti,
1162 "enzymejl_returnRoots", std::to_string(numRooting));
1166 for (
auto attr : Attrs.getAttributes(AttributeList::FunctionIndex))
1167 NewAttrs = NewAttrs.addAttribute(F->getContext(),
1168 AttributeList::FunctionIndex, attr);
1169 if (sretTy || roots_AT)
1172 SmallVector<std::tuple<Value *, Value *, Type *>> preCallReplacements;
1173 SmallVector<std::tuple<Value *, Value *, Type *, bool>>
1174 postCallReplacements;
1177 size_t local_root_count = 0;
1178 size_t sretCount = 0;
1179 if (!RT->isVoidTy()) {
1187 for (
size_t i = 0, end = CI->arg_size(); i < end; i++) {
1189 if (enzyme_srets.count(i)) {
1190 auto val = CI->getArgOperand(i);
1192 if (isa<UndefValue>(val) || isa<PoisonValue>(val) ||
1193 isa<ConstantPointerNull>(val)) {
1195 llvm::raw_string_ostream ss(s);
1196 ss <<
"Unsupported constant argument in "
1197 "FixupJuliaCallingConvention\n";
1198 ss <<
" + val: " << *val <<
"\n";
1199 ss <<
" + Function being rewritten: " << F->getName() <<
"\n";
1200 ss <<
" + CI erring: " << *CI <<
"\n";
1201 ss <<
" + Function containing CI: "
1202 << CI->getParent()->getParent()->getName() <<
"\n";
1205 nullptr,
nullptr,
nullptr);
1207 EmitFailure(
"UnsupportedArgument", CI->getDebugLoc(), CI,
1214 IRBuilder<> GEPB(cast<Instruction>(sret)->getNextNode());
1215 gep = GEPB.CreateConstInBoundsGEP2_32(ST, sret, 0, sretCount);
1218 bool handled =
false;
1219 if (
auto AI = dyn_cast<AllocaInst>(
getBaseObject(val,
false))) {
1220 if (AI->getAllocatedType() == Types[sretCount] ||
1222 DL.getTypeSizeInBits(AI->getAllocatedType()) ==
1223 DL.getTypeSizeInBits(Types[sretCount]))) {
1224 AI->replaceAllUsesWith(gep);
1225 AI->eraseFromParent();
1231 assert(!isa<UndefValue>(val));
1232 assert(!isa<PoisonValue>(val));
1233 assert(!isa<ConstantPointerNull>(val));
1239 bool should_sret = sret_jlvalue;
1250 postCallReplacements.emplace_back(val, gep, Types[sretCount],
1258 preCallReplacements.emplace_back(val, gep, Types[sretCount]);
1262 if (roots_AT && reroot_enzyme_srets.count(i)) {
1270 if (rroots.count(i)) {
1271 auto val = CI->getArgOperand(i);
1272 if (isa<UndefValue>(val) || isa<PoisonValue>(val) ||
1273 isa<ConstantPointerNull>(val)) {
1275 llvm::raw_string_ostream ss(s);
1276 ss <<
"Unsupported constant argument in "
1277 "FixupJuliaCallingConvention\n";
1278 ss <<
" + val: " << *val <<
"\n";
1279 ss <<
" + Function being rewritten: " << F->getName() <<
"\n";
1280 ss <<
" + CI erring: " << *CI <<
"\n";
1281 ss <<
" + Function containing CI: "
1282 << CI->getParent()->getParent()->getName() <<
"\n";
1285 nullptr,
nullptr,
nullptr);
1287 EmitFailure(
"UnsupportedArgument", CI->getDebugLoc(), CI,
1292 auto attr = Attrs.getAttribute(AttributeList::FirstArgIndex + i,
1293 "enzymejl_returnRoots");
1294 auto attrv = attr.getValueAsString();
1295 assert(attrv.size());
1298 Value *gep =
nullptr;
1302 IRBuilder<> GEPB(cast<Instruction>(roots)->getNextNode());
1304 if (local_root_count != 0) {
1305 gep = GEPB.CreateConstInBoundsGEP2_32(roots_AT, roots, 0,
1309 if (subCount != numRooting) {
1310 gep = GEPB.CreatePointerCast(
1311 gep,
getUnqual(ArrayType::get(T_prjlvalue, subCount)));
1313 local_root_count += subCount;
1314 if (reret_roots.count(i))
1317 assert(reret_roots.count(i));
1319 IRBuilder<> GEPB(cast<Instruction>(sret)->getNextNode());
1322 gep = GEPB.CreateConstInBoundsGEP2_32(ST, sret, 0, sretCount);
1327 bool handled =
false;
1328 if (
auto AI = dyn_cast<AllocaInst>(
getBaseObject(val,
false))) {
1329 if (AI->getAllocatedType() ==
1330 ArrayType::get(T_prjlvalue, subCount)) {
1331 AI->replaceAllUsesWith(gep);
1332 AI->eraseFromParent();
1338 assert(!isa<UndefValue>(val));
1339 assert(!isa<PoisonValue>(val));
1340 assert(!isa<ConstantPointerNull>(val));
1342 preCallReplacements.emplace_back(
1343 val, gep, ArrayType::get(T_prjlvalue, subCount));
1344 postCallReplacements.emplace_back(
1345 val, gep, ArrayType::get(T_prjlvalue, subCount),
true);
1350 for (
auto attr : Attrs.getAttributes(AttributeList::FirstArgIndex + i))
1351 NewAttrs = NewAttrs.addAttribute(
1352 F->getContext(), AttributeList::FirstArgIndex + nexti, attr);
1353 vals.push_back(CI->getArgOperand(i));
1357 assert(sretCount == Types.size());
1358 assert(local_root_count == numRooting);
1365 for (
auto &&[val, gep, ty] : preCallReplacements) {
1370 SmallVector<OperandBundleDef, 1> Bundles;
1371 for (
unsigned I = 0, E = CI->getNumOperandBundles(); I != E; ++I)
1372 Bundles.emplace_back(CI->getOperandBundleAt(I));
1374 if (!NewF->getFunctionType()->isVarArg() &&
1375 NewF->getFunctionType()->getNumParams() != vals.size()) {
1376 llvm::errs() <<
"NewF: " << *NewF <<
"\n";
1377 for (
size_t i = 0; i < vals.size(); i++) {
1378 llvm::errs() <<
" Args[" << i <<
"] = " << *vals[i] <<
"\n";
1381 auto NC = B.CreateCall(NewF, vals, Bundles);
1382 NC->setAttributes(NewAttrs);
1384 SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs;
1385 CI->getAllMetadataOtherThanDebugLoc(TheMDs);
1386 SmallVector<unsigned, 1> toCopy;
1387 for (
auto pair : TheMDs)
1388 if (pair.first != LLVMContext::MD_range) {
1389 toCopy.push_back(pair.first);
1391 if (!toCopy.empty())
1392 NC->copyMetadata(*CI, toCopy);
1393 NC->setDebugLoc(CI->getDebugLoc());
1395 if (!RT->isVoidTy()) {
1396 auto gep = ST ? B.CreateConstInBoundsGEP2_32(ST, sret, 0, 0) : sret;
1397 auto ld = B.CreateLoad(RT, gep);
1398 if (
auto MD = CI->getMetadata(LLVMContext::MD_range))
1399 ld->setMetadata(LLVMContext::MD_range, MD);
1401 Value *replacement = ld;
1411 CI->replaceAllUsesWith(replacement);
1414 for (
auto &&[val, gep, ty, jlvalue] : postCallReplacements) {
1416 auto ld = B.CreateLoad(ty, gep);
1417 auto SI = B.CreateStore(ld, val);
1418 if (val->getType()->getPointerAddressSpace() == 10)
1426 NC->setCallingConv(CI->getCallingConv());
1427 CI->eraseFromParent();
1429 NewF->setAttributes(NewAttrs);
1430 SmallVector<std::pair<unsigned, MDNode *>, 1> MD;
1431 F->getAllMetadata(MD);
1432 for (
auto pair : MD)
1433 if (pair.first != LLVMContext::MD_dbg)
1434 NewF->addMetadata(pair.first, *pair.second);
1436 NewF->setCallingConv(F->getCallingConv());
1437 F->eraseFromParent();
1449 auto RT = F->getReturnType();
1450 auto FT = F->getFunctionType();
1451 auto Attrs = F->getAttributes();
1453 AttributeList NewAttrs;
1454 SmallVector<Type *, 1> types;
1455 SmallSet<size_t, 1> changed;
1456 for (
auto pair : llvm::enumerate(FT->params())) {
1457 auto T = pair.value();
1458 auto i = pair.index();
1462 for (
auto attr : Attrs.getAttributes(AttributeList::FirstArgIndex + i)) {
1463 if (attr.isStringAttribute() &&
1464 attr.getKindAsString() ==
"enzyme_sret_v") {
1466 kind =
"enzyme_sret";
1467 value = attr.getValueAsString();
1468 }
else if (attr.isStringAttribute() &&
1469 attr.getKindAsString() ==
"enzymejl_rooted_typ_v") {
1471 kind =
"enzymejl_rooted_typ";
1472 value = attr.getValueAsString();
1473 }
else if (attr.isStringAttribute() &&
1474 attr.getKindAsString() ==
"enzymejl_returnRoots_v") {
1476 kind =
"enzymejl_returnRoots";
1477 value = attr.getValueAsString();
1479 NewAttrs = NewAttrs.addAttribute(
1480 F->getContext(), AttributeList::FirstArgIndex + types.size(), attr);
1483 if (
auto AT = dyn_cast<ArrayType>(T)) {
1484 if (
auto PT = dyn_cast<PointerType>(AT->getElementType())) {
1485 auto AS = PT->getAddressSpace();
1486 if (AS == 11 || AS == 12 || AS == 13 || sretv) {
1487 for (
unsigned i = 0; i < AT->getNumElements(); i++) {
1489 NewAttrs = NewAttrs.addAttribute(
1490 F->getContext(), AttributeList::FirstArgIndex + types.size(),
1491 Attribute::get(F->getContext(), kind, value));
1493 types.push_back(PT);
1503 if (changed.size() == 0)
1506 for (
auto attr : Attrs.getAttributes(AttributeList::FunctionIndex))
1507 NewAttrs = NewAttrs.addAttribute(F->getContext(),
1508 AttributeList::FunctionIndex, attr);
1510 for (
auto attr : Attrs.getAttributes(AttributeList::ReturnIndex))
1511 NewAttrs = NewAttrs.addAttribute(F->getContext(),
1512 AttributeList::ReturnIndex, attr);
1515 FunctionType::get(FT->getReturnType(), types, FT->isVarArg());
1518 Function *NewF = Function::Create(FTy, F->getLinkage(), F->getAddressSpace(),
1519 F->getName(), F->getParent());
1521 ValueToValueMapTy VMap;
1523 Function::arg_iterator DestI = NewF->arg_begin();
1527 SmallVector<Instruction *, 1> toInsert;
1528 for (Argument &I : F->args()) {
1529 auto T = I.getType();
1530 if (
auto AT = dyn_cast<ArrayType>(T)) {
1531 if (changed.count(I.getArgNo())) {
1532 Value *V = UndefValue::get(T);
1533 for (
unsigned i = 0; i < AT->getNumElements(); i++) {
1534 DestI->setName(I.getName() +
"." +
1536 unsigned idx[1] = {i};
1537 auto IV = InsertValueInst::Create(V, (llvm::Value *)&*DestI++, idx);
1538 toInsert.push_back(IV);
1545 DestI->setName(I.getName());
1546 VMap[&I] = &*DestI++;
1549 SmallVector<ReturnInst *, 8> Returns;
1550 CloneFunctionInto(NewF, F, VMap, CloneFunctionChangeType::LocalChangesOnly,
1551 Returns,
"",
nullptr);
1555 IRBuilder<> EB(&*NewF->getEntryBlock().begin());
1556 for (
auto I : toInsert)
1560 SmallVector<CallInst *, 1> callers;
1561 for (
auto U : F->users()) {
1562 auto CI = dyn_cast<CallInst>(U);
1564 assert(CI->getCalledFunction() == F);
1565 callers.push_back(CI);
1568 for (
auto CI : callers) {
1569 auto Attrs = CI->getAttributes();
1570 AttributeList NewAttrs;
1573 for (
auto attr : Attrs.getAttributes(AttributeList::FunctionIndex))
1574 NewAttrs = NewAttrs.addAttribute(F->getContext(),
1575 AttributeList::FunctionIndex, attr);
1577 for (
auto attr : Attrs.getAttributes(AttributeList::ReturnIndex))
1578 NewAttrs = NewAttrs.addAttribute(F->getContext(),
1579 AttributeList::ReturnIndex, attr);
1581 SmallVector<Value *, 1> vals;
1582 for (
size_t j = 0, end = CI->arg_size(); j < end; j++) {
1584 auto T = CI->getArgOperand(j)->getType();
1585 if (
auto AT = dyn_cast<ArrayType>(T)) {
1586 if (isa<PointerType>(AT->getElementType())) {
1587 if (changed.count(j)) {
1592 Attrs.getAttributes(AttributeList::FirstArgIndex + j)) {
1593 if (attr.isStringAttribute() &&
1594 attr.getKindAsString() ==
"enzyme_sret_v") {
1596 kind =
"enzyme_sret";
1597 value = attr.getValueAsString();
1598 }
else if (attr.isStringAttribute() &&
1599 attr.getKindAsString() ==
"enzymejl_returnRoots_v") {
1601 kind =
"enzymejl_returnRoots";
1602 value = attr.getValueAsString();
1603 }
else if (attr.isStringAttribute() &&
1604 attr.getKindAsString() ==
"enzymejl_rooted_typ_v") {
1606 kind =
"enzymejl_rooted_typ_v";
1607 value = attr.getValueAsString();
1610 for (
unsigned i = 0; i < AT->getNumElements(); i++) {
1612 NewAttrs = NewAttrs.addAttribute(
1613 F->getContext(), AttributeList::FirstArgIndex + vals.size(),
1614 Attribute::get(F->getContext(), kind, value));
1623 for (
auto attr : Attrs.getAttributes(AttributeList::FirstArgIndex + j)) {
1624 if (attr.isStringAttribute() &&
1625 attr.getKindAsString() ==
"enzyme_sret_v") {
1626 NewAttrs = NewAttrs.addAttribute(
1627 F->getContext(), AttributeList::FirstArgIndex + vals.size(),
1628 Attribute::get(F->getContext(),
"enzyme_sret",
1629 attr.getValueAsString()));
1630 }
else if (attr.isStringAttribute() &&
1631 attr.getKindAsString() ==
"enzymejl_returnRoots_v") {
1632 NewAttrs = NewAttrs.addAttribute(
1633 F->getContext(), AttributeList::FirstArgIndex + vals.size(),
1634 Attribute::get(F->getContext(),
"enzymejl_returnRoots",
1635 attr.getValueAsString()));
1636 }
else if (attr.isStringAttribute() &&
1637 attr.getKindAsString() ==
"enzymejl_rooted_typ_v") {
1638 NewAttrs = NewAttrs.addAttribute(
1639 F->getContext(), AttributeList::FirstArgIndex + vals.size(),
1640 Attribute::get(F->getContext(),
"enzymejl_rooted_typ",
1641 attr.getValueAsString()));
1643 NewAttrs = NewAttrs.addAttribute(
1644 F->getContext(), AttributeList::FirstArgIndex + vals.size(),
1649 vals.push_back(CI->getArgOperand(j));
1652 SmallVector<OperandBundleDef, 1> Bundles;
1653 for (
unsigned I = 0, E = CI->getNumOperandBundles(); I != E; ++I)
1654 Bundles.emplace_back(CI->getOperandBundleAt(I));
1655 auto NC = B.CreateCall(NewF, vals, Bundles);
1656 NC->setAttributes(NewAttrs);
1658 SmallVector<std::pair<unsigned, MDNode *>, 4> TheMDs;
1659 CI->getAllMetadataOtherThanDebugLoc(TheMDs);
1660 SmallVector<unsigned, 1> toCopy;
1661 for (
auto pair : TheMDs)
1662 toCopy.push_back(pair.first);
1663 if (!toCopy.empty())
1664 NC->copyMetadata(*CI, toCopy);
1665 NC->setDebugLoc(CI->getDebugLoc());
1667 if (!RT->isVoidTy()) {
1669 CI->replaceAllUsesWith(NC);
1672 NC->setCallingConv(CI->getCallingConv());
1673 CI->eraseFromParent();
1675 NewF->setAttributes(NewAttrs);
1676 SmallVector<std::pair<unsigned, MDNode *>, 1> MD;
1677 F->getAllMetadata(MD);
1678 for (
auto pair : MD)
1679 if (pair.first != LLVMContext::MD_dbg)
1680 NewF->addMetadata(pair.first, *pair.second);
1682 NewF->setCallingConv(F->getCallingConv());
1683 F->eraseFromParent();