diff --git a/llvm/include/llvm/Transforms/IPO/Attributor.h b/llvm/include/llvm/Transforms/IPO/Attributor.h --- a/llvm/include/llvm/Transforms/IPO/Attributor.h +++ b/llvm/include/llvm/Transforms/IPO/Attributor.h @@ -831,6 +831,97 @@ bool checkForAllUses(const function_ref &Pred, const AbstractAttribute &QueryingAA, const Value &V); + /// Helper struct used in the communication between an abstract attribute (AA) + /// that wants to change the signature of a function and the Attributor which + /// applies the changes. The struct is partially initialized with the + /// information from the AA (see the constructor). All other members are + /// provided by the Attributor prior to invoking any callbacks. + struct ArgumentReplacementInfo { + /// Callee repair callback type + /// + /// The function repair callback is invoked once to rewire the replacement + /// arguments in the body of the new function. The argument replacement info + /// is passed, as build from the registerFunctionSignatureRewrite call, as + /// well as the replacement function and an iteratore to the first + /// replacement argument. + using CalleeRepairCBTy = std::function; + + /// Abstract call site (ACS) repair callback type + /// + /// The abstract call site repair callback is invoked once on every abstract + /// call site of the replaced function (\see ReplacedFn). The callback needs + /// to provide the operands for the call to the new replacement function. + /// The number and type of the operands appended to the provided vector + /// (second argument) is defined by the number and types determined through + /// the replacement type vector (\see ReplacementTypes). The first argument + /// is the ArgumentReplacementInfo object registered with the Attributor + /// through the registerFunctionSignatureRewrite call. + using ACSRepairCBTy = + std::function &)>; + + /// Simple getters, see the corresponding members for details. + ///{ + + Attributor &getAttributor() const { return A; } + const Function &getReplacedFn() const { return ReplacedFn; } + const Argument &getReplacedArg() const { return ReplacedArg; } + unsigned getNumReplacementArgs() const { return ReplacementTypes.size(); } + const SmallVectorImpl &getReplacementTypes() const { + return ReplacementTypes; + } + + ///} + + private: + /// Constructor that takes the argument to be replaced, the types of + /// the replacement arguments, as well as callbacks to repair the call sites + /// and new function after the replacement happened. + ArgumentReplacementInfo(Attributor &A, Argument &Arg, + ArrayRef ReplacementTypes, + CalleeRepairCBTy &&CalleeRepairCB, + ACSRepairCBTy &&ACSRepairCB) + : A(A), ReplacedFn(*Arg.getParent()), ReplacedArg(Arg), + ReplacementTypes(ReplacementTypes.begin(), ReplacementTypes.end()), + CalleeRepairCB(std::move(CalleeRepairCB)), + ACSRepairCB(std::move(ACSRepairCB)) {} + + /// Reference to the attributor to allow access from the callbacks. + Attributor &A; + + /// The "old" function replaced by ReplacementFn. + const Function &ReplacedFn; + + /// The "old" argument replaced by new ones defined via ReplacementTypes. + const Argument &ReplacedArg; + + /// The types of the arguments replacing ReplacedArg. + const SmallVector ReplacementTypes; + + /// Callee repair callback, see CalleeRepairCBTy. + const CalleeRepairCBTy CalleeRepairCB; + + /// Abstract call site (ACS) repair callback, see ACSRepairCBTy. + const ACSRepairCBTy ACSRepairCB; + + /// Allow access to the private members from the Attributor. + friend class Attributor; + }; + + /// Register a rewrite for a function signature. + /// + /// The argument \p Arg is replaced with new ones defined by the number, + /// order, and types in \p ReplacementTypes. The rewiring at the call sites is + /// done through \p ACSRepairCB and at the callee site through + /// \p CalleeRepairCB. + /// + /// \returns True, if the replacement was registered, false otherwise. + bool registerFunctionSignatureRewrite( + Argument &Arg, ArrayRef ReplacementTypes, + ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB, + ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB); + /// Check \p Pred on all function call sites. /// /// This method will evaluate \p Pred on call sites and return @@ -961,6 +1052,11 @@ return nullptr; } + /// Apply all requested function signature rewrites + /// (\see registerFunctionSignatureRewrite) and return Changed if the module + /// was altered. + ChangeStatus rewriteFunctionSignatures(); + /// The set of all abstract attributes. ///{ using AAVector = SmallVector; @@ -984,6 +1080,10 @@ QueryMapTy QueryMap; ///} + /// Map to remember all requested signature changes (= argument replacements). + DenseMap> + ArgumentReplacementMap; + /// The information cache that holds pre-processed (LLVM-IR) information. InformationCache &InfoCache; diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -2195,6 +2195,19 @@ indicatePessimisticFixpoint(); } + /// See AbstractAttribute::manifest(...). + ChangeStatus manifest(Attributor &A) override { + ChangeStatus Changed = AAIsDeadFloating::manifest(A); + Argument &Arg = *getAssociatedArgument(); + if (Arg.getParent()->hasLocalLinkage()) + if (A.registerFunctionSignatureRewrite( + Arg, /* ReplacementTypes */ {}, + Attributor::ArgumentReplacementInfo::CalleeRepairCBTy{}, + Attributor::ArgumentReplacementInfo::ACSRepairCBTy{})) + return ChangeStatus::CHANGED; + return Changed; + } + /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(IsDead) } }; @@ -5025,6 +5038,9 @@ } } + // Rewrite the functions as requested during manifest. + ManifestChange = ManifestChange | rewriteFunctionSignatures(); + if (VerifyMaxFixpointIterations && IterationCounter != MaxFixpointIterations) { errs() << "\n[Attributor] Fixpoint iteration done after: " @@ -5037,6 +5053,254 @@ return ManifestChange; } +bool Attributor::registerFunctionSignatureRewrite( + Argument &Arg, ArrayRef ReplacementTypes, + ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB, + ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB) { + + auto CallSiteCanBeChanged = [](AbstractCallSite ACS) { + return !ACS.isCallbackCall(); + }; + + Function *Fn = Arg.getParent(); + // Avoid var-arg functions for now. + if (Fn->isVarArg()) { + LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite var-args functions\n"); + return false; + } + + // Avoid functions with complicated argument passing semantics. + AttributeList FnAttributeList = Fn->getAttributes(); + if (FnAttributeList.hasAttrSomewhere(Attribute::Nest) || + FnAttributeList.hasAttrSomewhere(Attribute::StructRet) || + FnAttributeList.hasAttrSomewhere(Attribute::InAlloca)) { + LLVM_DEBUG( + dbgs() << "[Attributor] Cannot rewrite due to complex attribute\n"); + return false; + } + + // Avoid callbacks for now. + if (!checkForAllCallSites(CallSiteCanBeChanged, *Fn, true, nullptr)) { + LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite all call sites\n"); + return false; + } + + auto InstPred = [](Instruction &I) { + if (auto *CI = dyn_cast(&I)) + return !CI->isMustTailCall(); + return true; + }; + + // Forbid must-tail calls for now. + // TODO: + bool AnyDead; + auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn); + if (!checkForAllInstructionsImpl(OpcodeInstMap, InstPred, nullptr, AnyDead, + {Instruction::Call})) { + LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite due to instructions\n"); + return false; + } + + SmallVectorImpl &ARIs = ArgumentReplacementMap[Fn]; + if (ARIs.size() == 0) + ARIs.resize(Fn->arg_size()); + + // If we have a replacement already with less than or equal new arguments, + // ignore this request. + ArgumentReplacementInfo *&ARI = ARIs[Arg.getArgNo()]; + if (ARI && ARI->getNumReplacementArgs() <= ReplacementTypes.size()) { + LLVM_DEBUG(dbgs() << "[Attributor] Existing rewrite is preferred\n"); + return false; + } + + // If we have a replacement already but we like the new one better, delete + // the old. + if (ARI) + delete ARI; + + // Remember the replacement. + ARI = new ArgumentReplacementInfo(*this, Arg, ReplacementTypes, + std::move(CalleeRepairCB), + std::move(ACSRepairCB)); + + return true; +} + +ChangeStatus Attributor::rewriteFunctionSignatures() { + ChangeStatus Changed = ChangeStatus::UNCHANGED; + + for (auto &It : ArgumentReplacementMap) { + Function *ReplacedFn = It.getFirst(); + + // Deleted functions do not require rewrites. + if (ToBeDeletedFunctions.count(ReplacedFn)) + continue; + + const SmallVectorImpl &ARIs = It.getSecond(); + assert(ARIs.size() == ReplacedFn->arg_size() && "Inconsistent state!"); + + SmallVector ReplacementArgumentTypes; + SmallVector ReplacementArgumentAttributes; + + // Collect replacement argument types and copy over existing attributes. + AttributeList ReplacedFnAttributeList = ReplacedFn->getAttributes(); + for (Argument &Arg : ReplacedFn->args()) { + if (ArgumentReplacementInfo *ARI = ARIs[Arg.getArgNo()]) { + ReplacementArgumentTypes.append(ARI->ReplacementTypes.begin(), + ARI->ReplacementTypes.end()); + ReplacementArgumentAttributes.append(ARI->getNumReplacementArgs(), + AttributeSet()); + } else { + ReplacementArgumentTypes.push_back(Arg.getType()); + ReplacementArgumentAttributes.push_back( + ReplacedFnAttributeList.getParamAttributes(Arg.getArgNo())); + } + } + + FunctionType *ReplacedFnTy = ReplacedFn->getFunctionType(); + Type *RetTy = ReplacedFnTy->getReturnType(); + + // Construct the new function type using the new arguments types. + FunctionType *ReplacementFnTy = FunctionType::get( + RetTy, ReplacementArgumentTypes, ReplacedFnTy->isVarArg()); + + LLVM_DEBUG(dbgs() << "[Attributor] Function rewrite '" + << ReplacedFn->getName() << "' from " + << *ReplacedFn->getFunctionType() << " to " + << *ReplacementFnTy << "\n"); + + // Create the new function body and insert it into the module. + Function *ReplacementFn = + Function::Create(ReplacementFnTy, ReplacedFn->getLinkage(), + ReplacedFn->getAddressSpace(), ""); + ReplacedFn->getParent()->getFunctionList().insert(ReplacedFn->getIterator(), + ReplacementFn); + ReplacementFn->takeName(ReplacedFn); + ReplacementFn->copyAttributesFrom(ReplacedFn); + + // Patch the pointer to LLVM function in debug info descriptor. + ReplacementFn->setSubprogram(ReplacedFn->getSubprogram()); + ReplacedFn->setSubprogram(nullptr); + + // Recompute the parameter attributes list based on the new arguments for + // the function. + LLVMContext &Ctx = ReplacedFn->getContext(); + ReplacementFn->setAttributes( + AttributeList::get(Ctx, ReplacedFnAttributeList.getFnAttributes(), + ReplacedFnAttributeList.getRetAttributes(), + ReplacementArgumentAttributes)); + + // Since we have now created the new function, splice the body of the old + // function right into the new function, leaving the old rotting hulk of the + // function empty. + ReplacementFn->getBasicBlockList().splice(ReplacementFn->begin(), + ReplacedFn->getBasicBlockList()); + + // Set of all "call-like" instructions that invoke the replaced function. + SmallPtrSet ReplacedCallSites; + + // Callback to create a new "call-like" instruction for a given one. + auto CallSiteReplacementCreator = [&](AbstractCallSite ACS) { + CallBase *ReplacedCB = cast(ACS.getInstruction()); + const AttributeList &ReplacedCallAttributeList = + ReplacedCB->getAttributes(); + + // Collect the new argument operands for the replacement call site. + SmallVector NewArgOperands; + SmallVector NewArgOperandAttributes; + for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); ++OldArgNum) { + unsigned NewFirstArgNum = NewArgOperands.size(); + if (ArgumentReplacementInfo *ARI = ARIs[OldArgNum]) { + if (ARI->ACSRepairCB) + ARI->ACSRepairCB(*ARI, ACS, NewArgOperands); + assert(ARI->getNumReplacementArgs() + NewFirstArgNum == + NewArgOperands.size() && + "ACS repair callback did not provide as many operand as new " + "types were registered!"); + // TODO: Exose the attribute set to the ACS repair callback + NewArgOperandAttributes.append(ARI->ReplacementTypes.size(), + AttributeSet()); + } else { + NewArgOperands.push_back(ACS.getCallArgOperand(OldArgNum)); + NewArgOperandAttributes.push_back( + ReplacedCallAttributeList.getParamAttributes(OldArgNum)); + } + } + + assert(NewArgOperands.size() == NewArgOperandAttributes.size() && + "Mismatch # argument operands vs. # argument operand attributes!"); + assert(NewArgOperands.size() == ReplacementFn->arg_size() && + "Mismatch # argument operands vs. # function arguments!"); + + SmallVector OperandBundleDefs; + ReplacedCB->getOperandBundlesAsDefs(OperandBundleDefs); + + // Create a new call or invoke instruction to replace the old one. + CallBase *ReplacementCB; + if (InvokeInst *II = dyn_cast(ReplacedCB)) { + ReplacementCB = InvokeInst::Create(ReplacementFn, II->getNormalDest(), + II->getUnwindDest(), NewArgOperands, + OperandBundleDefs, "", ReplacedCB); + } else { + auto *NewCI = CallInst::Create(ReplacementFn, NewArgOperands, + OperandBundleDefs, "", ReplacedCB); + NewCI->setTailCallKind(cast(ReplacedCB)->getTailCallKind()); + ReplacementCB = NewCI; + } + + // Copy over various properties and the new attributes. + ReplacedCB->replaceAllUsesWith(ReplacementCB); + uint64_t W; + if (ReplacedCB->extractProfTotalWeight(W)) + ReplacementCB->setProfWeight(W); + ReplacementCB->setCallingConv(ReplacedCB->getCallingConv()); + ReplacementCB->setDebugLoc(ReplacedCB->getDebugLoc()); + ReplacementCB->takeName(ReplacedCB); + ReplacementCB->setAttributes( + AttributeList::get(Ctx, ReplacedCallAttributeList.getFnAttributes(), + ReplacedCallAttributeList.getRetAttributes(), + NewArgOperandAttributes)); + + bool Inserted = ReplacedCallSites.insert(ReplacedCB).second; + assert(Inserted && "Call site was replaced twice!"); + (void)Inserted; + + return true; + }; + + // Use the CallSiteReplacementCreator to create replacement call sites. + bool Success = checkForAllCallSites(CallSiteReplacementCreator, *ReplacedFn, + true, nullptr); + assert(Success && "Assumed call site replacement to succeed!"); + + // Rewire the arguments. + auto ReplacedFnArgIt = ReplacedFn->arg_begin(); + auto ReplacementFnArgIt = ReplacementFn->arg_begin(); + for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); + ++OldArgNum, ++ReplacedFnArgIt) { + if (ArgumentReplacementInfo *ARI = ARIs[OldArgNum]) { + if (ARI->CalleeRepairCB) + ARI->CalleeRepairCB(*ARI, *ReplacementFn, ReplacementFnArgIt); + ReplacementFnArgIt += ARI->ReplacementTypes.size(); + } else { + ReplacementFnArgIt->takeName(&*ReplacedFnArgIt); + ReplacedFnArgIt->replaceAllUsesWith(&*ReplacementFnArgIt); + ++ReplacementFnArgIt; + } + } + + // Eliminate the instructions *after* we visited all of them. + for (Instruction *ReplacedCallSite : ReplacedCallSites) + ReplacedCallSite->eraseFromParent(); + + assert(ReplacedFn->getNumUses() == 0 && "Unexpected leftover uses!"); + ReplacedFn->eraseFromParent(); + Changed = ChangeStatus::CHANGED; + } + + return Changed; +} + void Attributor::initializeInformationCache(Function &F) { // Walk all instructions to find interesting instructions that might be diff --git a/llvm/test/Transforms/ArgumentPromotion/2008-02-01-ReturnAttrs.ll b/llvm/test/Transforms/ArgumentPromotion/2008-02-01-ReturnAttrs.ll --- a/llvm/test/Transforms/ArgumentPromotion/2008-02-01-ReturnAttrs.ll +++ b/llvm/test/Transforms/ArgumentPromotion/2008-02-01-ReturnAttrs.ll @@ -5,7 +5,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@deref ; ARGPROMOTION-SAME: (i32 [[X_VAL:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: ret i32 [[X_VAL]] +; ARGPROMOTION-NEXT: ret i32 [[X_VAL:%.*]] ; entry: %tmp2 = load i32, i32* %x, align 4 @@ -17,7 +17,7 @@ ; ARGPROMOTION-SAME: (i32 [[X:%.*]]) ; ARGPROMOTION-NEXT: entry: ; ARGPROMOTION-NEXT: [[X_ADDR:%.*]] = alloca i32 -; ARGPROMOTION-NEXT: store i32 [[X]], i32* [[X_ADDR]], align 4 +; ARGPROMOTION-NEXT: store i32 [[X:%.*]], i32* [[X_ADDR]], align 4 ; ARGPROMOTION-NEXT: [[X_ADDR_VAL:%.*]] = load i32, i32* [[X_ADDR]], align 4 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = call i32 @deref(i32 [[X_ADDR_VAL]]) ; ARGPROMOTION-NEXT: ret i32 [[TMP1]] diff --git a/llvm/test/Transforms/ArgumentPromotion/2008-07-02-array-indexing.ll b/llvm/test/Transforms/ArgumentPromotion/2008-07-02-array-indexing.ll --- a/llvm/test/Transforms/ArgumentPromotion/2008-07-02-array-indexing.ll +++ b/llvm/test/Transforms/ArgumentPromotion/2008-07-02-array-indexing.ll @@ -8,8 +8,8 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee ; ARGPROMOTION-SAME: (i1 [[C:%.*]], i32* [[A:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[A_0:%.*]] = load i32, i32* [[A]] -; ARGPROMOTION-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; ARGPROMOTION-NEXT: [[A_0:%.*]] = load i32, i32* [[A:%.*]] +; ARGPROMOTION-NEXT: br i1 [[C:%.*]], label [[T:%.*]], label [[F:%.*]] ; ARGPROMOTION: T: ; ARGPROMOTION-NEXT: ret i32 [[A_0]] ; ARGPROMOTION: F: diff --git a/llvm/test/Transforms/ArgumentPromotion/X86/attributes.ll b/llvm/test/Transforms/ArgumentPromotion/X86/attributes.ll --- a/llvm/test/Transforms/ArgumentPromotion/X86/attributes.ll +++ b/llvm/test/Transforms/ArgumentPromotion/X86/attributes.ll @@ -10,8 +10,8 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@no_promote_avx2 ; ARGPROMOTION-SAME: (<4 x i64>* [[ARG:%.*]], <4 x i64>* readonly [[ARG1:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1]] -; ARGPROMOTION-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <4 x i64>, <4 x i64>* [[ARG1:%.*]] +; ARGPROMOTION-NEXT: store <4 x i64> [[TMP]], <4 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -30,7 +30,7 @@ ; ARGPROMOTION-NEXT: call void @llvm.memset.p0i8.i64(i8* align 32 [[TMP3]], i8 0, i64 32, i1 false) ; ARGPROMOTION-NEXT: call fastcc void @no_promote_avx2(<4 x i64>* [[TMP2]], <4 x i64>* [[TMP]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -48,7 +48,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@promote_avx2 ; ARGPROMOTION-SAME: (<4 x i64>* [[ARG:%.*]], <4 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <4 x i64> [[ARG1_VAL]], <4 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <4 x i64> [[ARG1_VAL:%.*]], <4 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -68,7 +68,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <4 x i64>, <4 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @promote_avx2(<4 x i64>* [[TMP2]], <4 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <4 x i64>, <4 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <4 x i64> [[TMP4]], <4 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: diff --git a/llvm/test/Transforms/ArgumentPromotion/X86/min-legal-vector-width.ll b/llvm/test/Transforms/ArgumentPromotion/X86/min-legal-vector-width.ll --- a/llvm/test/Transforms/ArgumentPromotion/X86/min-legal-vector-width.ll +++ b/llvm/test/Transforms/ArgumentPromotion/X86/min-legal-vector-width.ll @@ -11,7 +11,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -31,7 +31,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer512(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -50,7 +50,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -70,7 +70,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer256(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -89,7 +89,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -109,7 +109,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal512_prefer512_call_avx512_legal512_prefer256(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -128,7 +128,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -148,7 +148,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal512_prefer512(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -167,8 +167,8 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64>* readonly [[ARG1:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]] -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1:%.*]] +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -187,7 +187,7 @@ ; ARGPROMOTION-NEXT: call void @llvm.memset.p0i8.i64(i8* align 32 [[TMP3]], i8 0, i64 32, i1 false) ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal256_prefer256_call_avx512_legal512_prefer256(<8 x i64>* [[TMP2]], <8 x i64>* [[TMP]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -206,8 +206,8 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64>* readonly [[ARG1:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1]] -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: [[TMP:%.*]] = load <8 x i64>, <8 x i64>* [[ARG1:%.*]] +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -226,7 +226,7 @@ ; ARGPROMOTION-NEXT: call void @llvm.memset.p0i8.i64(i8* align 32 [[TMP3]], i8 0, i64 32, i1 false) ; ARGPROMOTION-NEXT: call fastcc void @callee_avx512_legal512_prefer256_call_avx512_legal256_prefer256(<8 x i64>* [[TMP2]], <8 x i64>* [[TMP]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -245,7 +245,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -265,7 +265,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx2_legal256_prefer256_call_avx2_legal512_prefer256(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: @@ -284,7 +284,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256 ; ARGPROMOTION-SAME: (<8 x i64>* [[ARG:%.*]], <8 x i64> [[ARG1_VAL:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL]], <8 x i64>* [[ARG]] +; ARGPROMOTION-NEXT: store <8 x i64> [[ARG1_VAL:%.*]], <8 x i64>* [[ARG:%.*]] ; ARGPROMOTION-NEXT: ret void ; bb: @@ -304,7 +304,7 @@ ; ARGPROMOTION-NEXT: [[TMP_VAL:%.*]] = load <8 x i64>, <8 x i64>* [[TMP]] ; ARGPROMOTION-NEXT: call fastcc void @callee_avx2_legal512_prefer256_call_avx2_legal256_prefer256(<8 x i64>* [[TMP2]], <8 x i64> [[TMP_VAL]]) ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load <8 x i64>, <8 x i64>* [[TMP2]], align 32 -; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG]], align 2 +; ARGPROMOTION-NEXT: store <8 x i64> [[TMP4]], <8 x i64>* [[ARG:%.*]], align 2 ; ARGPROMOTION-NEXT: ret void ; bb: diff --git a/llvm/test/Transforms/ArgumentPromotion/X86/thiscall.ll b/llvm/test/Transforms/ArgumentPromotion/X86/thiscall.ll --- a/llvm/test/Transforms/ArgumentPromotion/X86/thiscall.ll +++ b/llvm/test/Transforms/ArgumentPromotion/X86/thiscall.ll @@ -16,7 +16,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun ; ARGPROMOTION-SAME: (%struct.a* [[THIS:%.*]], <{ [[STRUCT_A:%.*]] }>* inalloca [[TMP0:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0 +; ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A:%.*]] }>, <{ [[STRUCT_A]] }>* [[TMP0:%.*]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]]) @@ -26,7 +26,7 @@ ; GLOBALOPT_ARGPROMOTION-LABEL: define {{[^@]+}}@internalfun ; GLOBALOPT_ARGPROMOTION-SAME: (<{ [[STRUCT_A:%.*]] }>* [[TMP0:%.*]]) unnamed_addr ; GLOBALOPT_ARGPROMOTION-NEXT: entry: -; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[TMP0]], i32 0, i32 0 +; GLOBALOPT_ARGPROMOTION-NEXT: [[A:%.*]] = getelementptr inbounds <{ [[STRUCT_A:%.*]] }>, <{ [[STRUCT_A]] }>* [[TMP0:%.*]], i32 0, i32 0 ; GLOBALOPT_ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A]] }>, align 4 ; GLOBALOPT_ARGPROMOTION-NEXT: [[TMP1:%.*]] = getelementptr inbounds <{ [[STRUCT_A]] }>, <{ [[STRUCT_A]] }>* [[ARGMEM]], i32 0, i32 0 ; GLOBALOPT_ARGPROMOTION-NEXT: [[CALL:%.*]] = call x86_thiscallcc %struct.a* @copy_ctor(%struct.a* [[TMP1]], %struct.a* dereferenceable(1) [[A]]) @@ -48,7 +48,7 @@ ; ARGPROMOTION-SAME: (%struct.a* [[A:%.*]]) ; ARGPROMOTION-NEXT: [[INALLOCA_SAVE:%.*]] = tail call i8* @llvm.stacksave() ; ARGPROMOTION-NEXT: [[ARGMEM:%.*]] = alloca inalloca <{ [[STRUCT_A:%.*]] }>, align 4 -; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]]) +; ARGPROMOTION-NEXT: call x86_thiscallcc void @internalfun(%struct.a* [[A:%.*]], <{ [[STRUCT_A]] }>* inalloca [[ARGMEM]]) ; ARGPROMOTION-NEXT: call void @llvm.stackrestore(i8* [[INALLOCA_SAVE]]) ; ARGPROMOTION-NEXT: ret void ; diff --git a/llvm/test/Transforms/ArgumentPromotion/aggregate-promote.ll b/llvm/test/Transforms/ArgumentPromotion/aggregate-promote.ll --- a/llvm/test/Transforms/ArgumentPromotion/aggregate-promote.ll +++ b/llvm/test/Transforms/ArgumentPromotion/aggregate-promote.ll @@ -9,7 +9,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@test ; ARGPROMOTION-SAME: (i32 [[P_0_2_VAL:%.*]], i32 [[P_0_3_VAL:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[V:%.*]] = add i32 [[P_0_3_VAL]], [[P_0_2_VAL]] +; ARGPROMOTION-NEXT: [[V:%.*]] = add i32 [[P_0_3_VAL:%.*]], [[P_0_2_VAL:%.*]] ; ARGPROMOTION-NEXT: ret i32 [[V]] ; entry: diff --git a/llvm/test/Transforms/ArgumentPromotion/attrs.ll b/llvm/test/Transforms/ArgumentPromotion/attrs.ll --- a/llvm/test/Transforms/ArgumentPromotion/attrs.ll +++ b/llvm/test/Transforms/ArgumentPromotion/attrs.ll @@ -1,6 +1,7 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -argpromotion -S | FileCheck %s --check-prefixes=ARGPROMOTION,ALL ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s --check-prefixes=ARGPROMOTION,ALL +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s --check-prefixes=ALL,ATTRIBUTOR %struct.ss = type { i32, i64 } @@ -11,16 +12,26 @@ ; ARGPROMOTION-NEXT: entry: ; ARGPROMOTION-NEXT: [[B:%.*]] = alloca [[STRUCT_SS:%.*]] ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[B_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[B_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i64 [[B_1]], i64* [[DOT1]] +; ARGPROMOTION-NEXT: store i64 [[B_1:%.*]], i64* [[DOT1]] ; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4 ; ARGPROMOTION-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 ; ARGPROMOTION-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4 -; ARGPROMOTION-NEXT: store i32 0, i32* [[X]] +; ARGPROMOTION-NEXT: store i32 0, i32* [[X:%.*]] ; ARGPROMOTION-NEXT: ret void ; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@f +; ATTRIBUTOR-SAME: (%struct.ss* noalias nocapture nonnull byval align 8 dereferenceable(12) [[B:%.*]], i32* nocapture nonnull writeonly byval dereferenceable(4) [[X:%.*]]) +; ATTRIBUTOR-NEXT: entry: +; ATTRIBUTOR-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS:%.*]], %struct.ss* [[B:%.*]], i32 0, i32 0 +; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 8 +; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 +; ATTRIBUTOR-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 8 +; ATTRIBUTOR-NEXT: store i32 0, i32* [[X:%.*]] +; ATTRIBUTOR-NEXT: ret void +; entry: %tmp = getelementptr %struct.ss, %struct.ss* %b, i32 0, i32 0 @@ -46,9 +57,20 @@ ; ARGPROMOTION-NEXT: [[S_0_VAL:%.*]] = load i32, i32* [[S_0]] ; ARGPROMOTION-NEXT: [[S_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 ; ARGPROMOTION-NEXT: [[S_1_VAL:%.*]] = load i64, i64* [[S_1]] -; ARGPROMOTION-NEXT: call void @f(i32 [[S_0_VAL]], i64 [[S_1_VAL]], i32* byval [[X]], i32 zeroext 0) +; ARGPROMOTION-NEXT: call void @f(i32 [[S_0_VAL]], i64 [[S_1_VAL]], i32* byval [[X:%.*]], i32 zeroext 0) ; ARGPROMOTION-NEXT: ret i32 0 ; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test +; ATTRIBUTOR-SAME: (i32* nocapture writeonly [[X:%.*]]) +; ATTRIBUTOR-NEXT: entry: +; ATTRIBUTOR-NEXT: [[S:%.*]] = alloca [[STRUCT_SS:%.*]] +; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 0 +; ATTRIBUTOR-NEXT: store i32 1, i32* [[TMP1]], align 8 +; ATTRIBUTOR-NEXT: [[TMP4:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 +; ATTRIBUTOR-NEXT: store i64 2, i64* [[TMP4]], align 4 +; ATTRIBUTOR-NEXT: call void @f(%struct.ss* noalias nocapture nonnull byval align 8 dereferenceable(12) [[S]], i32* nocapture writeonly byval [[X:%.*]]) +; ATTRIBUTOR-NEXT: ret i32 0 +; entry: %S = alloca %struct.ss %tmp1 = getelementptr %struct.ss, %struct.ss* %S, i32 0, i32 0 diff --git a/llvm/test/Transforms/ArgumentPromotion/basictest.ll b/llvm/test/Transforms/ArgumentPromotion/basictest.ll --- a/llvm/test/Transforms/ArgumentPromotion/basictest.ll +++ b/llvm/test/Transforms/ArgumentPromotion/basictest.ll @@ -5,7 +5,7 @@ define internal i32 @test(i32* %X, i32* %Y) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@test ; ARGPROMOTION-SAME: (i32 [[X_VAL:%.*]], i32 [[Y_VAL:%.*]]) -; ARGPROMOTION-NEXT: [[C:%.*]] = add i32 [[X_VAL]], [[Y_VAL]] +; ARGPROMOTION-NEXT: [[C:%.*]] = add i32 [[X_VAL:%.*]], [[Y_VAL:%.*]] ; ARGPROMOTION-NEXT: ret i32 [[C]] ; %A = load i32, i32* %X @@ -17,7 +17,7 @@ define internal i32 @caller(i32* %B) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@caller ; ARGPROMOTION-SAME: (i32 [[B_VAL1:%.*]]) -; ARGPROMOTION-NEXT: [[C:%.*]] = call i32 @test(i32 1, i32 [[B_VAL1]]) +; ARGPROMOTION-NEXT: [[C:%.*]] = call i32 @test(i32 1, i32 [[B_VAL1:%.*]]) ; ARGPROMOTION-NEXT: ret i32 [[C]] ; %A = alloca i32 diff --git a/llvm/test/Transforms/ArgumentPromotion/byval-2.ll b/llvm/test/Transforms/ArgumentPromotion/byval-2.ll --- a/llvm/test/Transforms/ArgumentPromotion/byval-2.ll +++ b/llvm/test/Transforms/ArgumentPromotion/byval-2.ll @@ -13,14 +13,14 @@ ; ARGPROMOTION-NEXT: entry: ; ARGPROMOTION-NEXT: [[B:%.*]] = alloca [[STRUCT_SS:%.*]] ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[B_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[B_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i64 [[B_1]], i64* [[DOT1]] +; ARGPROMOTION-NEXT: store i64 [[B_1:%.*]], i64* [[DOT1]] ; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4 ; ARGPROMOTION-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 ; ARGPROMOTION-NEXT: store i32 [[TMP2]], i32* [[TMP]], align 4 -; ARGPROMOTION-NEXT: store i32 0, i32* [[X]] +; ARGPROMOTION-NEXT: store i32 0, i32* [[X:%.*]] ; ARGPROMOTION-NEXT: ret void ; entry: @@ -46,7 +46,7 @@ ; ARGPROMOTION-NEXT: [[S_0_VAL:%.*]] = load i32, i32* [[S_0]] ; ARGPROMOTION-NEXT: [[S_1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[S]], i32 0, i32 1 ; ARGPROMOTION-NEXT: [[S_1_VAL:%.*]] = load i64, i64* [[S_1]] -; ARGPROMOTION-NEXT: call void @f(i32 [[S_0_VAL]], i64 [[S_1_VAL]], i32* byval [[X]]) +; ARGPROMOTION-NEXT: call void @f(i32 [[S_0_VAL]], i64 [[S_1_VAL]], i32* byval [[X:%.*]]) ; ARGPROMOTION-NEXT: ret i32 0 ; entry: diff --git a/llvm/test/Transforms/ArgumentPromotion/byval.ll b/llvm/test/Transforms/ArgumentPromotion/byval.ll --- a/llvm/test/Transforms/ArgumentPromotion/byval.ll +++ b/llvm/test/Transforms/ArgumentPromotion/byval.ll @@ -12,9 +12,9 @@ ; ARGPROMOTION-NEXT: entry: ; ARGPROMOTION-NEXT: [[B:%.*]] = alloca [[STRUCT_SS:%.*]] ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[B_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[B_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i64 [[B_1]], i64* [[DOT1]] +; ARGPROMOTION-NEXT: store i64 [[B_1:%.*]], i64* [[DOT1]] ; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4 ; ARGPROMOTION-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 @@ -36,9 +36,9 @@ ; ARGPROMOTION-NEXT: entry: ; ARGPROMOTION-NEXT: [[B:%.*]] = alloca [[STRUCT_SS:%.*]], align 32 ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[B_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[B_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i64 [[B_1]], i64* [[DOT1]] +; ARGPROMOTION-NEXT: store i64 [[B_1:%.*]], i64* [[DOT1]] ; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[STRUCT_SS]], %struct.ss* [[B]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = load i32, i32* [[TMP]], align 4 ; ARGPROMOTION-NEXT: [[TMP2:%.*]] = add i32 [[TMP1]], 1 diff --git a/llvm/test/Transforms/ArgumentPromotion/chained.ll b/llvm/test/Transforms/ArgumentPromotion/chained.ll --- a/llvm/test/Transforms/ArgumentPromotion/chained.ll +++ b/llvm/test/Transforms/ArgumentPromotion/chained.ll @@ -9,7 +9,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@test ; ARGPROMOTION-SAME: (i32 [[X_VAL_VAL:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: ret i32 [[X_VAL_VAL]] +; ARGPROMOTION-NEXT: ret i32 [[X_VAL_VAL:%.*]] ; entry: %y = load i32*, i32** %x diff --git a/llvm/test/Transforms/ArgumentPromotion/control-flow.ll b/llvm/test/Transforms/ArgumentPromotion/control-flow.ll --- a/llvm/test/Transforms/ArgumentPromotion/control-flow.ll +++ b/llvm/test/Transforms/ArgumentPromotion/control-flow.ll @@ -7,11 +7,11 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee ; ARGPROMOTION-SAME: (i1 [[C:%.*]], i32* [[P:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; ARGPROMOTION-NEXT: br i1 [[C:%.*]], label [[T:%.*]], label [[F:%.*]] ; ARGPROMOTION: T: ; ARGPROMOTION-NEXT: ret i32 17 ; ARGPROMOTION: F: -; ARGPROMOTION-NEXT: [[X:%.*]] = load i32, i32* [[P]] +; ARGPROMOTION-NEXT: [[X:%.*]] = load i32, i32* [[P:%.*]] ; ARGPROMOTION-NEXT: ret i32 [[X]] ; entry: diff --git a/llvm/test/Transforms/ArgumentPromotion/control-flow2.ll b/llvm/test/Transforms/ArgumentPromotion/control-flow2.ll --- a/llvm/test/Transforms/ArgumentPromotion/control-flow2.ll +++ b/llvm/test/Transforms/ArgumentPromotion/control-flow2.ll @@ -7,11 +7,11 @@ define internal i32 @callee(i1 %C, i32* %P) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@callee ; ARGPROMOTION-SAME: (i1 [[C:%.*]], i32 [[P_VAL:%.*]]) -; ARGPROMOTION-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; ARGPROMOTION-NEXT: br i1 [[C:%.*]], label [[T:%.*]], label [[F:%.*]] ; ARGPROMOTION: T: ; ARGPROMOTION-NEXT: ret i32 17 ; ARGPROMOTION: F: -; ARGPROMOTION-NEXT: ret i32 [[P_VAL]] +; ARGPROMOTION-NEXT: ret i32 [[P_VAL:%.*]] ; br i1 %C, label %T, label %F diff --git a/llvm/test/Transforms/ArgumentPromotion/crash.ll b/llvm/test/Transforms/ArgumentPromotion/crash.ll --- a/llvm/test/Transforms/ArgumentPromotion/crash.ll +++ b/llvm/test/Transforms/ArgumentPromotion/crash.ll @@ -114,9 +114,9 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@test_inf_promote_callee ; ARGPROMOTION-SAME: (%S* [[ARG:%.*]], %S* [[ARG1:%.*]]) ; ARGPROMOTION-NEXT: bb: -; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[S:%.*]], %S* [[ARG1]], i32 0, i32 0 +; ARGPROMOTION-NEXT: [[TMP:%.*]] = getelementptr [[S:%.*]], %S* [[ARG1:%.*]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP2:%.*]] = load %S*, %S** [[TMP]] -; ARGPROMOTION-NEXT: [[TMP3:%.*]] = getelementptr [[S]], %S* [[ARG]], i32 0, i32 0 +; ARGPROMOTION-NEXT: [[TMP3:%.*]] = getelementptr [[S]], %S* [[ARG:%.*]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[TMP4:%.*]] = load %S*, %S** [[TMP3]] ; ARGPROMOTION-NEXT: [[TMP5:%.*]] = call i32 @test_inf_promote_callee(%S* [[TMP4]], %S* [[TMP2]]) ; ARGPROMOTION-NEXT: ret i32 0 diff --git a/llvm/test/Transforms/ArgumentPromotion/dbg.ll b/llvm/test/Transforms/ArgumentPromotion/dbg.ll --- a/llvm/test/Transforms/ArgumentPromotion/dbg.ll +++ b/llvm/test/Transforms/ArgumentPromotion/dbg.ll @@ -1,14 +1,22 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -argpromotion -S | FileCheck %s --check-prefixes=ARGPROMOTION,ALL ; RUN: opt < %s -passes=argpromotion -S | FileCheck %s --check-prefixes=ARGPROMOTION,ALL +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=2 < %s | FileCheck %s --check-prefixes=ALL,ATTRIBUTOR declare void @sink(i32) define internal void @test(i32** %X) !dbg !2 { ; ARGPROMOTION-LABEL: define {{[^@]+}}@test ; ARGPROMOTION-SAME: (i32 [[X_VAL_VAL:%.*]]) !dbg !3 -; ARGPROMOTION-NEXT: call void @sink(i32 [[X_VAL_VAL]]) +; ARGPROMOTION-NEXT: call void @sink(i32 [[X_VAL_VAL:%.*]]) ; ARGPROMOTION-NEXT: ret void +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test +; ATTRIBUTOR-SAME: (i32** nocapture nonnull readonly dereferenceable(8) [[X:%.*]]) !dbg !3 +; ATTRIBUTOR-NEXT: [[TMP1:%.*]] = load i32*, i32** [[X:%.*]], align 8 +; ATTRIBUTOR-NEXT: [[TMP2:%.*]] = load i32, i32* [[TMP1]], align 8 +; ATTRIBUTOR-NEXT: call void @sink(i32 [[TMP2]]) +; ATTRIBUTOR-NEXT: ret void ; %1 = load i32*, i32** %X, align 8 %2 = load i32, i32* %1, align 8 @@ -23,10 +31,13 @@ ; ARGPROMOTION-SAME: (i32 [[P_0:%.*]], i32 [[P_1:%.*]]) ; ARGPROMOTION-NEXT: [[P:%.*]] = alloca [[STRUCT_PAIR:%.*]] ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[STRUCT_PAIR]], %struct.pair* [[P]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[P_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[P_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[STRUCT_PAIR]], %struct.pair* [[P]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i32 [[P_1]], i32* [[DOT1]] +; ARGPROMOTION-NEXT: store i32 [[P_1:%.*]], i32* [[DOT1]] ; ARGPROMOTION-NEXT: ret void +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test_byval() +; ATTRIBUTOR-NEXT: ret void ; ret void } @@ -34,15 +45,21 @@ define void @caller(i32** %Y, %struct.pair* %P) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@caller ; ARGPROMOTION-SAME: (i32** [[Y:%.*]], %struct.pair* [[P:%.*]]) -; ARGPROMOTION-NEXT: [[Y_VAL:%.*]] = load i32*, i32** [[Y]], align 8, !dbg !4 +; ARGPROMOTION-NEXT: [[Y_VAL:%.*]] = load i32*, i32** [[Y:%.*]], align 8, !dbg !4 ; ARGPROMOTION-NEXT: [[Y_VAL_VAL:%.*]] = load i32, i32* [[Y_VAL]], align 8, !dbg !4 ; ARGPROMOTION-NEXT: call void @test(i32 [[Y_VAL_VAL]]), !dbg !4 -; ARGPROMOTION-NEXT: [[P_0:%.*]] = getelementptr [[STRUCT_PAIR:%.*]], %struct.pair* [[P]], i32 0, i32 0, !dbg !5 +; ARGPROMOTION-NEXT: [[P_0:%.*]] = getelementptr [[STRUCT_PAIR:%.*]], %struct.pair* [[P:%.*]], i32 0, i32 0, !dbg !5 ; ARGPROMOTION-NEXT: [[P_0_VAL:%.*]] = load i32, i32* [[P_0]], !dbg !5 ; ARGPROMOTION-NEXT: [[P_1:%.*]] = getelementptr [[STRUCT_PAIR]], %struct.pair* [[P]], i32 0, i32 1, !dbg !5 ; ARGPROMOTION-NEXT: [[P_1_VAL:%.*]] = load i32, i32* [[P_1]], !dbg !5 ; ARGPROMOTION-NEXT: call void @test_byval(i32 [[P_0_VAL]], i32 [[P_1_VAL]]), !dbg !5 ; ARGPROMOTION-NEXT: ret void +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@caller +; ATTRIBUTOR-SAME: (i32** nocapture readonly [[Y:%.*]], %struct.pair* nocapture readnone [[P:%.*]]) +; ATTRIBUTOR-NEXT: call void @test(i32** nocapture readonly [[Y:%.*]]), !dbg !4 +; ATTRIBUTOR-NEXT: call void @test_byval(), !dbg !5 +; ATTRIBUTOR-NEXT: ret void ; call void @test(i32** %Y), !dbg !1 diff --git a/llvm/test/Transforms/ArgumentPromotion/fp80.ll b/llvm/test/Transforms/ArgumentPromotion/fp80.ll --- a/llvm/test/Transforms/ArgumentPromotion/fp80.ll +++ b/llvm/test/Transforms/ArgumentPromotion/fp80.ll @@ -36,7 +36,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@UseLongDoubleUnsafely ; ARGPROMOTION-SAME: (%union.u* byval align 16 [[ARG:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[BITCAST:%.*]] = bitcast %union.u* [[ARG]] to %struct.s* +; ARGPROMOTION-NEXT: [[BITCAST:%.*]] = bitcast %union.u* [[ARG:%.*]] to %struct.s* ; ARGPROMOTION-NEXT: [[GEP:%.*]] = getelementptr inbounds [[STRUCT_S:%.*]], %struct.s* [[BITCAST]], i64 0, i32 2 ; ARGPROMOTION-NEXT: [[RESULT:%.*]] = load i8, i8* [[GEP]] ; ARGPROMOTION-NEXT: ret i8 [[RESULT]] @@ -53,7 +53,7 @@ ; ARGPROMOTION-SAME: (x86_fp80 [[ARG_0:%.*]]) ; ARGPROMOTION-NEXT: [[ARG:%.*]] = alloca [[UNION_U:%.*]], align 16 ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[UNION_U]], %union.u* [[ARG]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store x86_fp80 [[ARG_0]], x86_fp80* [[DOT0]] +; ARGPROMOTION-NEXT: store x86_fp80 [[ARG_0:%.*]], x86_fp80* [[DOT0]] ; ARGPROMOTION-NEXT: [[GEP:%.*]] = getelementptr inbounds [[UNION_U]], %union.u* [[ARG]], i64 0, i32 0 ; ARGPROMOTION-NEXT: [[FP80:%.*]] = load x86_fp80, x86_fp80* [[GEP]] ; ARGPROMOTION-NEXT: ret x86_fp80 [[FP80]] @@ -66,7 +66,7 @@ define internal i64 @AccessPaddingOfStruct(%struct.Foo* byval %a) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@AccessPaddingOfStruct ; ARGPROMOTION-SAME: (%struct.Foo* byval [[A:%.*]]) -; ARGPROMOTION-NEXT: [[P:%.*]] = bitcast %struct.Foo* [[A]] to i64* +; ARGPROMOTION-NEXT: [[P:%.*]] = bitcast %struct.Foo* [[A:%.*]] to i64* ; ARGPROMOTION-NEXT: [[V:%.*]] = load i64, i64* [[P]] ; ARGPROMOTION-NEXT: ret i64 [[V]] ; @@ -83,7 +83,7 @@ ; ARGPROMOTION-NEXT: br label [[LOOP:%.*]] ; ARGPROMOTION: loop: ; ARGPROMOTION-NEXT: [[PHI:%.*]] = phi %struct.Foo* [ null, [[ENTRY:%.*]] ], [ [[GEP:%.*]], [[LOOP]] ] -; ARGPROMOTION-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ] +; ARGPROMOTION-NEXT: [[TMP0:%.*]] = phi %struct.Foo* [ [[A:%.*]], [[ENTRY]] ], [ [[TMP0]], [[LOOP]] ] ; ARGPROMOTION-NEXT: store %struct.Foo* [[PHI]], %struct.Foo** [[A_PTR]] ; ARGPROMOTION-NEXT: [[GEP]] = getelementptr [[STRUCT_FOO:%.*]], %struct.Foo* [[A]], i64 0 ; ARGPROMOTION-NEXT: br label [[LOOP]] diff --git a/llvm/test/Transforms/ArgumentPromotion/inalloca.ll b/llvm/test/Transforms/ArgumentPromotion/inalloca.ll --- a/llvm/test/Transforms/ArgumentPromotion/inalloca.ll +++ b/llvm/test/Transforms/ArgumentPromotion/inalloca.ll @@ -11,7 +11,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@f ; ARGPROMOTION-SAME: (i32 [[S_0_0_VAL:%.*]], i32 [[S_0_1_VAL:%.*]]) unnamed_addr ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[R:%.*]] = add i32 [[S_0_0_VAL]], [[S_0_1_VAL]] +; ARGPROMOTION-NEXT: [[R:%.*]] = add i32 [[S_0_0_VAL:%.*]], [[S_0_1_VAL:%.*]] ; ARGPROMOTION-NEXT: ret i32 [[R]] ; entry: @@ -44,7 +44,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@g ; ARGPROMOTION-SAME: (%struct.ss* [[A:%.*]], %struct.ss* [[B:%.*]]) unnamed_addr ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[C:%.*]] = icmp eq %struct.ss* [[A]], [[B]] +; ARGPROMOTION-NEXT: [[C:%.*]] = icmp eq %struct.ss* [[A:%.*]], [[B:%.*]] ; ARGPROMOTION-NEXT: ret i1 [[C]] ; entry: diff --git a/llvm/test/Transforms/ArgumentPromotion/invalidation.ll b/llvm/test/Transforms/ArgumentPromotion/invalidation.ll --- a/llvm/test/Transforms/ArgumentPromotion/invalidation.ll +++ b/llvm/test/Transforms/ArgumentPromotion/invalidation.ll @@ -15,7 +15,7 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@a ; ARGPROMOTION-SAME: (i32 [[X_VAL:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: ret i32 [[X_VAL]] +; ARGPROMOTION-NEXT: ret i32 [[X_VAL:%.*]] ; entry: %v = load i32, i32* %x diff --git a/llvm/test/Transforms/ArgumentPromotion/musttail.ll b/llvm/test/Transforms/ArgumentPromotion/musttail.ll --- a/llvm/test/Transforms/ArgumentPromotion/musttail.ll +++ b/llvm/test/Transforms/ArgumentPromotion/musttail.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt < %s -argpromotion -S | FileCheck %s --check-prefixes=ARGPROMOTION,ALL +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=5 < %s | FileCheck %s --check-prefixes=ATTRIBUTOR,ALL ; PR36543 ; Don't promote arguments of musttail callee @@ -9,12 +10,21 @@ define internal i32 @test(%T* %p) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@test ; ARGPROMOTION-SAME: (%T* [[P:%.*]]) -; ARGPROMOTION-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3 +; ARGPROMOTION-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P:%.*]], i64 0, i32 3 ; ARGPROMOTION-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2 ; ARGPROMOTION-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]] ; ARGPROMOTION-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]] ; ARGPROMOTION-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] ; ARGPROMOTION-NEXT: ret i32 [[V]] +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test +; ATTRIBUTOR-SAME: (%T* nocapture readonly [[P:%.*]]) +; ATTRIBUTOR-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P:%.*]], i64 0, i32 3 +; ATTRIBUTOR-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2 +; ATTRIBUTOR-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]] +; ATTRIBUTOR-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]] +; ATTRIBUTOR-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] +; ATTRIBUTOR-NEXT: ret i32 [[V]] ; %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 @@ -27,8 +37,13 @@ define i32 @caller(%T* %p) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@caller ; ARGPROMOTION-SAME: (%T* [[P:%.*]]) -; ARGPROMOTION-NEXT: [[V:%.*]] = musttail call i32 @test(%T* [[P]]) +; ARGPROMOTION-NEXT: [[V:%.*]] = musttail call i32 @test(%T* [[P:%.*]]) ; ARGPROMOTION-NEXT: ret i32 [[V]] +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@caller +; ATTRIBUTOR-SAME: (%T* nocapture readonly [[P:%.*]]) +; ATTRIBUTOR-NEXT: [[V:%.*]] = musttail call i32 @test(%T* nocapture readonly [[P:%.*]]) +; ATTRIBUTOR-NEXT: ret i32 [[V]] ; %v = musttail call i32 @test(%T* %p) ret i32 %v @@ -40,6 +55,10 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@foo ; ARGPROMOTION-SAME: (%T* [[P:%.*]], i32 [[V:%.*]]) ; ARGPROMOTION-NEXT: ret i32 0 +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@foo +; ATTRIBUTOR-SAME: (%T* nocapture readnone [[P:%.*]], i32 [[V:%.*]]) +; ATTRIBUTOR-NEXT: ret i32 0 ; ret i32 0 } @@ -47,13 +66,18 @@ define internal i32 @test2(%T* %p, i32 %p2) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@test2 ; ARGPROMOTION-SAME: (%T* [[P:%.*]], i32 [[P2:%.*]]) -; ARGPROMOTION-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P]], i64 0, i32 3 +; ARGPROMOTION-NEXT: [[A_GEP:%.*]] = getelementptr [[T:%.*]], %T* [[P:%.*]], i64 0, i32 3 ; ARGPROMOTION-NEXT: [[B_GEP:%.*]] = getelementptr [[T]], %T* [[P]], i64 0, i32 2 ; ARGPROMOTION-NEXT: [[A:%.*]] = load i32, i32* [[A_GEP]] ; ARGPROMOTION-NEXT: [[B:%.*]] = load i32, i32* [[B_GEP]] ; ARGPROMOTION-NEXT: [[V:%.*]] = add i32 [[A]], [[B]] ; ARGPROMOTION-NEXT: [[CA:%.*]] = musttail call i32 @foo(%T* undef, i32 [[V]]) ; ARGPROMOTION-NEXT: ret i32 [[CA]] +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@test2 +; ATTRIBUTOR-SAME: (%T* nocapture readonly [[P:%.*]], i32 [[P2:%.*]]) +; ATTRIBUTOR-NEXT: [[CA:%.*]] = musttail call i32 @foo(%T* undef, i32 undef) +; ATTRIBUTOR-NEXT: ret i32 [[CA]] ; %a.gep = getelementptr %T, %T* %p, i64 0, i32 3 %b.gep = getelementptr %T, %T* %p, i64 0, i32 2 @@ -67,8 +91,13 @@ define i32 @caller2(%T* %g) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@caller2 ; ARGPROMOTION-SAME: (%T* [[G:%.*]]) -; ARGPROMOTION-NEXT: [[V:%.*]] = call i32 @test2(%T* [[G]], i32 0) +; ARGPROMOTION-NEXT: [[V:%.*]] = call i32 @test2(%T* [[G:%.*]], i32 0) ; ARGPROMOTION-NEXT: ret i32 [[V]] +; +; ATTRIBUTOR-LABEL: define {{[^@]+}}@caller2 +; ATTRIBUTOR-SAME: (%T* nocapture readonly [[G:%.*]]) +; ATTRIBUTOR-NEXT: [[V:%.*]] = call i32 @test2(%T* nocapture readonly undef, i32 undef) +; ATTRIBUTOR-NEXT: ret i32 0 ; %v = call i32 @test2(%T* %g, i32 0) ret i32 %v diff --git a/llvm/test/Transforms/ArgumentPromotion/pr32917.ll b/llvm/test/Transforms/ArgumentPromotion/pr32917.ll --- a/llvm/test/Transforms/ArgumentPromotion/pr32917.ll +++ b/llvm/test/Transforms/ArgumentPromotion/pr32917.ll @@ -25,7 +25,7 @@ define internal fastcc void @fn1(i32* nocapture readonly) unnamed_addr { ; ARGPROMOTION-LABEL: define {{[^@]+}}@fn1 ; ARGPROMOTION-SAME: (i32 [[DOT18446744073709551615_VAL:%.*]]) unnamed_addr -; ARGPROMOTION-NEXT: store i32 [[DOT18446744073709551615_VAL]], i32* @a, align 4 +; ARGPROMOTION-NEXT: store i32 [[DOT18446744073709551615_VAL:%.*]], i32* @a, align 4 ; ARGPROMOTION-NEXT: ret void ; %2 = getelementptr inbounds i32, i32* %0, i64 -1 diff --git a/llvm/test/Transforms/ArgumentPromotion/profile.ll b/llvm/test/Transforms/ArgumentPromotion/profile.ll --- a/llvm/test/Transforms/ArgumentPromotion/profile.ll +++ b/llvm/test/Transforms/ArgumentPromotion/profile.ll @@ -18,7 +18,7 @@ define internal void @promote_i32_ptr(i32* %xp) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@promote_i32_ptr ; ARGPROMOTION-SAME: (i32 [[XP_VAL:%.*]]) -; ARGPROMOTION-NEXT: call void @use_i32(i32 [[XP_VAL]]) +; ARGPROMOTION-NEXT: call void @use_i32(i32 [[XP_VAL:%.*]]) ; ARGPROMOTION-NEXT: ret void ; %x = load i32, i32* %xp diff --git a/llvm/test/Transforms/ArgumentPromotion/reserve-tbaa.ll b/llvm/test/Transforms/ArgumentPromotion/reserve-tbaa.ll --- a/llvm/test/Transforms/ArgumentPromotion/reserve-tbaa.ll +++ b/llvm/test/Transforms/ArgumentPromotion/reserve-tbaa.ll @@ -18,8 +18,8 @@ ; ARGPROMOTION-LABEL: define {{[^@]+}}@fn ; ARGPROMOTION-SAME: (i32 [[P1_VAL:%.*]], i64 [[P2_VAL:%.*]]) ; ARGPROMOTION-NEXT: entry: -; ARGPROMOTION-NEXT: [[CONV:%.*]] = trunc i64 [[P2_VAL]] to i32 -; ARGPROMOTION-NEXT: [[CONV1:%.*]] = trunc i32 [[P1_VAL]] to i8 +; ARGPROMOTION-NEXT: [[CONV:%.*]] = trunc i64 [[P2_VAL:%.*]] to i32 +; ARGPROMOTION-NEXT: [[CONV1:%.*]] = trunc i32 [[P1_VAL:%.*]] to i8 ; ARGPROMOTION-NEXT: store i8 [[CONV1]], i8* @d, align 1, !tbaa !0 ; ARGPROMOTION-NEXT: ret void ; diff --git a/llvm/test/Transforms/ArgumentPromotion/sret.ll b/llvm/test/Transforms/ArgumentPromotion/sret.ll --- a/llvm/test/Transforms/ArgumentPromotion/sret.ll +++ b/llvm/test/Transforms/ArgumentPromotion/sret.ll @@ -8,8 +8,8 @@ define internal void @add({i32, i32}* %this, i32* sret %r) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@add ; ARGPROMOTION-SAME: (i32 [[THIS_0_0_VAL:%.*]], i32 [[THIS_0_1_VAL:%.*]], i32* noalias [[R:%.*]]) -; ARGPROMOTION-NEXT: [[AB:%.*]] = add i32 [[THIS_0_0_VAL]], [[THIS_0_1_VAL]] -; ARGPROMOTION-NEXT: store i32 [[AB]], i32* [[R]] +; ARGPROMOTION-NEXT: [[AB:%.*]] = add i32 [[THIS_0_0_VAL:%.*]], [[THIS_0_1_VAL:%.*]] +; ARGPROMOTION-NEXT: store i32 [[AB]], i32* [[R:%.*]] ; ARGPROMOTION-NEXT: ret void ; %ap = getelementptr {i32, i32}, {i32, i32}* %this, i32 0, i32 0 diff --git a/llvm/test/Transforms/ArgumentPromotion/tail.ll b/llvm/test/Transforms/ArgumentPromotion/tail.ll --- a/llvm/test/Transforms/ArgumentPromotion/tail.ll +++ b/llvm/test/Transforms/ArgumentPromotion/tail.ll @@ -14,9 +14,9 @@ ; ARGPROMOTION-SAME: (i32 [[DATA_0:%.*]], i32 [[DATA_1:%.*]]) ; ARGPROMOTION-NEXT: [[DATA:%.*]] = alloca [[PAIR:%.*]] ; ARGPROMOTION-NEXT: [[DOT0:%.*]] = getelementptr [[PAIR]], %pair* [[DATA]], i32 0, i32 0 -; ARGPROMOTION-NEXT: store i32 [[DATA_0]], i32* [[DOT0]] +; ARGPROMOTION-NEXT: store i32 [[DATA_0:%.*]], i32* [[DOT0]] ; ARGPROMOTION-NEXT: [[DOT1:%.*]] = getelementptr [[PAIR]], %pair* [[DATA]], i32 0, i32 1 -; ARGPROMOTION-NEXT: store i32 [[DATA_1]], i32* [[DOT1]] +; ARGPROMOTION-NEXT: store i32 [[DATA_1:%.*]], i32* [[DOT1]] ; ARGPROMOTION-NEXT: [[TMP1:%.*]] = call i8* @foo(%pair* [[DATA]]) ; ARGPROMOTION-NEXT: ret void ; @@ -27,7 +27,7 @@ define void @zed(%pair* byval %Data) { ; ARGPROMOTION-LABEL: define {{[^@]+}}@zed ; ARGPROMOTION-SAME: (%pair* byval [[DATA:%.*]]) -; ARGPROMOTION-NEXT: [[DATA_0:%.*]] = getelementptr [[PAIR:%.*]], %pair* [[DATA]], i32 0, i32 0 +; ARGPROMOTION-NEXT: [[DATA_0:%.*]] = getelementptr [[PAIR:%.*]], %pair* [[DATA:%.*]], i32 0, i32 0 ; ARGPROMOTION-NEXT: [[DATA_0_VAL:%.*]] = load i32, i32* [[DATA_0]] ; ARGPROMOTION-NEXT: [[DATA_1:%.*]] = getelementptr [[PAIR]], %pair* [[DATA]], i32 0, i32 1 ; ARGPROMOTION-NEXT: [[DATA_1_VAL:%.*]] = load i32, i32* [[DATA_1]] diff --git a/llvm/test/Transforms/FunctionAttrs/liveness.ll b/llvm/test/Transforms/FunctionAttrs/liveness.ll --- a/llvm/test/Transforms/FunctionAttrs/liveness.ll +++ b/llvm/test/Transforms/FunctionAttrs/liveness.ll @@ -716,14 +716,14 @@ ret void } -; CHECK: define internal void @useless_arg_sink(i32* nocapture readnone %a) +; CHECK: define internal void @useless_arg_sink() define internal void @useless_arg_sink(i32* %a) { ret void } -; CHECK: define internal void @useless_arg_almost_sink(i32* nocapture readnone %a) +; CHECK: define internal void @useless_arg_almost_sink() define internal void @useless_arg_almost_sink(i32* %a) { -; CHECK: call void @useless_arg_sink(i32* undef) +; CHECK: call void @useless_arg_sink() call void @useless_arg_sink(i32* %a) ret void } @@ -731,7 +731,7 @@ ; Check we do not annotate the function interface of this weak function. ; CHECK: define weak_odr void @useless_arg_ext(i32* %a) define weak_odr void @useless_arg_ext(i32* %a) { -; CHECK: call void @useless_arg_almost_sink(i32* undef) +; CHECK: call void @useless_arg_almost_sink() call void @useless_arg_almost_sink(i32* %a) ret void } diff --git a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll --- a/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll +++ b/llvm/test/Transforms/FunctionAttrs/noalias_returned.ll @@ -1,4 +1,4 @@ -; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=3 < %s | FileCheck %s +; RUN: opt -S -passes=attributor -aa-pipeline='basic-aa' -attributor-disable=false -attributor-max-iterations-verify -attributor-max-iterations=4 < %s | FileCheck %s ; TEST 1 - negative. @@ -152,13 +152,27 @@ ; TEST 9 ; Simple Argument Test -define internal void @test9(i8* %a, i8* %b) { -; CHECK: define internal void @test9(i8* noalias nocapture readnone %a, i8* nocapture readnone %b) +declare void @use_i8(i8* nocapture) readnone +define internal void @test9a(i8* %a, i8* %b) { +; CHECK: define internal void @test9a() + ret void +} +define internal void @test9b(i8* %a, i8* %b) { +; CHECK: define internal void @test9b(i8* noalias nocapture readnone %a, i8* nocapture readnone %b) + call void @use_i8(i8* %a) + call void @use_i8(i8* %b) ret void } define void @test9_helper(i8* %a, i8* %b) { - tail call void @test9(i8* noalias %a, i8* %b) - tail call void @test9(i8* noalias %b, i8* noalias %a) +; CHECK: define void @test9_helper(i8* nocapture readnone %a, i8* nocapture readnone %b) +; CHECK: tail call void @test9a() +; CHECK: tail call void @test9a() +; CHECK: tail call void @test9b(i8* noalias nocapture %a, i8* nocapture %b) +; CHECK: tail call void @test9b(i8* noalias nocapture %b, i8* noalias nocapture %a) + tail call void @test9a(i8* noalias %a, i8* %b) + tail call void @test9a(i8* noalias %b, i8* noalias %a) + tail call void @test9b(i8* noalias %a, i8* %b) + tail call void @test9b(i8* noalias %b, i8* noalias %a) ret void } diff --git a/llvm/test/Transforms/FunctionAttrs/nonnull.ll b/llvm/test/Transforms/FunctionAttrs/nonnull.ll --- a/llvm/test/Transforms/FunctionAttrs/nonnull.ll +++ b/llvm/test/Transforms/FunctionAttrs/nonnull.ll @@ -173,8 +173,12 @@ tail call void @test13(i8* %nonnullptr, i8* %maybenullptr, i8* %nonnullptr) ret void } +declare void @user_i8_ptr(i8*) readnone nounwind define internal void @test13(i8* %a, i8* %b, i8* %c) { ; ATTRIBUTOR: define internal void @test13(i8* nocapture nonnull readnone %a, i8* nocapture readnone %b, i8* nocapture readnone %c) + call void @user_i8_ptr(i8* %a) + call void @user_i8_ptr(i8* %b) + call void @user_i8_ptr(i8* %c) ret void }