Index: llvm/lib/Analysis/IRSimilarityIdentifier.cpp =================================================================== --- llvm/lib/Analysis/IRSimilarityIdentifier.cpp +++ llvm/lib/Analysis/IRSimilarityIdentifier.cpp @@ -43,6 +43,11 @@ cl::opt DisableIntrinsics("no-ir-sim-intrinsics", cl::init(false), cl::ReallyHidden, cl::desc("Don't match or outline intrinsics")); + +cl::opt DisableMustTailCalls( + "no-ir-musttail", cl::init(false), cl::ReallyHidden, + cl::desc("Don't match or outline any musttail functions")); + } // namespace llvm IRInstructionData::IRInstructionData(Instruction &I, bool Legality, @@ -1200,7 +1205,7 @@ bool IRSimilarityIdentifierWrapperPass::doInitialization(Module &M) { IRSI.reset(new IRSimilarityIdentifier(!DisableBranches, !DisableIndirectCalls, MatchCallsByName, !DisableIntrinsics, - false)); + !DisableMustTailCalls)); return false; } @@ -1219,7 +1224,7 @@ ModuleAnalysisManager &) { auto IRSI = IRSimilarityIdentifier(!DisableBranches, !DisableIndirectCalls, MatchCallsByName, !DisableIntrinsics, - false); + !DisableMustTailCalls); IRSI.findSimilarity(M); return IRSI; } Index: llvm/lib/Transforms/IPO/IROutliner.cpp =================================================================== --- llvm/lib/Transforms/IPO/IROutliner.cpp +++ llvm/lib/Transforms/IPO/IROutliner.cpp @@ -32,6 +32,7 @@ #define DEBUG_TYPE "iroutliner" using namespace llvm; +using namespace CallingConv; using namespace IRSimilarity; // A command flag to be used for debugging to exclude branches from similarity @@ -47,6 +48,10 @@ // matching and outlining. extern cl::opt DisableIntrinsics; +// A command flag to be used for debugging to exclude intrinsics from similarity +// matching and outlining. +extern cl::opt DisableMustTailCalls; + } // namespace llvm // Set to true if the user wants the ir outliner to run on linkonceodr linkage @@ -136,6 +141,14 @@ /// needed, there is no value. Optional SwiftErrorArgument; + /// The boolean to track whether the group is outlining a SwiftTail calling + /// convention function. + Optional HasTailCC; + + /// The boolean to track whether the group is outlining a musttail marked + /// function. + bool ContainsMustTailCall = false; + /// For the \ref Regions, we look at every Value. If it is a constant, /// we check whether it is the same in Region. /// @@ -601,6 +614,11 @@ Group.OutlinedFunction->addParamAttr(Group.SwiftErrorArgument.getValue(), Attribute::SwiftError); + // Transfer the SwiftTail calling convention if relevant for the outlined + // code. + if (Group.HasTailCC.hasValue()) + Group.OutlinedFunction->setCallingConv(*Group.HasTailCC); + Group.OutlinedFunction->addFnAttr(Attribute::OptimizeForSize); Group.OutlinedFunction->addFnAttr(Attribute::MinSize); @@ -2049,7 +2067,7 @@ if (OutputStoreBBs.size() == 1) { LLVM_DEBUG(dbgs() << "Move store instructions to the end block in " << *OG.OutlinedFunction << "\n"); - DenseMap OutputBlocks = OutputStoreBBs[0]; + DenseMap &OutputBlocks = OutputStoreBBs[0]; for (std::pair &VBPair : OutputBlocks) { DenseMap::iterator EndBBIt = EndBBs.find(VBPair.first); @@ -2063,7 +2081,42 @@ Term->moveBefore(*EndBB, EndBB->end()); OutputBB->eraseFromParent(); } + return; + } + + // If there are no End Blocks, then we have no return instructions to compress + // and no other exits. We can simply return without having done anything. + if (EndBBs.size() == 0) + return; + + // At this point, we have no outputs to handle, and only one exit but we still + // branch unnecessarily to a different block. So we eliminate this branch to + // the final block and move it into it's predecessors. + + // This is not only an optimization, but necessary in the case where we are + // outlining a tail called function, as it still must remain the final + // operation, excluding the return in the function. + DenseMap::iterator EndBBIt = EndBBs.begin(); + BasicBlock *EndBB = EndBBIt->second; + Instruction *RI = EndBB->getTerminator(); + Instruction *RIDup; + Instruction *Term; + SmallVector TermsToErase; + bool AllWereCompressed = true; + for (BasicBlock *Pred : predecessors(EndBB)) { + if (!Pred->getUniqueSuccessor()) { + AllWereCompressed = false; + continue; + } + Term = Pred->getTerminator(); + TermsToErase.push_back(Term); + RIDup = RI->clone(); + RIDup->insertAfter(&Pred->back()); } + for (Instruction *Term : TermsToErase) + Term->eraseFromParent(); + if (AllWereCompressed) + EndBB->eraseFromParent(); } /// Fill the new function that will serve as the replacement function for all of @@ -2161,6 +2214,16 @@ FuncsToRemove.push_back(CurrentOS->ExtractedFunction); } + for (OutlinableRegion *Region : CurrentGroup.Regions) { + // Make sure that the calling convention for SwiftTail is set. + if (CurrentGroup.HasTailCC.hasValue()) + Region->Call->setCallingConv(*CurrentGroup.HasTailCC); + + // Make sure that the calling convention for SwiftTail is set. + if (CurrentGroup.ContainsMustTailCall) + Region->Call->setTailCallKind(CallInst::TailCallKind::TCK_MustTail); + } + // Create a switch statement to handle the different output schemes. createSwitchStatement(M, CurrentGroup, CurrentGroup.EndBBs, OutputStoreBBs); @@ -2371,24 +2434,18 @@ return OverallCost; } -/// Find the extra instructions needed to handle any output values for the -/// region. +/// Determine how many different exit paths exists for a region in the \ref +/// OutlinableGroup \param CurrentGroup. This is done by chekcing how many +/// branches target BasicBlocks outside of the region. /// -/// \param [in] M - The Module to outline from. -/// \param [in] CurrentGroup - The collection of OutlinableRegions to analyze. -/// \param [in] TTI - The TargetTransformInfo used to collect information for -/// new instruction costs. -/// \returns the additional cost to handle the outputs. -static InstructionCost findCostForOutputBlocks(Module &M, - OutlinableGroup &CurrentGroup, - TargetTransformInfo &TTI) { - InstructionCost OutputCost = 0; - unsigned NumOutputBranches = 0; - - OutlinableRegion &FirstRegion = *CurrentGroup.Regions[0]; - IRSimilarityCandidate &Candidate = *CurrentGroup.Regions[0]->Candidate; +/// +/// \param CurrentGroup - The region whose blocks to analyze. +/// \returns the number of exit paths from the region. +static unsigned findNumberOutputBranches(OutlinableRegion &Region) { + IRSimilarityCandidate &Candidate = *Region.Candidate; DenseSet CandidateBlocks; Candidate.getBasicBlocks(CandidateBlocks); + unsigned NumOutputBranches = 0; // Count the number of different output branches that point to blocks outside // of the region. @@ -2407,7 +2464,24 @@ } } - CurrentGroup.BranchesToOutside = NumOutputBranches; + return NumOutputBranches; +} + +/// Find the extra instructions needed to handle any output values for the +/// region. +/// +/// \param [in] M - The Module to outline from. +/// \param [in] CurrentGroup - The collection of OutlinableRegions to analyze. +/// \param [in] TTI - The TargetTransformInfo used to collect information for +/// new instruction costs. +/// \returns the additional cost to handle the outputs. +static InstructionCost findCostForOutputBlocks(Module &M, + OutlinableGroup &CurrentGroup, + TargetTransformInfo &TTI) { + InstructionCost OutputCost = 0; + unsigned NumOutputBranches = CurrentGroup.BranchesToOutside; + + OutlinableRegion &FirstRegion = *CurrentGroup.Regions[0]; for (const ArrayRef &OutputUse : CurrentGroup.OutputGVNCombinations) { @@ -2615,6 +2689,7 @@ InstructionClassifier.EnableBranches = !DisableBranches; InstructionClassifier.EnableIndirectCalls = !DisableIndirectCalls; InstructionClassifier.EnableIntrinsics = !DisableIntrinsics; + InstructionClassifier.EnableMustTailCalls = !DisableMustTailCalls; IRSimilarityIdentifier &Identifier = getIRSI(M); SimilarityGroupList &SimilarityCandidates = *Identifier.getSimilarity(); @@ -2642,6 +2717,38 @@ for (SimilarityGroup &CandidateVec : SimilarityCandidates) { OutlinableGroup &CurrentGroup = PotentialGroups[PotentialGroupIdx++]; + // We check if any call instruction in the set contains a swifttailcc + // or tailcc calling convention function. If it does, we indicate it in the + // OutlinableGroup. + bool HasATailCC = + any_of(CandidateVec[0], [](IRInstructionData &ID) { + CallInst *CI = dyn_cast(ID.Inst); + if (!CI) + return false; + + if(CI->getCallingConv() == CallingConv::SwiftTail || + CI->getCallingConv() == CallingConv::Tail) + return true; + + return false; + }); + + if (HasATailCC) + CurrentGroup.HasTailCC = + CandidateVec[0].frontInstruction()->getFunction()->getCallingConv(); + + // We check if any call instruction in the set contains a musttail + // function attribute. If it does, we inidicate it in the group, as any + // outlined function must also be marked with this attribute. + CurrentGroup.ContainsMustTailCall = + any_of(CandidateVec[0], [](IRInstructionData &ID) { + CallInst *CI = dyn_cast(ID.Inst); + if (!CI) + return false; + + return CI->isMustTailCall(); + }); + // Remove entries that were previously outlined pruneIncompatibleRegions(CandidateVec, CurrentGroup); @@ -2696,6 +2803,20 @@ CurrentGroup.collectGVNStoreSets(M); + // If we are outlining a function that contains a tail call, we must + // ensure that there is only one exit from the outlined region. If there is + // not, this means that there will be instructions that need to be executed + // after the outlined function resolves to handle the different exit paths. + + // As a result, we disregard groups containing a tail call, but contain + // multiple exits. + CurrentGroup.BranchesToOutside = + findNumberOutputBranches(*CurrentGroup.Regions[0]); + if (CurrentGroup.BranchesToOutside > 1 && + (CurrentGroup.HasTailCC.hasValue() || + CurrentGroup.ContainsMustTailCall)) + continue; + if (CostModel) findCostBenefit(M, CurrentGroup); Index: llvm/test/Transforms/IROutliner/included-phi-nodes-begin.ll =================================================================== --- llvm/test/Transforms/IROutliner/included-phi-nodes-begin.ll +++ llvm/test/Transforms/IROutliner/included-phi-nodes-begin.ll @@ -76,7 +76,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[TEST1_TO_OUTLINE:%.*]] ; CHECK: test1_to_outline: @@ -87,7 +87,5 @@ ; CHECK-NEXT: br i1 true, label [[TEST:%.*]], label [[TEST1_TO_OUTLINE]] ; CHECK: test: ; CHECK-NEXT: [[D:%.*]] = load i32, i32* [[TMP1]], align 4 -; CHECK-NEXT: br label [[FIRST_EXITSTUB:%.*]] -; CHECK: first.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/included-phi-nodes-end.ll =================================================================== --- llvm/test/Transforms/IROutliner/included-phi-nodes-end.ll +++ llvm/test/Transforms/IROutliner/included-phi-nodes-end.ll @@ -71,7 +71,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal i1 @outlined_ir_func_0( +; CHECK-LABEL: define internal i1 @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: Index: llvm/test/Transforms/IROutliner/legal-debug.ll =================================================================== --- llvm/test/Transforms/IROutliner/legal-debug.ll +++ llvm/test/Transforms/IROutliner/legal-debug.ll @@ -123,13 +123,15 @@ ; CHECK-NEXT: ret void, !dbg [[DBG34:![0-9]+]] ; ; -; CHECK: @outlined_ir_func_0(i32* [[TMP0:%.*]], i32* [[TMP1:%.*]], i32* [[TMP2:%.*]]) +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: -; CHECK-NEXT: store i32 2, i32* [[TMP0]], align 4 -; CHECK-NEXT: store i32 3, i32* [[TMP1]], align 4 -; CHECK-NEXT: store i32 4, i32* [[TMP2]], align 4 +; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4 +; CHECK-NEXT: store i32 3, i32* [[TMP1:%.*]], align 4 +; CHECK-NEXT: store i32 4, i32* [[TMP2:%.*]], align 4 ; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4 ; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] +; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/legal-indirect-calls.ll =================================================================== --- llvm/test/Transforms/IROutliner/legal-indirect-calls.ll +++ llvm/test/Transforms/IROutliner/legal-indirect-calls.ll @@ -54,7 +54,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: @@ -65,7 +65,5 @@ ; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4 ; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/mismatched-phi-outputs-ordering.ll =================================================================== --- llvm/test/Transforms/IROutliner/mismatched-phi-outputs-ordering.ll +++ llvm/test/Transforms/IROutliner/mismatched-phi-outputs-ordering.ll @@ -138,13 +138,11 @@ ; CHECK-NEXT: ret i1 true ; ; -; CHECK-LABEL: @outlined_ir_func_1( +; CHECK-LABEL: define internal void @outlined_ir_func_1( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[NEXT_TO_OUTLINE:%.*]] ; CHECK: next_to_outline: ; CHECK-NEXT: [[TMP2:%.*]] = add i32 [[TMP0:%.*]], 1 ; CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP1:%.*]], 1 -; CHECK-NEXT: br label [[NEXT_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: next_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/no-outlining-swifttailcc.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/IROutliner/no-outlining-swifttailcc.ll @@ -0,0 +1,34 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs +; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost -no-ir-musttail < %s | FileCheck %s + +; Check that we do not outline musttail calls when swifttailcc is present +; if specified on the command line. + +declare swifttailcc void @musttail() + +define swifttailcc void @f1() { + %a = alloca i32, align 4 + store i32 2, i32* %a, align 4 + musttail call swifttailcc void @musttail() + ret void +} + +define swifttailcc void @f2() { + %a = alloca i32, align 4 + store i32 2, i32* %a, align 4 + musttail call swifttailcc void @musttail() + ret void +} +; CHECK-LABEL: @f1( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 2, i32* [[A]], align 4 +; CHECK-NEXT: musttail call swifttailcc void @musttail() +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @f2( +; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 +; CHECK-NEXT: store i32 2, i32* [[A]], align 4 +; CHECK-NEXT: musttail call swifttailcc void @musttail() +; CHECK-NEXT: ret void +; Index: llvm/test/Transforms/IROutliner/outline-memset.ll =================================================================== --- llvm/test/Transforms/IROutliner/outline-memset.ll +++ llvm/test/Transforms/IROutliner/outline-memset.ll @@ -40,7 +40,7 @@ ; CHECK-NEXT: ret i64 0 ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: @@ -49,7 +49,5 @@ ; CHECK-NEXT: [[CMP3:%.*]] = icmp eq i64 [[TMP1:%.*]], 0 ; CHECK-NEXT: [[A:%.*]] = add i64 [[TMP2:%.*]], [[TMP3:%.*]] ; CHECK-NEXT: [[C:%.*]] = add i64 [[TMP2]], [[TMP3]] -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outline-vaarg-intrinsic.ll =================================================================== --- llvm/test/Transforms/IROutliner/outline-vaarg-intrinsic.ll +++ llvm/test/Transforms/IROutliner/outline-vaarg-intrinsic.ll @@ -77,14 +77,12 @@ ; CHECK-NEXT: ret i32 [[TMP]] ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: ; CHECK-NEXT: call void @llvm.va_copy(i8* [[TMP0:%.*]], i8* [[TMP1:%.*]]) ; CHECK-NEXT: call void @llvm.va_end(i8* [[TMP1]]) ; CHECK-NEXT: store i32 [[TMP2:%.*]], i32* [[TMP3:%.*]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-across-branch.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-across-branch.ll +++ llvm/test/Transforms/IROutliner/outlining-across-branch.ll @@ -61,8 +61,8 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_0( -; CHECK: newFuncRoot: +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: ; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4 @@ -71,7 +71,5 @@ ; CHECK: next: ; CHECK-NEXT: store i32 2, i32* [[TMP2:%.*]], align 4 ; CHECK-NEXT: store i32 3, i32* [[TMP3:%.*]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-basic-branches.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-basic-branches.ll +++ llvm/test/Transforms/IROutliner/outlining-basic-branches.ll @@ -40,13 +40,11 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_0( -; CHECK: newFuncRoot: +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[NEXT_TO_OUTLINE:%.*]] ; CHECK: next_to_outline: ; CHECK-NEXT: br label [[NEXT2:%.*]] ; CHECK: next2: -; CHECK-NEXT: br label [[NEXT_EXITSTUB:%.*]] -; CHECK: next.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-bitcasts.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-bitcasts.ll +++ llvm/test/Transforms/IROutliner/outlining-bitcasts.ll @@ -116,7 +116,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK-LABEL: @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: @@ -127,6 +127,5 @@ ; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4 ; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void +; Index: llvm/test/Transforms/IROutliner/outlining-call-and-indirect.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-call-and-indirect.ll +++ llvm/test/Transforms/IROutliner/outlining-call-and-indirect.ll @@ -64,7 +64,5 @@ ; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4 ; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-calls.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-calls.ll +++ llvm/test/Transforms/IROutliner/outlining-calls.ll @@ -90,7 +90,5 @@ ; CHECK-NEXT: [[AL:%.*]] = load i32, i32* [[TMP0]], align 4 ; CHECK-NEXT: [[BL:%.*]] = load i32, i32* [[TMP1]], align 4 ; CHECK-NEXT: [[CL:%.*]] = load i32, i32* [[TMP2]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-commutative-operands-opposite-order.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-commutative-operands-opposite-order.ll +++ llvm/test/Transforms/IROutliner/outlining-commutative-operands-opposite-order.ll @@ -31,10 +31,15 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: @outlined_ir_func_0(i32 [[TMP0:%.*]], i32 [[TMP1:%.*]], i32 [[TMP2:%.*]]) +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: -; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP0]], [[TMP1]] -; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i32 [[TMP1]], [[TMP2]] +; CHECK-NEXT: [[TMP3:%.*]] = add nsw i32 [[TMP0:%.*]], [[TMP1:%.*]] +; CHECK-NEXT: [[TMP4:%.*]] = sub nsw i32 [[TMP1]], [[TMP2:%.*]] ; CHECK-NEXT: [[TMP5:%.*]] = sub nsw i32 [[TMP0]], [[TMP2]] -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] +; CHECK-NEXT: ret void ; +;. +; CHECK: attributes #[[ATTR0:[0-9]+]] = { minsize optsize } +;. Index: llvm/test/Transforms/IROutliner/outlining-swift-error.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-swift-error.ll +++ llvm/test/Transforms/IROutliner/outlining-swift-error.ll @@ -1,15 +1,9 @@ -; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --include-generated-funcs ; RUN: opt -S -verify -iroutliner -ir-outlining-no-cost < %s | FileCheck %s %swift.error = type opaque define void @outlining_swifterror1(%swift.error** swifterror %err) { -; CHECK-LABEL: @outlining_swifterror1( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[X:%.*]] = alloca i64, align 8 -; CHECK-NEXT: call void @outlined_ir_func_0(i64 5, i64* [[X]], %swift.error** swifterror [[ERR:%.*]]) -; CHECK-NEXT: ret void -; entry: %x = alloca i64 %0 = mul i64 5, 5 @@ -21,12 +15,6 @@ } define void @outlining_swifterror2(%swift.error** swifterror %err) { -; CHECK-LABEL: @outlining_swifterror2( -; CHECK-NEXT: entry: -; CHECK-NEXT: [[X:%.*]] = alloca i64, align 8 -; CHECK-NEXT: call void @outlined_ir_func_0(i64 3, i64* [[X]], %swift.error** swifterror [[ERR:%.*]]) -; CHECK-NEXT: ret void -; entry: %x = alloca i64 %0 = mul i64 3, 3 @@ -37,11 +25,28 @@ ret void } -; CHECK: define internal void @outlined_ir_func_0(i64 [[ARG0:%.*]], i64* [[ARG1:%.*]], %swift.error** swifterror [[ARG2:%.*]]) -; CHECK: entry_to_outline: -; CHECK-NEXT: [[TMP0:%.*]] = mul i64 [[ARG0]], [[ARG0]] -; CHECK-NEXT: [[TMP1:%.*]] = add i64 [[TMP0]], [[TMP0]] -; CHECK-NEXT: store i64 [[TMP1]], i64* [[ARG1]], align 4 -; CHECK-NEXT: %casted = bitcast i64* [[ARG1]] to %swift.error* -; CHECK-NEXT: store %swift.error* %casted, %swift.error** [[ARG2]], align 8 -; CHECK-NEXT: br label %entry_after_outline.exitStub +; CHECK-LABEL: @outlining_swifterror1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X:%.*]] = alloca i64, align 8 +; CHECK-NEXT: call void @outlined_ir_func_0(i64 5, i64* [[X]], %swift.error** swifterror [[ERR:%.*]]) +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: @outlining_swifterror2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[X:%.*]] = alloca i64, align 8 +; CHECK-NEXT: call void @outlined_ir_func_0(i64 3, i64* [[X]], %swift.error** swifterror [[ERR:%.*]]) +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: define internal void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] +; CHECK: entry_to_outline: +; CHECK-NEXT: [[TMP3:%.*]] = mul i64 [[TMP0:%.*]], [[TMP0]] +; CHECK-NEXT: [[TMP4:%.*]] = add i64 [[TMP3]], [[TMP3]] +; CHECK-NEXT: store i64 [[TMP4]], i64* [[TMP1:%.*]], align 4 +; CHECK-NEXT: [[CASTED:%.*]] = bitcast i64* [[TMP1]] to %swift.error* +; CHECK-NEXT: store %swift.error* [[CASTED]], %swift.error** [[TMP2:%.*]], align 8 +; CHECK-NEXT: ret void +; Index: llvm/test/Transforms/IROutliner/outlining-swifttailcc.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-swifttailcc.ll +++ llvm/test/Transforms/IROutliner/outlining-swifttailcc.ll @@ -20,14 +20,21 @@ } ; CHECK-LABEL: @f1( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 -; CHECK-NEXT: musttail call swifttailcc void @musttail() +; CHECK-NEXT: musttail call swifttailcc void @outlined_ir_func_0(i32* [[A]]) ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: @f2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 +; CHECK-NEXT: musttail call swifttailcc void @outlined_ir_func_0(i32* [[A]]) +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: define internal swifttailcc void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[_TO_OUTLINE:%.*]] +; CHECK: _to_outline: +; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4 ; CHECK-NEXT: musttail call swifttailcc void @musttail() ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/outlining-tailcc.ll =================================================================== --- llvm/test/Transforms/IROutliner/outlining-tailcc.ll +++ llvm/test/Transforms/IROutliner/outlining-tailcc.ll @@ -20,14 +20,21 @@ } ; CHECK-LABEL: @f1( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 -; CHECK-NEXT: musttail call tailcc void @musttail() +; CHECK-NEXT: musttail call tailcc void @outlined_ir_func_0(i32* [[A]]) ; CHECK-NEXT: ret void ; ; ; CHECK-LABEL: @f2( ; CHECK-NEXT: [[A:%.*]] = alloca i32, align 4 -; CHECK-NEXT: store i32 2, i32* [[A]], align 4 +; CHECK-NEXT: musttail call tailcc void @outlined_ir_func_0(i32* [[A]]) +; CHECK-NEXT: ret void +; +; +; CHECK-LABEL: define internal tailcc void @outlined_ir_func_0( +; CHECK-NEXT: newFuncRoot: +; CHECK-NEXT: br label [[_TO_OUTLINE:%.*]] +; CHECK: _to_outline: +; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4 ; CHECK-NEXT: musttail call tailcc void @musttail() ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/phi-nodes-non-constant.ll =================================================================== --- llvm/test/Transforms/IROutliner/phi-nodes-non-constant.ll +++ llvm/test/Transforms/IROutliner/phi-nodes-non-constant.ll @@ -52,7 +52,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: @@ -68,7 +68,5 @@ ; CHECK-NEXT: [[TMP3:%.*]] = phi i32 [ [[C]], [[TEST:%.*]] ], [ [[E]], [[TEST1]] ] ; CHECK-NEXT: store i32 2, i32* [[TMP1:%.*]], align 4 ; CHECK-NEXT: store i32 3, i32* [[TMP2:%.*]], align 4 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/phi-nodes-simple.ll =================================================================== --- llvm/test/Transforms/IROutliner/phi-nodes-simple.ll +++ llvm/test/Transforms/IROutliner/phi-nodes-simple.ll @@ -43,7 +43,7 @@ ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[TEST_TO_OUTLINE:%.*]] ; CHECK: test_to_outline: @@ -52,7 +52,5 @@ ; CHECK-NEXT: [[TMP2:%.*]] = phi i32 [ 0, [[TEST_TO_OUTLINE]] ] ; CHECK-NEXT: store i32 2, i32* [[TMP0:%.*]], align 4 ; CHECK-NEXT: store i32 3, i32* [[TMP1:%.*]], align 4 -; CHECK-NEXT: br label [[TEST_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: test_after_outline.exitStub: ; CHECK-NEXT: ret void ; Index: llvm/test/Transforms/IROutliner/region-end-of-module.ll =================================================================== --- llvm/test/Transforms/IROutliner/region-end-of-module.ll +++ llvm/test/Transforms/IROutliner/region-end-of-module.ll @@ -87,7 +87,7 @@ ; CHECK-NEXT: unreachable ; ; -; CHECK: define internal void @outlined_ir_func_0( +; CHECK-LABEL: define internal void @outlined_ir_func_0( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[ENTRY_TO_OUTLINE:%.*]] ; CHECK: entry_to_outline: @@ -96,17 +96,13 @@ ; CHECK-NEXT: br label [[FOR_BODY:%.*]] ; CHECK: for.body: ; CHECK-NEXT: [[INC:%.*]] = add nsw i32 2, 1 -; CHECK-NEXT: br label [[ENTRY_AFTER_OUTLINE_EXITSTUB:%.*]] -; CHECK: entry_after_outline.exitStub: ; CHECK-NEXT: ret void ; ; -; CHECK: define internal void @outlined_ir_func_1( +; CHECK-LABEL: define internal void @outlined_ir_func_1( ; CHECK-NEXT: newFuncRoot: ; CHECK-NEXT: br label [[FOR_BODY_TO_OUTLINE:%.*]] ; CHECK: for.body_to_outline: ; CHECK-NEXT: [[INC:%.*]] = add nsw i32 2, 1 -; CHECK-NEXT: br label [[FOR_COND1_EXITSTUB:%.*]] -; CHECK: for.cond1.exitStub: ; CHECK-NEXT: ret void ;