@@ -2963,6 +2963,132 @@ bool Attributor::shouldSeedAttribute(AbstractAttribute &AA) {
29632963 return Result;
29642964}
29652965
2966+ // For now: argument can be put in the struct if it's write only and
2967+ // has no aliases.
2968+ static bool canBeComapctedInAStruct (const Argument &Arg, Attributor &A,
2969+ const AbstractAttribute &QueryingAA) {
2970+ IRPosition ArgPosition = IRPosition::argument (Arg);
2971+ // Check if Arg has no alias.
2972+ auto *AAliasInfo =
2973+ A.getAAFor <AANoAlias>(QueryingAA, ArgPosition, DepClassTy::NONE);
2974+ if (!AAliasInfo || !AAliasInfo->isKnownNoAlias ())
2975+ return false ;
2976+
2977+ // Check if Arg is write-only.
2978+ const auto *MemBehaviorAA =
2979+ A.getAAFor <AAMemoryBehavior>(QueryingAA, ArgPosition, DepClassTy::NONE);
2980+ if (!MemBehaviorAA || !MemBehaviorAA->isKnownWriteOnly ())
2981+ return false ;
2982+
2983+ return true ;
2984+ }
2985+
2986+ static void replaceArgRetWithStructRetCalls (Function &OldFunction,
2987+ Function &NewFunction) {
2988+ for (auto UseItr = OldFunction.use_begin (); UseItr != OldFunction.use_end ();
2989+ ++UseItr) {
2990+ CallBase *Call = dyn_cast<CallBase>(UseItr->getUser ());
2991+ if (!Call)
2992+ continue ;
2993+
2994+ IRBuilder<> Builder (Call);
2995+ SmallVector<Value *, 8 > NewArgs;
2996+ for (unsigned ArgIdx = 0 ; ArgIdx < Call->arg_size (); ++ArgIdx)
2997+ if (std::find_if (OldFunction.arg_begin (), OldFunction.arg_end (),
2998+ [&](Argument &Arg) {
2999+ return &Arg == Call->getArgOperand (ArgIdx);
3000+ }) == OldFunction.arg_end ())
3001+ NewArgs.push_back (Call->getArgOperand (ArgIdx));
3002+
3003+ CallInst *NewCall = Builder.CreateCall (&NewFunction, NewArgs);
3004+ Call->replaceAllUsesWith (NewCall);
3005+ Call->eraseFromParent ();
3006+ }
3007+ }
3008+
3009+ static bool convertOutArgsToRetStruct (Function &F, Attributor &A,
3010+ AbstractAttribute &QueryingAA) {
3011+ // Get valid ptr args.
3012+ DenseMap<Argument *, Type *> PtrToType;
3013+ for (unsigned ArgIdx = 0 ; ArgIdx < F.arg_size (); ++ArgIdx) {
3014+ Argument *Arg = F.getArg (ArgIdx);
3015+ if (Arg->getType ()->isPointerTy () &&
3016+ canBeComapctedInAStruct (*Arg, A, QueryingAA)) {
3017+ // Get the the type of the pointer through its users
3018+ for (auto UseItr = Arg->use_begin (); UseItr != Arg->use_end (); ++UseItr) {
3019+ auto *Store = dyn_cast<StoreInst>(UseItr->getUser ());
3020+ if (Store)
3021+ PtrToType[Arg] = Store->getValueOperand ()->getType ();
3022+ }
3023+ }
3024+ }
3025+
3026+ // If there is no valid candidates then return false.
3027+ if (PtrToType.empty ())
3028+ return false ;
3029+
3030+ // Create the new struct return type.
3031+ SmallVector<Type *, 4 > OutStructElements;
3032+ if (auto *OriginalFuncTy = F.getReturnType (); !OriginalFuncTy->isVoidTy ())
3033+ OutStructElements.push_back (OriginalFuncTy);
3034+
3035+ for (const auto &[Arg, Type] : PtrToType)
3036+ OutStructElements.push_back (Type);
3037+
3038+ auto *ReturnStructType = StructType::create (F.getContext (), OutStructElements,
3039+ (F.getName () + " Out" ).str ());
3040+
3041+ // Get the new Args.
3042+ SmallVector<Type *, 4 > NewParamTypes;
3043+ for (unsigned ArgIdx = 0 ; ArgIdx < F.arg_size (); ++ArgIdx)
3044+ if (!PtrToType.count (F.getArg (ArgIdx)))
3045+ NewParamTypes.push_back (F.getArg (ArgIdx)->getType ());
3046+
3047+ auto *NewFunctionType =
3048+ FunctionType::get (ReturnStructType, NewParamTypes, F.isVarArg ());
3049+ auto *NewFunction = Function::Create (NewFunctionType, F.getLinkage (),
3050+ F.getAddressSpace (), F.getName ());
3051+
3052+ // Map old args to new args.
3053+ ValueToValueMapTy VMap;
3054+ auto *NewArgIt = NewFunction->arg_begin ();
3055+ for (Argument &OldArg : F.args ())
3056+ if (!PtrToType.count (F.getArg (OldArg.getArgNo ())))
3057+ VMap[&OldArg] = &(*NewArgIt++);
3058+
3059+ // Clone the old function into the new one.
3060+ SmallVector<ReturnInst *, 8 > Returns;
3061+ CloneFunctionInto (NewFunction, &F, VMap,
3062+ CloneFunctionChangeType::LocalChangesOnly, Returns);
3063+
3064+ // Update the return values (make it struct).
3065+ for (ReturnInst *Ret : Returns) {
3066+ IRBuilder<> Builder (Ret);
3067+ SmallVector<Value *, 4 > StructValues;
3068+ // Include original return type, if any
3069+ if (auto *OriginalFuncTy = F.getReturnType (); !OriginalFuncTy->isVoidTy ())
3070+ StructValues.push_back (Ret->getReturnValue ());
3071+
3072+ // Create a load instruction to fill the struct element.
3073+ for (const auto &[Arg, Ty] : PtrToType) {
3074+ Value *OutVal = Builder.CreateLoad (Ty, VMap[Arg]);
3075+ StructValues.push_back (OutVal);
3076+ }
3077+
3078+ // Build the return struct incrementally.
3079+ Value *StructRetVal = UndefValue::get (ReturnStructType);
3080+ for (unsigned i = 0 ; i < StructValues.size (); ++i)
3081+ StructRetVal =
3082+ Builder.CreateInsertValue (StructRetVal, StructValues[i], i);
3083+
3084+ Builder.CreateRet (StructRetVal);
3085+ Ret->eraseFromParent ();
3086+ }
3087+
3088+ replaceArgRetWithStructRetCalls (F, *NewFunction);
3089+ F.eraseFromParent ();
3090+ }
3091+
29663092ChangeStatus Attributor::rewriteFunctionSignatures (
29673093 SmallSetVector<Function *, 8 > &ModifiedFns) {
29683094 ChangeStatus Changed = ChangeStatus::UNCHANGED;
0 commit comments