From b60736ec1405bb0a8dd40989f67ef4c93da068ab Mon Sep 17 00:00:00 2001 From: Dimitry Andric Date: Tue, 16 Feb 2021 21:13:02 +0100 Subject: Vendor import of llvm-project main 8e464dd76bef, the last commit before the upstream release/12.x branch was created. --- .../AggressiveInstCombine.cpp | 149 +- .../AggressiveInstCombine/TruncInstCombine.cpp | 13 +- llvm/lib/Transforms/Coroutines/CoroCleanup.cpp | 1 + llvm/lib/Transforms/Coroutines/CoroEarly.cpp | 11 +- llvm/lib/Transforms/Coroutines/CoroElide.cpp | 25 +- llvm/lib/Transforms/Coroutines/CoroFrame.cpp | 1499 +++++--- llvm/lib/Transforms/Coroutines/CoroInstr.h | 181 +- llvm/lib/Transforms/Coroutines/CoroInternal.h | 59 +- llvm/lib/Transforms/Coroutines/CoroSplit.cpp | 595 +++- llvm/lib/Transforms/Coroutines/Coroutines.cpp | 109 +- llvm/lib/Transforms/HelloNew/HelloWorld.cpp | 17 + llvm/lib/Transforms/IPO/AlwaysInliner.cpp | 55 +- llvm/lib/Transforms/IPO/Annotation2Metadata.cpp | 106 + llvm/lib/Transforms/IPO/ArgumentPromotion.cpp | 44 +- llvm/lib/Transforms/IPO/Attributor.cpp | 542 ++- llvm/lib/Transforms/IPO/AttributorAttributes.cpp | 1306 ++++++- llvm/lib/Transforms/IPO/BlockExtractor.cpp | 79 +- .../lib/Transforms/IPO/DeadArgumentElimination.cpp | 31 +- llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp | 47 +- llvm/lib/Transforms/IPO/FunctionAttrs.cpp | 265 +- llvm/lib/Transforms/IPO/FunctionImport.cpp | 49 +- llvm/lib/Transforms/IPO/GlobalOpt.cpp | 38 +- llvm/lib/Transforms/IPO/HotColdSplitting.cpp | 100 +- llvm/lib/Transforms/IPO/IPConstantPropagation.cpp | 308 -- llvm/lib/Transforms/IPO/IPO.cpp | 11 +- llvm/lib/Transforms/IPO/IROutliner.cpp | 1764 ++++++++++ llvm/lib/Transforms/IPO/Inliner.cpp | 100 +- llvm/lib/Transforms/IPO/LoopExtractor.cpp | 137 +- llvm/lib/Transforms/IPO/LowerTypeTests.cpp | 32 +- llvm/lib/Transforms/IPO/MergeFunctions.cpp | 6 +- llvm/lib/Transforms/IPO/OpenMPOpt.cpp | 1350 ++++++-- llvm/lib/Transforms/IPO/PartialInlining.cpp | 329 +- llvm/lib/Transforms/IPO/PassManagerBuilder.cpp | 161 +- llvm/lib/Transforms/IPO/PruneEH.cpp | 72 +- llvm/lib/Transforms/IPO/SampleContextTracker.cpp | 521 +++ llvm/lib/Transforms/IPO/SampleProfile.cpp | 315 +- llvm/lib/Transforms/IPO/SampleProfileProbe.cpp | 276 ++ llvm/lib/Transforms/IPO/StripSymbols.cpp | 56 +- llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp | 6 +- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp | 22 +- .../Transforms/InstCombine/InstCombineAddSub.cpp | 335 +- .../Transforms/InstCombine/InstCombineAndOrXor.cpp | 760 ++-- .../InstCombine/InstCombineAtomicRMW.cpp | 18 +- .../Transforms/InstCombine/InstCombineCalls.cpp | 3327 ++---------------- .../Transforms/InstCombine/InstCombineCasts.cpp | 375 +- .../Transforms/InstCombine/InstCombineCompares.cpp | 502 +-- .../Transforms/InstCombine/InstCombineInternal.h | 409 +-- .../InstCombine/InstCombineLoadStoreAlloca.cpp | 232 +- .../InstCombine/InstCombineMulDivRem.cpp | 205 +- .../Transforms/InstCombine/InstCombineNegator.cpp | 149 +- llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp | 245 +- .../Transforms/InstCombine/InstCombineSelect.cpp | 491 +-- .../Transforms/InstCombine/InstCombineShifts.cpp | 208 +- .../InstCombine/InstCombineSimplifyDemanded.cpp | 597 +--- .../Transforms/InstCombine/InstCombineTables.td | 11 - .../InstCombine/InstCombineVectorOps.cpp | 434 ++- .../InstCombine/InstructionCombining.cpp | 417 ++- .../Instrumentation/AddressSanitizer.cpp | 186 +- llvm/lib/Transforms/Instrumentation/CFGMST.h | 17 +- llvm/lib/Transforms/Instrumentation/CGProfile.cpp | 3 +- .../Instrumentation/ControlHeightReduction.cpp | 38 +- .../Instrumentation/DataFlowSanitizer.cpp | 859 +++-- .../Transforms/Instrumentation/GCOVProfiling.cpp | 682 ++-- .../Instrumentation/HWAddressSanitizer.cpp | 311 +- .../Instrumentation/IndirectCallPromotion.cpp | 9 +- .../Transforms/Instrumentation/InstrProfiling.cpp | 109 +- .../Transforms/Instrumentation/Instrumentation.cpp | 4 +- .../lib/Transforms/Instrumentation/MemProfiler.cpp | 638 ++++ .../Transforms/Instrumentation/MemorySanitizer.cpp | 411 ++- .../Instrumentation/PGOInstrumentation.cpp | 324 +- .../Transforms/Instrumentation/PGOMemOPSizeOpt.cpp | 38 +- .../Transforms/Instrumentation/PoisonChecking.cpp | 10 +- .../Instrumentation/SanitizerCoverage.cpp | 124 +- .../Transforms/Instrumentation/ThreadSanitizer.cpp | 186 +- .../Instrumentation/ValueProfileCollector.cpp | 2 +- .../Instrumentation/ValueProfileCollector.h | 9 +- llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp | 67 +- llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h | 12 +- llvm/lib/Transforms/ObjCARC/ObjCARC.cpp | 4 +- llvm/lib/Transforms/ObjCARC/ObjCARC.h | 2 - llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp | 78 +- llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp | 226 +- llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp | 78 +- llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp | 337 +- llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp | 25 +- llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h | 12 +- .../ObjCARC/ProvenanceAnalysisEvaluator.cpp | 4 +- llvm/lib/Transforms/ObjCARC/PtrState.cpp | 4 +- llvm/lib/Transforms/Scalar/ADCE.cpp | 2 +- llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp | 90 + llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp | 2 +- llvm/lib/Transforms/Scalar/ConstantHoisting.cpp | 15 +- llvm/lib/Transforms/Scalar/ConstantProp.cpp | 121 - .../Transforms/Scalar/ConstraintElimination.cpp | 407 +++ .../Scalar/CorrelatedValuePropagation.cpp | 339 +- llvm/lib/Transforms/Scalar/DCE.cpp | 66 +- .../lib/Transforms/Scalar/DeadStoreElimination.cpp | 1066 ++++-- llvm/lib/Transforms/Scalar/DivRemPairs.cpp | 10 +- llvm/lib/Transforms/Scalar/EarlyCSE.cpp | 432 ++- llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp | 1 + llvm/lib/Transforms/Scalar/Float2Int.cpp | 1 - llvm/lib/Transforms/Scalar/GVN.cpp | 417 ++- llvm/lib/Transforms/Scalar/GVNHoist.cpp | 1383 ++++---- llvm/lib/Transforms/Scalar/GVNSink.cpp | 13 +- llvm/lib/Transforms/Scalar/GuardWidening.cpp | 14 +- llvm/lib/Transforms/Scalar/IndVarSimplify.cpp | 1308 ++----- .../Scalar/InductiveRangeCheckElimination.cpp | 104 +- llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp | 160 +- llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp | 2 + llvm/lib/Transforms/Scalar/JumpThreading.cpp | 350 +- llvm/lib/Transforms/Scalar/LICM.cpp | 333 +- llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp | 2 +- llvm/lib/Transforms/Scalar/LoopDeletion.cpp | 129 +- llvm/lib/Transforms/Scalar/LoopDistribute.cpp | 16 +- llvm/lib/Transforms/Scalar/LoopFlatten.cpp | 728 ++++ llvm/lib/Transforms/Scalar/LoopFuse.cpp | 329 +- llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp | 534 ++- llvm/lib/Transforms/Scalar/LoopInterchange.cpp | 135 +- llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp | 63 +- llvm/lib/Transforms/Scalar/LoopPassManager.cpp | 313 +- llvm/lib/Transforms/Scalar/LoopPredication.cpp | 15 +- llvm/lib/Transforms/Scalar/LoopRerollPass.cpp | 66 +- llvm/lib/Transforms/Scalar/LoopRotation.cpp | 45 +- llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp | 28 +- llvm/lib/Transforms/Scalar/LoopSink.cpp | 148 +- llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp | 139 +- .../lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp | 12 +- llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp | 92 +- llvm/lib/Transforms/Scalar/LoopUnswitch.cpp | 321 +- llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp | 110 +- .../Transforms/Scalar/LowerConstantIntrinsics.cpp | 2 +- .../lib/Transforms/Scalar/LowerExpectIntrinsic.cpp | 21 +- .../Transforms/Scalar/LowerMatrixIntrinsics.cpp | 291 +- llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp | 860 +++-- llvm/lib/Transforms/Scalar/MergeICmps.cpp | 24 +- llvm/lib/Transforms/Scalar/NaryReassociate.cpp | 90 +- llvm/lib/Transforms/Scalar/NewGVN.cpp | 127 +- llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp | 9 +- llvm/lib/Transforms/Scalar/Reassociate.cpp | 114 +- llvm/lib/Transforms/Scalar/Reg2Mem.cpp | 120 +- .../Transforms/Scalar/RewriteStatepointsForGC.cpp | 147 +- llvm/lib/Transforms/Scalar/SCCP.cpp | 412 ++- llvm/lib/Transforms/Scalar/SROA.cpp | 313 +- llvm/lib/Transforms/Scalar/Scalar.cpp | 37 +- .../Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp | 948 +++++ llvm/lib/Transforms/Scalar/Scalarizer.cpp | 9 +- .../Scalar/SeparateConstOffsetFromGEP.cpp | 84 +- llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp | 74 +- llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp | 188 +- llvm/lib/Transforms/Scalar/Sink.cpp | 80 +- llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp | 11 +- .../lib/Transforms/Scalar/SpeculativeExecution.cpp | 9 +- .../Scalar/StraightLineStrengthReduce.cpp | 101 +- llvm/lib/Transforms/Scalar/StructurizeCFG.cpp | 171 +- .../Transforms/Scalar/TailRecursionElimination.cpp | 146 +- .../lib/Transforms/Scalar/WarnMissedTransforms.cpp | 6 +- llvm/lib/Transforms/Utils/AMDGPUEmitPrintf.cpp | 3 - llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp | 5 +- llvm/lib/Transforms/Utils/BasicBlockUtils.cpp | 320 +- llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp | 35 +- llvm/lib/Transforms/Utils/BuildLibCalls.cpp | 477 ++- llvm/lib/Transforms/Utils/CallGraphUpdater.cpp | 5 +- llvm/lib/Transforms/Utils/CallPromotionUtils.cpp | 13 +- .../Transforms/Utils/CanonicalizeFreezeInLoops.cpp | 4 +- llvm/lib/Transforms/Utils/CloneFunction.cpp | 142 +- llvm/lib/Transforms/Utils/CloneModule.cpp | 15 +- llvm/lib/Transforms/Utils/CodeExtractor.cpp | 60 +- llvm/lib/Transforms/Utils/CodeMoverUtils.cpp | 45 +- llvm/lib/Transforms/Utils/Debugify.cpp | 103 +- .../lib/Transforms/Utils/EntryExitInstrumenter.cpp | 13 +- llvm/lib/Transforms/Utils/EscapeEnumerator.cpp | 5 +- llvm/lib/Transforms/Utils/Evaluator.cpp | 14 +- llvm/lib/Transforms/Utils/FixIrreducible.cpp | 32 +- llvm/lib/Transforms/Utils/FunctionComparator.cpp | 25 +- llvm/lib/Transforms/Utils/GlobalStatus.cpp | 3 +- llvm/lib/Transforms/Utils/GuardUtils.cpp | 2 +- .../Utils/ImportedFunctionsInliningStatistics.cpp | 202 -- llvm/lib/Transforms/Utils/InjectTLIMappings.cpp | 4 +- llvm/lib/Transforms/Utils/InlineFunction.cpp | 261 +- llvm/lib/Transforms/Utils/InstructionNamer.cpp | 59 +- llvm/lib/Transforms/Utils/LCSSA.cpp | 82 +- llvm/lib/Transforms/Utils/Local.cpp | 734 ++-- llvm/lib/Transforms/Utils/LoopPeel.cpp | 847 +++++ llvm/lib/Transforms/Utils/LoopRotationUtils.cpp | 108 +- llvm/lib/Transforms/Utils/LoopSimplify.cpp | 24 +- llvm/lib/Transforms/Utils/LoopUnroll.cpp | 129 +- llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp | 35 +- llvm/lib/Transforms/Utils/LoopUnrollPeel.cpp | 798 ----- llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp | 33 +- llvm/lib/Transforms/Utils/LoopUtils.cpp | 485 +-- llvm/lib/Transforms/Utils/LoopVersioning.cpp | 150 +- llvm/lib/Transforms/Utils/LowerInvoke.cpp | 2 +- llvm/lib/Transforms/Utils/LowerSwitch.cpp | 403 ++- llvm/lib/Transforms/Utils/MatrixUtils.cpp | 104 + llvm/lib/Transforms/Utils/MetaRenamer.cpp | 235 +- llvm/lib/Transforms/Utils/MisExpect.cpp | 178 - llvm/lib/Transforms/Utils/PredicateInfo.cpp | 225 +- .../Transforms/Utils/PromoteMemoryToRegister.cpp | 118 +- llvm/lib/Transforms/Utils/SSAUpdater.cpp | 19 +- .../Transforms/Utils/ScalarEvolutionExpander.cpp | 753 ++-- llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 1874 ++++++---- llvm/lib/Transforms/Utils/SimplifyIndVar.cpp | 1130 +++++- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp | 105 +- llvm/lib/Transforms/Utils/SizeOpts.cpp | 5 - llvm/lib/Transforms/Utils/StripGCRelocates.cpp | 46 +- .../Utils/StripNonLineTableDebugInfo.cpp | 23 +- .../Transforms/Utils/UnifyFunctionExitNodes.cpp | 113 +- llvm/lib/Transforms/Utils/UnifyLoopExits.cpp | 53 +- .../Utils/UniqueInternalLinkageNames.cpp | 23 +- llvm/lib/Transforms/Utils/Utils.cpp | 10 +- llvm/lib/Transforms/Utils/VNCoercion.cpp | 35 +- llvm/lib/Transforms/Utils/ValueMapper.cpp | 28 +- .../Transforms/Vectorize/LoadStoreVectorizer.cpp | 18 +- .../Vectorize/LoopVectorizationLegality.cpp | 104 +- .../Vectorize/LoopVectorizationPlanner.h | 48 +- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp | 3657 ++++++++++++++------ llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp | 2242 ++++++------ llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h | 10 +- llvm/lib/Transforms/Vectorize/VPlan.cpp | 302 +- llvm/lib/Transforms/Vectorize/VPlan.h | 606 ++-- llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp | 4 +- llvm/lib/Transforms/Vectorize/VPlanSLP.cpp | 25 +- llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp | 10 +- llvm/lib/Transforms/Vectorize/VPlanValue.h | 214 +- llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp | 8 +- llvm/lib/Transforms/Vectorize/VectorCombine.cpp | 207 +- 226 files changed, 36380 insertions(+), 20395 deletions(-) create mode 100644 llvm/lib/Transforms/HelloNew/HelloWorld.cpp create mode 100644 llvm/lib/Transforms/IPO/Annotation2Metadata.cpp delete mode 100644 llvm/lib/Transforms/IPO/IPConstantPropagation.cpp create mode 100644 llvm/lib/Transforms/IPO/IROutliner.cpp create mode 100644 llvm/lib/Transforms/IPO/SampleContextTracker.cpp create mode 100644 llvm/lib/Transforms/IPO/SampleProfileProbe.cpp delete mode 100644 llvm/lib/Transforms/InstCombine/InstCombineTables.td create mode 100644 llvm/lib/Transforms/Instrumentation/MemProfiler.cpp create mode 100644 llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp delete mode 100644 llvm/lib/Transforms/Scalar/ConstantProp.cpp create mode 100644 llvm/lib/Transforms/Scalar/ConstraintElimination.cpp create mode 100644 llvm/lib/Transforms/Scalar/LoopFlatten.cpp create mode 100644 llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp delete mode 100644 llvm/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp create mode 100644 llvm/lib/Transforms/Utils/LoopPeel.cpp delete mode 100644 llvm/lib/Transforms/Utils/LoopUnrollPeel.cpp create mode 100644 llvm/lib/Transforms/Utils/MatrixUtils.cpp delete mode 100644 llvm/lib/Transforms/Utils/MisExpect.cpp (limited to 'llvm/lib/Transforms') diff --git a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp index d315c7f13ac2..a7ae10d156d5 100644 --- a/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp +++ b/llvm/lib/Transforms/AggressiveInstCombine/AggressiveInstCombine.cpp @@ -21,8 +21,10 @@ #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/Function.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PatternMatch.h" @@ -38,6 +40,8 @@ using namespace PatternMatch; STATISTIC(NumAnyOrAllBitsSet, "Number of any/all-bits-set patterns folded"); STATISTIC(NumGuardedRotates, "Number of guarded rotates transformed into funnel shifts"); +STATISTIC(NumGuardedFunnelShifts, + "Number of guarded funnel shifts transformed into funnel shifts"); STATISTIC(NumPopCountRecognized, "Number of popcount idioms recognized"); namespace { @@ -66,96 +70,127 @@ public: }; } // namespace -/// Match a pattern for a bitwise rotate operation that partially guards -/// against undefined behavior by branching around the rotation when the shift -/// amount is 0. -static bool foldGuardedRotateToFunnelShift(Instruction &I) { +/// Match a pattern for a bitwise funnel/rotate operation that partially guards +/// against undefined behavior by branching around the funnel-shift/rotation +/// when the shift amount is 0. +static bool foldGuardedFunnelShift(Instruction &I, const DominatorTree &DT) { if (I.getOpcode() != Instruction::PHI || I.getNumOperands() != 2) return false; // As with the one-use checks below, this is not strictly necessary, but we // are being cautious to avoid potential perf regressions on targets that - // do not actually have a rotate instruction (where the funnel shift would be - // expanded back into math/shift/logic ops). + // do not actually have a funnel/rotate instruction (where the funnel shift + // would be expanded back into math/shift/logic ops). if (!isPowerOf2_32(I.getType()->getScalarSizeInBits())) return false; - // Match V to funnel shift left/right and capture the source operand and - // shift amount in X and Y. - auto matchRotate = [](Value *V, Value *&X, Value *&Y) { - Value *L0, *L1, *R0, *R1; + // Match V to funnel shift left/right and capture the source operands and + // shift amount. + auto matchFunnelShift = [](Value *V, Value *&ShVal0, Value *&ShVal1, + Value *&ShAmt) { + Value *SubAmt; unsigned Width = V->getType()->getScalarSizeInBits(); - auto Sub = m_Sub(m_SpecificInt(Width), m_Value(R1)); - - // rotate_left(X, Y) == (X << Y) | (X >> (Width - Y)) - auto RotL = m_OneUse( - m_c_Or(m_Shl(m_Value(L0), m_Value(L1)), m_LShr(m_Value(R0), Sub))); - if (RotL.match(V) && L0 == R0 && L1 == R1) { - X = L0; - Y = L1; - return Intrinsic::fshl; + + // fshl(ShVal0, ShVal1, ShAmt) + // == (ShVal0 << ShAmt) | (ShVal1 >> (Width -ShAmt)) + if (match(V, m_OneUse(m_c_Or( + m_Shl(m_Value(ShVal0), m_Value(ShAmt)), + m_LShr(m_Value(ShVal1), + m_Sub(m_SpecificInt(Width), m_Value(SubAmt))))))) { + if (ShAmt == SubAmt) // TODO: Use m_Specific + return Intrinsic::fshl; } - // rotate_right(X, Y) == (X >> Y) | (X << (Width - Y)) - auto RotR = m_OneUse( - m_c_Or(m_LShr(m_Value(L0), m_Value(L1)), m_Shl(m_Value(R0), Sub))); - if (RotR.match(V) && L0 == R0 && L1 == R1) { - X = L0; - Y = L1; - return Intrinsic::fshr; + // fshr(ShVal0, ShVal1, ShAmt) + // == (ShVal0 >> ShAmt) | (ShVal1 << (Width - ShAmt)) + if (match(V, + m_OneUse(m_c_Or(m_Shl(m_Value(ShVal0), m_Sub(m_SpecificInt(Width), + m_Value(SubAmt))), + m_LShr(m_Value(ShVal1), m_Value(ShAmt)))))) { + if (ShAmt == SubAmt) // TODO: Use m_Specific + return Intrinsic::fshr; } return Intrinsic::not_intrinsic; }; - // One phi operand must be a rotate operation, and the other phi operand must - // be the source value of that rotate operation: - // phi [ rotate(RotSrc, RotAmt), RotBB ], [ RotSrc, GuardBB ] + // One phi operand must be a funnel/rotate operation, and the other phi + // operand must be the source value of that funnel/rotate operation: + // phi [ rotate(RotSrc, ShAmt), FunnelBB ], [ RotSrc, GuardBB ] + // phi [ fshl(ShVal0, ShVal1, ShAmt), FunnelBB ], [ ShVal0, GuardBB ] + // phi [ fshr(ShVal0, ShVal1, ShAmt), FunnelBB ], [ ShVal1, GuardBB ] PHINode &Phi = cast(I); + unsigned FunnelOp = 0, GuardOp = 1; Value *P0 = Phi.getOperand(0), *P1 = Phi.getOperand(1); - Value *RotSrc, *RotAmt; - Intrinsic::ID IID = matchRotate(P0, RotSrc, RotAmt); - if (IID == Intrinsic::not_intrinsic || RotSrc != P1) { - IID = matchRotate(P1, RotSrc, RotAmt); - if (IID == Intrinsic::not_intrinsic || RotSrc != P0) + Value *ShVal0, *ShVal1, *ShAmt; + Intrinsic::ID IID = matchFunnelShift(P0, ShVal0, ShVal1, ShAmt); + if (IID == Intrinsic::not_intrinsic || + (IID == Intrinsic::fshl && ShVal0 != P1) || + (IID == Intrinsic::fshr && ShVal1 != P1)) { + IID = matchFunnelShift(P1, ShVal0, ShVal1, ShAmt); + if (IID == Intrinsic::not_intrinsic || + (IID == Intrinsic::fshl && ShVal0 != P0) || + (IID == Intrinsic::fshr && ShVal1 != P0)) return false; assert((IID == Intrinsic::fshl || IID == Intrinsic::fshr) && "Pattern must match funnel shift left or right"); + std::swap(FunnelOp, GuardOp); } // The incoming block with our source operand must be the "guard" block. - // That must contain a cmp+branch to avoid the rotate when the shift amount - // is equal to 0. The other incoming block is the block with the rotate. - BasicBlock *GuardBB = Phi.getIncomingBlock(RotSrc == P1); - BasicBlock *RotBB = Phi.getIncomingBlock(RotSrc != P1); + // That must contain a cmp+branch to avoid the funnel/rotate when the shift + // amount is equal to 0. The other incoming block is the block with the + // funnel/rotate. + BasicBlock *GuardBB = Phi.getIncomingBlock(GuardOp); + BasicBlock *FunnelBB = Phi.getIncomingBlock(FunnelOp); Instruction *TermI = GuardBB->getTerminator(); + + // Ensure that the shift values dominate each block. + if (!DT.dominates(ShVal0, TermI) || !DT.dominates(ShVal1, TermI)) + return false; + ICmpInst::Predicate Pred; BasicBlock *PhiBB = Phi.getParent(); - if (!match(TermI, m_Br(m_ICmp(Pred, m_Specific(RotAmt), m_ZeroInt()), - m_SpecificBB(PhiBB), m_SpecificBB(RotBB)))) + if (!match(TermI, m_Br(m_ICmp(Pred, m_Specific(ShAmt), m_ZeroInt()), + m_SpecificBB(PhiBB), m_SpecificBB(FunnelBB)))) return false; if (Pred != CmpInst::ICMP_EQ) return false; + IRBuilder<> Builder(PhiBB, PhiBB->getFirstInsertionPt()); + + if (ShVal0 == ShVal1) + ++NumGuardedRotates; + else + ++NumGuardedFunnelShifts; + + // If this is not a rotate then the select was blocking poison from the + // 'shift-by-zero' non-TVal, but a funnel shift won't - so freeze it. + bool IsFshl = IID == Intrinsic::fshl; + if (ShVal0 != ShVal1) { + if (IsFshl && !llvm::isGuaranteedNotToBePoison(ShVal1)) + ShVal1 = Builder.CreateFreeze(ShVal1); + else if (!IsFshl && !llvm::isGuaranteedNotToBePoison(ShVal0)) + ShVal0 = Builder.CreateFreeze(ShVal0); + } + // We matched a variation of this IR pattern: // GuardBB: - // %cmp = icmp eq i32 %RotAmt, 0 - // br i1 %cmp, label %PhiBB, label %RotBB - // RotBB: - // %sub = sub i32 32, %RotAmt - // %shr = lshr i32 %X, %sub - // %shl = shl i32 %X, %RotAmt - // %rot = or i32 %shr, %shl + // %cmp = icmp eq i32 %ShAmt, 0 + // br i1 %cmp, label %PhiBB, label %FunnelBB + // FunnelBB: + // %sub = sub i32 32, %ShAmt + // %shr = lshr i32 %ShVal1, %sub + // %shl = shl i32 %ShVal0, %ShAmt + // %fsh = or i32 %shr, %shl // br label %PhiBB // PhiBB: - // %cond = phi i32 [ %rot, %RotBB ], [ %X, %GuardBB ] + // %cond = phi i32 [ %fsh, %FunnelBB ], [ %ShVal0, %GuardBB ] // --> - // llvm.fshl.i32(i32 %X, i32 %RotAmt) - IRBuilder<> Builder(PhiBB, PhiBB->getFirstInsertionPt()); + // llvm.fshl.i32(i32 %ShVal0, i32 %ShVal1, i32 %ShAmt) Function *F = Intrinsic::getDeclaration(Phi.getModule(), IID, Phi.getType()); - Phi.replaceAllUsesWith(Builder.CreateCall(F, {RotSrc, RotSrc, RotAmt})); - ++NumGuardedRotates; + Phi.replaceAllUsesWith(Builder.CreateCall(F, {ShVal0, ShVal1, ShAmt})); return true; } @@ -202,8 +237,8 @@ static bool matchAndOrChain(Value *V, MaskOps &MOps) { // We need a shift-right or a bare value representing a compare of bit 0 of // the original source operand. Value *Candidate; - uint64_t BitIndex = 0; - if (!match(V, m_LShr(m_Value(Candidate), m_ConstantInt(BitIndex)))) + const APInt *BitIndex = nullptr; + if (!match(V, m_LShr(m_Value(Candidate), m_APInt(BitIndex)))) Candidate = V; // Initialize result source operand. @@ -211,11 +246,11 @@ static bool matchAndOrChain(Value *V, MaskOps &MOps) { MOps.Root = Candidate; // The shift constant is out-of-range? This code hasn't been simplified. - if (BitIndex >= MOps.Mask.getBitWidth()) + if (BitIndex && BitIndex->uge(MOps.Mask.getBitWidth())) return false; // Fill in the mask bit derived from the shift constant. - MOps.Mask.setBit(BitIndex); + MOps.Mask.setBit(BitIndex ? BitIndex->getZExtValue() : 0); return MOps.Root == Candidate; } @@ -344,7 +379,7 @@ static bool foldUnusualPatterns(Function &F, DominatorTree &DT) { // iteratively in this loop rather than waiting until the end. for (Instruction &I : make_range(BB.rbegin(), BB.rend())) { MadeChange |= foldAnyOrAllBitsSet(I); - MadeChange |= foldGuardedRotateToFunnelShift(I); + MadeChange |= foldGuardedFunnelShift(I, DT); MadeChange |= tryToRecognizePopCount(I); } } diff --git a/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp b/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp index 5cd40c66227f..16b82219e8ca 100644 --- a/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp +++ b/llvm/lib/Transforms/AggressiveInstCombine/TruncInstCombine.cpp @@ -31,8 +31,8 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/Dominators.h" -#include "llvm/IR/Instruction.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" using namespace llvm; @@ -130,8 +130,7 @@ bool TruncInstCombine::buildTruncExpressionDag() { case Instruction::Select: { SmallVector Operands; getRelevantOperands(I, Operands); - for (Value *Operand : Operands) - Worklist.push_back(Operand); + append_range(Worklist, Operands); break; } default: @@ -289,10 +288,8 @@ Type *TruncInstCombine::getBestTruncatedType() { /// version of \p Ty, otherwise return \p Ty. static Type *getReducedType(Value *V, Type *Ty) { assert(Ty && !Ty->isVectorTy() && "Expect Scalar Type"); - if (auto *VTy = dyn_cast(V->getType())) { - // FIXME: should this handle scalable vectors? - return FixedVectorType::get(Ty, VTy->getNumElements()); - } + if (auto *VTy = dyn_cast(V->getType())) + return VectorType::get(Ty, VTy->getElementCount()); return Ty; } @@ -344,7 +341,7 @@ void TruncInstCombine::ReduceExpressionDag(Type *SclTy) { // 1. Update Old-TruncInst -> New-TruncInst. // 2. Remove Old-TruncInst (if New node is not TruncInst). // 3. Add New-TruncInst (if Old node was not TruncInst). - auto Entry = find(Worklist, I); + auto *Entry = find(Worklist, I); if (Entry != Worklist.end()) { if (auto *NewCI = dyn_cast(Res)) *Entry = NewCI; diff --git a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp index 233eae37c497..298149f8b546 100644 --- a/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroCleanup.cpp @@ -74,6 +74,7 @@ bool Lowerer::lowerRemainingCoroIntrinsics(Function &F) { case Intrinsic::coro_id: case Intrinsic::coro_id_retcon: case Intrinsic::coro_id_retcon_once: + case Intrinsic::coro_id_async: II->replaceAllUsesWith(ConstantTokenNone::get(Context)); break; case Intrinsic::coro_subfn_addr: diff --git a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp index 242e6c3f6b23..1660e41ba830 100644 --- a/llvm/lib/Transforms/Coroutines/CoroEarly.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroEarly.cpp @@ -164,10 +164,11 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) { if (cast(&I)->isFinal()) CB->setCannotDuplicate(); break; + case Intrinsic::coro_end_async: case Intrinsic::coro_end: // Make sure that fallthrough coro.end is not duplicated as CoroSplit // pass expects that there is at most one fallthrough coro.end. - if (cast(&I)->isFallthrough()) + if (cast(&I)->isFallthrough()) CB->setCannotDuplicate(); break; case Intrinsic::coro_noop: @@ -187,6 +188,7 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) { break; case Intrinsic::coro_id_retcon: case Intrinsic::coro_id_retcon_once: + case Intrinsic::coro_id_async: F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT); break; case Intrinsic::coro_resume: @@ -217,9 +219,10 @@ bool Lowerer::lowerEarlyIntrinsics(Function &F) { static bool declaresCoroEarlyIntrinsics(const Module &M) { return coro::declaresIntrinsics( M, {"llvm.coro.id", "llvm.coro.id.retcon", "llvm.coro.id.retcon.once", - "llvm.coro.destroy", "llvm.coro.done", "llvm.coro.end", - "llvm.coro.noop", "llvm.coro.free", "llvm.coro.promise", - "llvm.coro.resume", "llvm.coro.suspend"}); + "llvm.coro.id.async", "llvm.coro.destroy", "llvm.coro.done", + "llvm.coro.end", "llvm.coro.end.async", "llvm.coro.noop", + "llvm.coro.free", "llvm.coro.promise", "llvm.coro.resume", + "llvm.coro.suspend"}); } PreservedAnalyses CoroEarlyPass::run(Function &F, FunctionAnalysisManager &) { diff --git a/llvm/lib/Transforms/Coroutines/CoroElide.cpp b/llvm/lib/Transforms/Coroutines/CoroElide.cpp index 9d364b3097c1..07a183cfc66b 100644 --- a/llvm/lib/Transforms/Coroutines/CoroElide.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroElide.cpp @@ -83,14 +83,8 @@ static void removeTailCallAttribute(AllocaInst *Frame, AAResults &AA) { Function &F = *Frame->getFunction(); for (Instruction &I : instructions(F)) if (auto *Call = dyn_cast(&I)) - if (Call->isTailCall() && operandReferences(Call, Frame, AA)) { - // FIXME: If we ever hit this check. Evaluate whether it is more - // appropriate to retain musttail and allow the code to compile. - if (Call->isMustTailCall()) - report_fatal_error("Call referring to the coroutine frame cannot be " - "marked as musttail"); + if (Call->isTailCall() && operandReferences(Call, Frame, AA)) Call->setTailCall(false); - } } // Given a resume function @f.resume(%f.frame* %frame), returns the size @@ -252,7 +246,20 @@ bool Lowerer::shouldElide(Function *F, DominatorTree &DT) const { // If size of the set is the same as total number of coro.begin, that means we // found a coro.free or coro.destroy referencing each coro.begin, so we can // perform heap elision. - return ReferencedCoroBegins.size() == CoroBegins.size(); + if (ReferencedCoroBegins.size() != CoroBegins.size()) + return false; + + // If any call in the function is a musttail call, it usually won't work + // because we cannot drop the tailcall attribute, and a tail call will reuse + // the entire stack where we are going to put the new frame. In theory a more + // precise analysis can be done to check whether the new frame aliases with + // the call, however it's challenging to do so before the elision actually + // happened. + for (BasicBlock &BB : *F) + if (BB.getTerminatingMustTailCall()) + return false; + + return true; } void Lowerer::collectPostSplitCoroIds(Function *F) { @@ -366,7 +373,7 @@ static bool replaceDevirtTrigger(Function &F) { } static bool declaresCoroElideIntrinsics(Module &M) { - return coro::declaresIntrinsics(M, {"llvm.coro.id"}); + return coro::declaresIntrinsics(M, {"llvm.coro.id", "llvm.coro.id.async"}); } PreservedAnalyses CoroElidePass::run(Function &F, FunctionAnalysisManager &AM) { diff --git a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp index f55501a05d85..e53e7605b254 100644 --- a/llvm/lib/Transforms/Coroutines/CoroFrame.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroFrame.cpp @@ -20,16 +20,18 @@ #include "llvm/ADT/BitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/Analysis/PtrUseVisitor.h" +#include "llvm/Analysis/StackLifetime.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/CFG.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstIterator.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/MathExtras.h" -#include "llvm/Support/circular_raw_ostream.h" #include "llvm/Support/OptimizedStructLayout.h" +#include "llvm/Support/circular_raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" @@ -41,6 +43,13 @@ using namespace llvm; // "coro-frame", which results in leaner debug spew. #define DEBUG_TYPE "coro-suspend-crossing" +static cl::opt EnableReuseStorageInFrame( + "reuse-storage-in-coroutine-frame", cl::Hidden, + cl::desc( + "Enable the optimization which would reuse the storage in the coroutine \ + frame for allocas whose liferanges are not overlapped, for testing purposes"), + llvm::cl::init(false)); + enum { SmallVectorThreshold = 32 }; // Provides two way mapping between the blocks and numbers. @@ -126,10 +135,10 @@ struct SuspendCrossingInfo { BasicBlock *UseBB = I->getParent(); - // As a special case, treat uses by an llvm.coro.suspend.retcon - // as if they were uses in the suspend's single predecessor: the - // uses conceptually occur before the suspend. - if (isa(I)) { + // As a special case, treat uses by an llvm.coro.suspend.retcon or an + // llvm.coro.suspend.async as if they were uses in the suspend's single + // predecessor: the uses conceptually occur before the suspend. + if (isa(I) || isa(I)) { UseBB = UseBB->getSinglePredecessor(); assert(UseBB && "should have split coro.suspend into its own block"); } @@ -283,71 +292,96 @@ SuspendCrossingInfo::SuspendCrossingInfo(Function &F, coro::Shape &Shape) #undef DEBUG_TYPE // "coro-suspend-crossing" #define DEBUG_TYPE "coro-frame" -// We build up the list of spills for every case where a use is separated -// from the definition by a suspend point. - -static const unsigned InvalidFieldIndex = ~0U; - namespace { -class Spill { - Value *Def = nullptr; - Instruction *User = nullptr; - unsigned FieldNo = InvalidFieldIndex; - -public: - Spill(Value *Def, llvm::User *U) : Def(Def), User(cast(U)) {} - - Value *def() const { return Def; } - Instruction *user() const { return User; } - BasicBlock *userBlock() const { return User->getParent(); } +class FrameTypeBuilder; +// Mapping from the to-be-spilled value to all the users that need reload. +using SpillInfo = SmallMapVector, 8>; +struct AllocaInfo { + AllocaInst *Alloca; + DenseMap> Aliases; + bool MayWriteBeforeCoroBegin; + AllocaInfo(AllocaInst *Alloca, + DenseMap> Aliases, + bool MayWriteBeforeCoroBegin) + : Alloca(Alloca), Aliases(std::move(Aliases)), + MayWriteBeforeCoroBegin(MayWriteBeforeCoroBegin) {} +}; +struct FrameDataInfo { + // All the values (that are not allocas) that needs to be spilled to the + // frame. + SpillInfo Spills; + // Allocas contains all values defined as allocas that need to live in the + // frame. + SmallVector Allocas; + + SmallVector getAllDefs() const { + SmallVector Defs; + for (const auto &P : Spills) + Defs.push_back(P.first); + for (const auto &A : Allocas) + Defs.push_back(A.Alloca); + return Defs; + } - // Note that field index is stored in the first SpillEntry for a particular - // definition. Subsequent mentions of a defintion do not have fieldNo - // assigned. This works out fine as the users of Spills capture the info about - // the definition the first time they encounter it. Consider refactoring - // SpillInfo into two arrays to normalize the spill representation. - unsigned fieldIndex() const { - assert(FieldNo != InvalidFieldIndex && "Accessing unassigned field"); - return FieldNo; + uint32_t getFieldIndex(Value *V) const { + auto Itr = FieldIndexMap.find(V); + assert(Itr != FieldIndexMap.end() && + "Value does not have a frame field index"); + return Itr->second; } - void setFieldIndex(unsigned FieldNumber) { - assert(FieldNo == InvalidFieldIndex && "Reassigning field number"); - FieldNo = FieldNumber; + + void setFieldIndex(Value *V, uint32_t Index) { + assert((LayoutIndexUpdateStarted || FieldIndexMap.count(V) == 0) && + "Cannot set the index for the same field twice."); + FieldIndexMap[V] = Index; } + + // Remap the index of every field in the frame, using the final layout index. + void updateLayoutIndex(FrameTypeBuilder &B); + +private: + // LayoutIndexUpdateStarted is used to avoid updating the index of any field + // twice by mistake. + bool LayoutIndexUpdateStarted = false; + // Map from values to their slot indexes on the frame. They will be first set + // with their original insertion field index. After the frame is built, their + // indexes will be updated into the final layout index. + DenseMap FieldIndexMap; }; } // namespace -// Note that there may be more than one record with the same value of Def in -// the SpillInfo vector. -using SpillInfo = SmallVector; - #ifndef NDEBUG -static void dump(StringRef Title, SpillInfo const &Spills) { +static void dumpSpills(StringRef Title, const SpillInfo &Spills) { dbgs() << "------------- " << Title << "--------------\n"; - Value *CurrentValue = nullptr; - for (auto const &E : Spills) { - if (CurrentValue != E.def()) { - CurrentValue = E.def(); - CurrentValue->dump(); - } + for (const auto &E : Spills) { + E.first->dump(); dbgs() << " user: "; - E.user()->dump(); + for (auto *I : E.second) + I->dump(); + } +} + +static void dumpAllocas(const SmallVectorImpl &Allocas) { + dbgs() << "------------- Allocas --------------\n"; + for (const auto &A : Allocas) { + A.Alloca->dump(); } } #endif namespace { +using FieldIDType = size_t; // We cannot rely solely on natural alignment of a type when building a // coroutine frame and if the alignment specified on the Alloca instruction // differs from the natural alignment of the alloca type we will need to insert // padding. class FrameTypeBuilder { +private: struct Field { uint64_t Size; uint64_t Offset; - Spill *ForSpill; Type *Ty; - unsigned FieldIndex; + FieldIDType LayoutFieldIndex; Align Alignment; Align TyAlignment; }; @@ -363,19 +397,12 @@ class FrameTypeBuilder { public: FrameTypeBuilder(LLVMContext &Context, DataLayout const &DL) - : DL(DL), Context(Context) {} - - class FieldId { - size_t Value; - explicit FieldId(size_t Value) : Value(Value) {} - - friend class FrameTypeBuilder; - }; + : DL(DL), Context(Context) {} /// Add a field to this structure for the storage of an `alloca` /// instruction. - FieldId addFieldForAlloca(AllocaInst *AI, Spill *ForSpill = nullptr, - bool IsHeader = false) { + LLVM_NODISCARD FieldIDType addFieldForAlloca(AllocaInst *AI, + bool IsHeader = false) { Type *Ty = AI->getAllocatedType(); // Make an array type if this is a static array allocation. @@ -386,13 +413,42 @@ public: report_fatal_error("Coroutines cannot handle non static allocas yet"); } - return addField(Ty, AI->getAlign(), ForSpill, IsHeader); + return addField(Ty, AI->getAlign(), IsHeader); } + /// We want to put the allocas whose lifetime-ranges are not overlapped + /// into one slot of coroutine frame. + /// Consider the example at:https://bugs.llvm.org/show_bug.cgi?id=45566 + /// + /// cppcoro::task alternative_paths(bool cond) { + /// if (cond) { + /// big_structure a; + /// process(a); + /// co_await something(); + /// } else { + /// big_structure b; + /// process2(b); + /// co_await something(); + /// } + /// } + /// + /// We want to put variable a and variable b in the same slot to + /// reduce the size of coroutine frame. + /// + /// This function use StackLifetime algorithm to partition the AllocaInsts in + /// Spills to non-overlapped sets in order to put Alloca in the same + /// non-overlapped set into the same slot in the Coroutine Frame. Then add + /// field for the allocas in the same non-overlapped set by using the largest + /// type as the field type. + /// + /// Side Effects: Because We sort the allocas, the order of allocas in the + /// frame may be different with the order in the source code. + void addFieldForAllocas(const Function &F, FrameDataInfo &FrameData, + coro::Shape &Shape); + /// Add a field to this structure. - FieldId addField(Type *Ty, MaybeAlign FieldAlignment, - Spill *ForSpill = nullptr, - bool IsHeader = false) { + LLVM_NODISCARD FieldIDType addField(Type *Ty, MaybeAlign FieldAlignment, + bool IsHeader = false) { assert(!IsFinished && "adding fields to a finished builder"); assert(Ty && "must provide a type for a field"); @@ -415,9 +471,8 @@ public: Offset = OptimizedStructLayoutField::FlexibleOffset; } - Fields.push_back({FieldSize, Offset, ForSpill, Ty, 0, - *FieldAlignment, TyAlignment}); - return FieldId(Fields.size() - 1); + Fields.push_back({FieldSize, Offset, Ty, 0, *FieldAlignment, TyAlignment}); + return Fields.size() - 1; } /// Finish the layout and set the body on the given type. @@ -433,13 +488,162 @@ public: return StructAlign; } - unsigned getFieldIndex(FieldId Id) const { + FieldIDType getLayoutFieldIndex(FieldIDType Id) const { assert(IsFinished && "not yet finished!"); - return Fields[Id.Value].FieldIndex; + return Fields[Id].LayoutFieldIndex; } }; } // namespace +void FrameDataInfo::updateLayoutIndex(FrameTypeBuilder &B) { + auto Updater = [&](Value *I) { + setFieldIndex(I, B.getLayoutFieldIndex(getFieldIndex(I))); + }; + LayoutIndexUpdateStarted = true; + for (auto &S : Spills) + Updater(S.first); + for (const auto &A : Allocas) + Updater(A.Alloca); + LayoutIndexUpdateStarted = false; +} + +void FrameTypeBuilder::addFieldForAllocas(const Function &F, + FrameDataInfo &FrameData, + coro::Shape &Shape) { + DenseMap AllocaIndex; + using AllocaSetType = SmallVector; + SmallVector NonOverlapedAllocas; + + // We need to add field for allocas at the end of this function. However, this + // function has multiple exits, so we use this helper to avoid redundant code. + struct RTTIHelper { + std::function func; + RTTIHelper(std::function &&func) : func(func) {} + ~RTTIHelper() { func(); } + } Helper([&]() { + for (auto AllocaList : NonOverlapedAllocas) { + auto *LargestAI = *AllocaList.begin(); + FieldIDType Id = addFieldForAlloca(LargestAI); + for (auto *Alloca : AllocaList) + FrameData.setFieldIndex(Alloca, Id); + } + }); + + if (!Shape.ReuseFrameSlot && !EnableReuseStorageInFrame) { + for (const auto &A : FrameData.Allocas) { + AllocaInst *Alloca = A.Alloca; + AllocaIndex[Alloca] = NonOverlapedAllocas.size(); + NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca)); + } + return; + } + + // Because there are pathes from the lifetime.start to coro.end + // for each alloca, the liferanges for every alloca is overlaped + // in the blocks who contain coro.end and the successor blocks. + // So we choose to skip there blocks when we calculates the liferange + // for each alloca. It should be reasonable since there shouldn't be uses + // in these blocks and the coroutine frame shouldn't be used outside the + // coroutine body. + // + // Note that the user of coro.suspend may not be SwitchInst. However, this + // case seems too complex to handle. And it is harmless to skip these + // patterns since it just prevend putting the allocas to live in the same + // slot. + DenseMap DefaultSuspendDest; + for (auto CoroSuspendInst : Shape.CoroSuspends) { + for (auto U : CoroSuspendInst->users()) { + if (auto *ConstSWI = dyn_cast(U)) { + auto *SWI = const_cast(ConstSWI); + DefaultSuspendDest[SWI] = SWI->getDefaultDest(); + SWI->setDefaultDest(SWI->getSuccessor(1)); + } + } + } + + auto ExtractAllocas = [&]() { + AllocaSetType Allocas; + Allocas.reserve(FrameData.Allocas.size()); + for (const auto &A : FrameData.Allocas) + Allocas.push_back(A.Alloca); + return Allocas; + }; + StackLifetime StackLifetimeAnalyzer(F, ExtractAllocas(), + StackLifetime::LivenessType::May); + StackLifetimeAnalyzer.run(); + auto IsAllocaInferenre = [&](const AllocaInst *AI1, const AllocaInst *AI2) { + return StackLifetimeAnalyzer.getLiveRange(AI1).overlaps( + StackLifetimeAnalyzer.getLiveRange(AI2)); + }; + auto GetAllocaSize = [&](const AllocaInfo &A) { + Optional RetSize = A.Alloca->getAllocationSizeInBits(DL); + assert(RetSize && "Variable Length Arrays (VLA) are not supported.\n"); + assert(!RetSize->isScalable() && "Scalable vectors are not yet supported"); + return RetSize->getFixedSize(); + }; + // Put larger allocas in the front. So the larger allocas have higher + // priority to merge, which can save more space potentially. Also each + // AllocaSet would be ordered. So we can get the largest Alloca in one + // AllocaSet easily. + sort(FrameData.Allocas, [&](const auto &Iter1, const auto &Iter2) { + return GetAllocaSize(Iter1) > GetAllocaSize(Iter2); + }); + for (const auto &A : FrameData.Allocas) { + AllocaInst *Alloca = A.Alloca; + bool Merged = false; + // Try to find if the Alloca is not inferenced with any existing + // NonOverlappedAllocaSet. If it is true, insert the alloca to that + // NonOverlappedAllocaSet. + for (auto &AllocaSet : NonOverlapedAllocas) { + assert(!AllocaSet.empty() && "Processing Alloca Set is not empty.\n"); + bool NoInference = none_of(AllocaSet, [&](auto Iter) { + return IsAllocaInferenre(Alloca, Iter); + }); + // If the alignment of A is multiple of the alignment of B, the address + // of A should satisfy the requirement for aligning for B. + // + // There may be other more fine-grained strategies to handle the alignment + // infomation during the merging process. But it seems hard to handle + // these strategies and benefit little. + bool Alignable = [&]() -> bool { + auto *LargestAlloca = *AllocaSet.begin(); + return LargestAlloca->getAlign().value() % Alloca->getAlign().value() == + 0; + }(); + bool CouldMerge = NoInference && Alignable; + if (!CouldMerge) + continue; + AllocaIndex[Alloca] = AllocaIndex[*AllocaSet.begin()]; + AllocaSet.push_back(Alloca); + Merged = true; + break; + } + if (!Merged) { + AllocaIndex[Alloca] = NonOverlapedAllocas.size(); + NonOverlapedAllocas.emplace_back(AllocaSetType(1, Alloca)); + } + } + // Recover the default target destination for each Switch statement + // reserved. + for (auto SwitchAndDefaultDest : DefaultSuspendDest) { + SwitchInst *SWI = SwitchAndDefaultDest.first; + BasicBlock *DestBB = SwitchAndDefaultDest.second; + SWI->setDefaultDest(DestBB); + } + // This Debug Info could tell us which allocas are merged into one slot. + LLVM_DEBUG(for (auto &AllocaSet + : NonOverlapedAllocas) { + if (AllocaSet.size() > 1) { + dbgs() << "In Function:" << F.getName() << "\n"; + dbgs() << "Find Union Set " + << "\n"; + dbgs() << "\tAllocas are \n"; + for (auto Alloca : AllocaSet) + dbgs() << "\t\t" << *Alloca << "\n"; + } + }); +} + void FrameTypeBuilder::finish(StructType *Ty) { assert(!IsFinished && "already finished!"); @@ -491,13 +695,8 @@ void FrameTypeBuilder::finish(StructType *Ty) { Offset - LastOffset)); } - // Record the layout information into both the Field and the - // original Spill, if there is one. F.Offset = Offset; - F.FieldIndex = FieldTypes.size(); - if (F.ForSpill) { - F.ForSpill->setFieldIndex(F.FieldIndex); - } + F.LayoutFieldIndex = FieldTypes.size(); FieldTypes.push_back(F.Ty); LastOffset = Offset + F.Size; @@ -509,8 +708,8 @@ void FrameTypeBuilder::finish(StructType *Ty) { // Check that the IR layout matches the offsets we expect. auto Layout = DL.getStructLayout(Ty); for (auto &F : Fields) { - assert(Ty->getElementType(F.FieldIndex) == F.Ty); - assert(Layout->getElementOffset(F.FieldIndex) == F.Offset); + assert(Ty->getElementType(F.LayoutFieldIndex) == F.Ty); + assert(Layout->getElementOffset(F.LayoutFieldIndex) == F.Offset); } #endif @@ -526,7 +725,7 @@ void FrameTypeBuilder::finish(StructType *Ty) { // ... spills ... // }; static StructType *buildFrameType(Function &F, coro::Shape &Shape, - SpillInfo &Spills) { + FrameDataInfo &FrameData) { LLVMContext &C = F.getContext(); const DataLayout &DL = F.getParent()->getDataLayout(); StructType *FrameTy = [&] { @@ -538,8 +737,7 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, FrameTypeBuilder B(C, DL); AllocaInst *PromiseAlloca = Shape.getPromiseAlloca(); - Optional PromiseFieldId; - Optional SwitchIndexFieldId; + Optional SwitchIndexFieldId; if (Shape.ABI == coro::ABI::Switch) { auto *FramePtrTy = FrameTy->getPointerTo(); @@ -549,14 +747,15 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, // Add header fields for the resume and destroy functions. // We can rely on these being perfectly packed. - B.addField(FnPtrTy, None, nullptr, /*header*/ true); - B.addField(FnPtrTy, None, nullptr, /*header*/ true); + (void)B.addField(FnPtrTy, None, /*header*/ true); + (void)B.addField(FnPtrTy, None, /*header*/ true); - // Add a header field for the promise if there is one. - if (PromiseAlloca) { - PromiseFieldId = - B.addFieldForAlloca(PromiseAlloca, nullptr, /*header*/ true); - } + // PromiseAlloca field needs to be explicitly added here because it's + // a header field with a fixed offset based on its alignment. Hence it + // needs special handling and cannot be added to FrameData.Allocas. + if (PromiseAlloca) + FrameData.setFieldIndex( + PromiseAlloca, B.addFieldForAlloca(PromiseAlloca, /*header*/ true)); // Add a field to store the suspend index. This doesn't need to // be in the header. @@ -568,40 +767,34 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, assert(PromiseAlloca == nullptr && "lowering doesn't support promises"); } - Value *CurrentDef = nullptr; - + // Because multiple allocas may own the same field slot, + // we add allocas to field here. + B.addFieldForAllocas(F, FrameData, Shape); + // Add PromiseAlloca to Allocas list so that + // 1. updateLayoutIndex could update its index after + // `performOptimizedStructLayout` + // 2. it is processed in insertSpills. + if (Shape.ABI == coro::ABI::Switch && PromiseAlloca) + // We assume that the promise alloca won't be modified before + // CoroBegin and no alias will be create before CoroBegin. + FrameData.Allocas.emplace_back( + PromiseAlloca, DenseMap>{}, false); // Create an entry for every spilled value. - for (auto &S : Spills) { - // We can have multiple entries in Spills for a single value, but - // they should form a contiguous run. Ignore all but the first. - if (CurrentDef == S.def()) - continue; - - CurrentDef = S.def(); - - assert(CurrentDef != PromiseAlloca && - "recorded spill use of promise alloca?"); - - if (auto *AI = dyn_cast(CurrentDef)) { - B.addFieldForAlloca(AI, &S); - } else { - Type *Ty = CurrentDef->getType(); - B.addField(Ty, None, &S); - } + for (auto &S : FrameData.Spills) { + FieldIDType Id = B.addField(S.first->getType(), None); + FrameData.setFieldIndex(S.first, Id); } B.finish(FrameTy); + FrameData.updateLayoutIndex(B); Shape.FrameAlign = B.getStructAlign(); Shape.FrameSize = B.getStructSize(); switch (Shape.ABI) { - // In the switch ABI, remember the field indices for the promise and - // switch-index fields. case coro::ABI::Switch: + // In the switch ABI, remember the switch-index field. Shape.SwitchLowering.IndexField = - B.getFieldIndex(*SwitchIndexFieldId); - Shape.SwitchLowering.PromiseField = - (PromiseAlloca ? B.getFieldIndex(*PromiseFieldId) : 0); + B.getLayoutFieldIndex(*SwitchIndexFieldId); // Also round the frame size up to a multiple of its alignment, as is // generally expected in C/C++. @@ -617,65 +810,246 @@ static StructType *buildFrameType(Function &F, coro::Shape &Shape, B.getStructAlign() <= Id->getStorageAlignment()); break; } + case coro::ABI::Async: { + Shape.AsyncLowering.FrameOffset = + alignTo(Shape.AsyncLowering.ContextHeaderSize, Shape.FrameAlign); + // Also make the final context size a multiple of the context alignment to + // make allocation easier for allocators. + Shape.AsyncLowering.ContextSize = + alignTo(Shape.AsyncLowering.FrameOffset + Shape.FrameSize, + Shape.AsyncLowering.getContextAlignment()); + if (Shape.AsyncLowering.getContextAlignment() < Shape.FrameAlign) { + report_fatal_error( + "The alignment requirment of frame variables cannot be higher than " + "the alignment of the async function context"); + } + break; + } } return FrameTy; } -// We use a pointer use visitor to discover if there are any writes into an -// alloca that dominates CoroBegin. If that is the case, insertSpills will copy -// the value from the alloca into the coroutine frame spill slot corresponding -// to that alloca. +// We use a pointer use visitor to track how an alloca is being used. +// The goal is to be able to answer the following three questions: +// 1. Should this alloca be allocated on the frame instead. +// 2. Could the content of the alloca be modified prior to CoroBegn, which would +// require copying the data from alloca to the frame after CoroBegin. +// 3. Is there any alias created for this alloca prior to CoroBegin, but used +// after CoroBegin. In that case, we will need to recreate the alias after +// CoroBegin based off the frame. To answer question 1, we track two things: +// a. List of all BasicBlocks that use this alloca or any of the aliases of +// the alloca. In the end, we check if there exists any two basic blocks that +// cross suspension points. If so, this alloca must be put on the frame. b. +// Whether the alloca or any alias of the alloca is escaped at some point, +// either by storing the address somewhere, or the address is used in a +// function call that might capture. If it's ever escaped, this alloca must be +// put on the frame conservatively. +// To answer quetion 2, we track through the variable MayWriteBeforeCoroBegin. +// Whenever a potential write happens, either through a store instruction, a +// function call or any of the memory intrinsics, we check whether this +// instruction is prior to CoroBegin. To answer question 3, we track the offsets +// of all aliases created for the alloca prior to CoroBegin but used after +// CoroBegin. llvm::Optional is used to be able to represent the case when the +// offset is unknown (e.g. when you have a PHINode that takes in different +// offset values). We cannot handle unknown offsets and will assert. This is the +// potential issue left out. An ideal solution would likely require a +// significant redesign. namespace { struct AllocaUseVisitor : PtrUseVisitor { using Base = PtrUseVisitor; AllocaUseVisitor(const DataLayout &DL, const DominatorTree &DT, - const CoroBeginInst &CB) - : PtrUseVisitor(DL), DT(DT), CoroBegin(CB) {} + const CoroBeginInst &CB, const SuspendCrossingInfo &Checker) + : PtrUseVisitor(DL), DT(DT), CoroBegin(CB), Checker(Checker) {} - // We are only interested in uses that dominate coro.begin. void visit(Instruction &I) { - if (DT.dominates(&I, &CoroBegin)) - Base::visit(I); + UserBBs.insert(I.getParent()); + Base::visit(I); + // If the pointer is escaped prior to CoroBegin, we have to assume it would + // be written into before CoroBegin as well. + if (PI.isEscaped() && !DT.dominates(&CoroBegin, PI.getEscapingInst())) { + MayWriteBeforeCoroBegin = true; + } } // We need to provide this overload as PtrUseVisitor uses a pointer based // visiting function. void visit(Instruction *I) { return visit(*I); } - void visitLoadInst(LoadInst &) {} // Good. Nothing to do. + void visitPHINode(PHINode &I) { + enqueueUsers(I); + handleAlias(I); + } + + void visitSelectInst(SelectInst &I) { + enqueueUsers(I); + handleAlias(I); + } + + void visitStoreInst(StoreInst &SI) { + // Regardless whether the alias of the alloca is the value operand or the + // pointer operand, we need to assume the alloca is been written. + handleMayWrite(SI); + + if (SI.getValueOperand() != U->get()) + return; + + // We are storing the pointer into a memory location, potentially escaping. + // As an optimization, we try to detect simple cases where it doesn't + // actually escape, for example: + // %ptr = alloca .. + // %addr = alloca .. + // store %ptr, %addr + // %x = load %addr + // .. + // If %addr is only used by loading from it, we could simply treat %x as + // another alias of %ptr, and not considering %ptr being escaped. + auto IsSimpleStoreThenLoad = [&]() { + auto *AI = dyn_cast(SI.getPointerOperand()); + // If the memory location we are storing to is not an alloca, it + // could be an alias of some other memory locations, which is difficult + // to analyze. + if (!AI) + return false; + // StoreAliases contains aliases of the memory location stored into. + SmallVector StoreAliases = {AI}; + while (!StoreAliases.empty()) { + Instruction *I = StoreAliases.pop_back_val(); + for (User *U : I->users()) { + // If we are loading from the memory location, we are creating an + // alias of the original pointer. + if (auto *LI = dyn_cast(U)) { + enqueueUsers(*LI); + handleAlias(*LI); + continue; + } + // If we are overriding the memory location, the pointer certainly + // won't escape. + if (auto *S = dyn_cast(U)) + if (S->getPointerOperand() == I) + continue; + if (auto *II = dyn_cast(U)) + if (II->isLifetimeStartOrEnd()) + continue; + // BitCastInst creats aliases of the memory location being stored + // into. + if (auto *BI = dyn_cast(U)) { + StoreAliases.push_back(BI); + continue; + } + return false; + } + } + + return true; + }; - // If the use is an operand, the pointer escaped and anything can write into - // that memory. If the use is the pointer, we are definitely writing into the - // alloca and therefore we need to copy. - void visitStoreInst(StoreInst &SI) { PI.setAborted(&SI); } + if (!IsSimpleStoreThenLoad()) + PI.setEscaped(&SI); + } - // Any other instruction that is not filtered out by PtrUseVisitor, will - // result in the copy. - void visitInstruction(Instruction &I) { PI.setAborted(&I); } + // All mem intrinsics modify the data. + void visitMemIntrinsic(MemIntrinsic &MI) { handleMayWrite(MI); } + + void visitBitCastInst(BitCastInst &BC) { + Base::visitBitCastInst(BC); + handleAlias(BC); + } + + void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { + Base::visitAddrSpaceCastInst(ASC); + handleAlias(ASC); + } + + void visitGetElementPtrInst(GetElementPtrInst &GEPI) { + // The base visitor will adjust Offset accordingly. + Base::visitGetElementPtrInst(GEPI); + handleAlias(GEPI); + } + + void visitCallBase(CallBase &CB) { + for (unsigned Op = 0, OpCount = CB.getNumArgOperands(); Op < OpCount; ++Op) + if (U->get() == CB.getArgOperand(Op) && !CB.doesNotCapture(Op)) + PI.setEscaped(&CB); + handleMayWrite(CB); + } + + bool getShouldLiveOnFrame() const { + if (!ShouldLiveOnFrame) + ShouldLiveOnFrame = computeShouldLiveOnFrame(); + return ShouldLiveOnFrame.getValue(); + } + + bool getMayWriteBeforeCoroBegin() const { return MayWriteBeforeCoroBegin; } + + DenseMap> getAliasesCopy() const { + assert(getShouldLiveOnFrame() && "This method should only be called if the " + "alloca needs to live on the frame."); + for (const auto &P : AliasOffetMap) + if (!P.second) + report_fatal_error("Unable to handle an alias with unknown offset " + "created before CoroBegin."); + return AliasOffetMap; + } private: const DominatorTree &DT; const CoroBeginInst &CoroBegin; -}; -} // namespace -static bool mightWriteIntoAllocaPtr(AllocaInst &A, const DominatorTree &DT, - const CoroBeginInst &CB) { - const DataLayout &DL = A.getModule()->getDataLayout(); - AllocaUseVisitor Visitor(DL, DT, CB); - auto PtrI = Visitor.visitPtr(A); - if (PtrI.isEscaped() || PtrI.isAborted()) { - auto *PointerEscapingInstr = PtrI.getEscapingInst() - ? PtrI.getEscapingInst() - : PtrI.getAbortingInst(); - if (PointerEscapingInstr) { - LLVM_DEBUG( - dbgs() << "AllocaInst copy was triggered by instruction: " - << *PointerEscapingInstr << "\n"); + const SuspendCrossingInfo &Checker; + // All alias to the original AllocaInst, created before CoroBegin and used + // after CoroBegin. Each entry contains the instruction and the offset in the + // original Alloca. They need to be recreated after CoroBegin off the frame. + DenseMap> AliasOffetMap{}; + SmallPtrSet UserBBs{}; + bool MayWriteBeforeCoroBegin{false}; + + mutable llvm::Optional ShouldLiveOnFrame{}; + + bool computeShouldLiveOnFrame() const { + if (PI.isEscaped()) + return true; + + for (auto *BB1 : UserBBs) + for (auto *BB2 : UserBBs) + if (Checker.hasPathCrossingSuspendPoint(BB1, BB2)) + return true; + + return false; + } + + void handleMayWrite(const Instruction &I) { + if (!DT.dominates(&CoroBegin, &I)) + MayWriteBeforeCoroBegin = true; + } + + bool usedAfterCoroBegin(Instruction &I) { + for (auto &U : I.uses()) + if (DT.dominates(&CoroBegin, U)) + return true; + return false; + } + + void handleAlias(Instruction &I) { + // We track all aliases created prior to CoroBegin but used after. + // These aliases may need to be recreated after CoroBegin if the alloca + // need to live on the frame. + if (DT.dominates(&CoroBegin, &I) || !usedAfterCoroBegin(I)) + return; + + if (!IsOffsetKnown) { + AliasOffetMap[&I].reset(); + } else { + auto Itr = AliasOffetMap.find(&I); + if (Itr == AliasOffetMap.end()) { + AliasOffetMap[&I] = Offset; + } else if (Itr->second.hasValue() && Itr->second.getValue() != Offset) { + // If we have seen two different possible values for this alias, we set + // it to empty. + AliasOffetMap[&I].reset(); + } } - return true; } - return false; -} +}; +} // namespace // We need to make room to insert a spill after initial PHIs, but before // catchswitch instruction. Placing it before violates the requirement that @@ -720,7 +1094,8 @@ static Instruction *splitBeforeCatchSwitch(CatchSwitchInst *CatchSwitch) { // whatever // // -static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { +static Instruction *insertSpills(const FrameDataInfo &FrameData, + coro::Shape &Shape) { auto *CB = Shape.CoroBegin; LLVMContext &C = CB->getContext(); IRBuilder<> Builder(CB->getNextNode()); @@ -729,32 +1104,13 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { auto *FramePtr = cast(Builder.CreateBitCast(CB, FramePtrTy, "FramePtr")); DominatorTree DT(*CB->getFunction()); - - Value *CurrentValue = nullptr; - BasicBlock *CurrentBlock = nullptr; - Value *CurrentReload = nullptr; - - // Proper field number will be read from field definition. - unsigned Index = InvalidFieldIndex; - - // We need to keep track of any allocas that need "spilling" - // since they will live in the coroutine frame now, all access to them - // need to be changed, not just the access across suspend points - // we remember allocas and their indices to be handled once we processed - // all the spills. - SmallVector, 4> Allocas; - - // Promise alloca (if present) doesn't show in the spills and has a - // special field number. - if (auto *PromiseAlloca = Shape.getPromiseAlloca()) { - assert(Shape.ABI == coro::ABI::Switch); - Allocas.emplace_back(PromiseAlloca, Shape.getPromiseField()); - } + SmallDenseMap DbgPtrAllocaCache; // Create a GEP with the given index into the coroutine frame for the original // value Orig. Appends an extra 0 index for array-allocas, preserving the // original type. - auto GetFramePointer = [&](uint32_t Index, Value *Orig) -> Value * { + auto GetFramePointer = [&](Value *Orig) -> Value * { + FieldIDType Index = FrameData.getFieldIndex(Orig); SmallVector Indices = { ConstantInt::get(Type::getInt32Ty(C), 0), ConstantInt::get(Type::getInt32Ty(C), Index), @@ -771,147 +1127,145 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { } } - return Builder.CreateInBoundsGEP(FrameTy, FramePtr, Indices); - }; - - // Create a load instruction to reload the spilled value from the coroutine - // frame. Populates the Value pointer reference provided with the frame GEP. - auto CreateReload = [&](Instruction *InsertBefore, Value *&G) { - assert(Index != InvalidFieldIndex && "accessing unassigned field number"); - Builder.SetInsertPoint(InsertBefore); - - G = GetFramePointer(Index, CurrentValue); - G->setName(CurrentValue->getName() + Twine(".reload.addr")); - - return isa(CurrentValue) - ? G - : Builder.CreateLoad(FrameTy->getElementType(Index), G, - CurrentValue->getName() + Twine(".reload")); + auto GEP = cast( + Builder.CreateInBoundsGEP(FrameTy, FramePtr, Indices)); + if (isa(Orig)) { + // If the type of GEP is not equal to the type of AllocaInst, it implies + // that the AllocaInst may be reused in the Frame slot of other + // AllocaInst. So We cast GEP to the AllocaInst here to re-use + // the Frame storage. + // + // Note: If we change the strategy dealing with alignment, we need to refine + // this casting. + if (GEP->getResultElementType() != Orig->getType()) + return Builder.CreateBitCast(GEP, Orig->getType(), + Orig->getName() + Twine(".cast")); + } + return GEP; }; - Value *GEP = nullptr, *CurrentGEP = nullptr; - for (auto const &E : Spills) { - // If we have not seen the value, generate a spill. - if (CurrentValue != E.def()) { - CurrentValue = E.def(); - CurrentBlock = nullptr; - CurrentReload = nullptr; - - Index = E.fieldIndex(); - - if (auto *AI = dyn_cast(CurrentValue)) { - // Spilled AllocaInst will be replaced with GEP from the coroutine frame - // there is no spill required. - Allocas.emplace_back(AI, Index); - if (!AI->isStaticAlloca()) - report_fatal_error("Coroutines cannot handle non static allocas yet"); + for (auto const &E : FrameData.Spills) { + Value *Def = E.first; + // Create a store instruction storing the value into the + // coroutine frame. + Instruction *InsertPt = nullptr; + if (auto *Arg = dyn_cast(Def)) { + // For arguments, we will place the store instruction right after + // the coroutine frame pointer instruction, i.e. bitcast of + // coro.begin from i8* to %f.frame*. + InsertPt = FramePtr->getNextNode(); + + // If we're spilling an Argument, make sure we clear 'nocapture' + // from the coroutine function. + Arg->getParent()->removeParamAttr(Arg->getArgNo(), Attribute::NoCapture); + + } else if (auto *CSI = dyn_cast(Def)) { + // Don't spill immediately after a suspend; splitting assumes + // that the suspend will be followed by a branch. + InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHI(); + } else { + auto *I = cast(Def); + if (!DT.dominates(CB, I)) { + // If it is not dominated by CoroBegin, then spill should be + // inserted immediately after CoroFrame is computed. + InsertPt = FramePtr->getNextNode(); + } else if (auto *II = dyn_cast(I)) { + // If we are spilling the result of the invoke instruction, split + // the normal edge and insert the spill in the new block. + auto *NewBB = SplitEdge(II->getParent(), II->getNormalDest()); + InsertPt = NewBB->getTerminator(); + } else if (isa(I)) { + // Skip the PHINodes and EH pads instructions. + BasicBlock *DefBlock = I->getParent(); + if (auto *CSI = dyn_cast(DefBlock->getTerminator())) + InsertPt = splitBeforeCatchSwitch(CSI); + else + InsertPt = &*DefBlock->getFirstInsertionPt(); } else { - // Otherwise, create a store instruction storing the value into the - // coroutine frame. - - Instruction *InsertPt = nullptr; - if (auto Arg = dyn_cast(CurrentValue)) { - // For arguments, we will place the store instruction right after - // the coroutine frame pointer instruction, i.e. bitcast of - // coro.begin from i8* to %f.frame*. - InsertPt = FramePtr->getNextNode(); - - // If we're spilling an Argument, make sure we clear 'nocapture' - // from the coroutine function. - Arg->getParent()->removeParamAttr(Arg->getArgNo(), - Attribute::NoCapture); - - } else if (auto *II = dyn_cast(CurrentValue)) { - // If we are spilling the result of the invoke instruction, split the - // normal edge and insert the spill in the new block. - auto NewBB = SplitEdge(II->getParent(), II->getNormalDest()); - InsertPt = NewBB->getTerminator(); - } else if (isa(CurrentValue)) { - // Skip the PHINodes and EH pads instructions. - BasicBlock *DefBlock = cast(E.def())->getParent(); - if (auto *CSI = dyn_cast(DefBlock->getTerminator())) - InsertPt = splitBeforeCatchSwitch(CSI); - else - InsertPt = &*DefBlock->getFirstInsertionPt(); - } else if (auto CSI = dyn_cast(CurrentValue)) { - // Don't spill immediately after a suspend; splitting assumes - // that the suspend will be followed by a branch. - InsertPt = CSI->getParent()->getSingleSuccessor()->getFirstNonPHI(); - } else { - auto *I = cast(E.def()); - assert(!I->isTerminator() && "unexpected terminator"); - // For all other values, the spill is placed immediately after - // the definition. - if (DT.dominates(CB, I)) { - InsertPt = I->getNextNode(); - } else { - // Unless, it is not dominated by CoroBegin, then it will be - // inserted immediately after CoroFrame is computed. - InsertPt = FramePtr->getNextNode(); - } - } - - Builder.SetInsertPoint(InsertPt); - auto *G = Builder.CreateConstInBoundsGEP2_32( - FrameTy, FramePtr, 0, Index, - CurrentValue->getName() + Twine(".spill.addr")); - Builder.CreateStore(CurrentValue, G); + assert(!I->isTerminator() && "unexpected terminator"); + // For all other values, the spill is placed immediately after + // the definition. + InsertPt = I->getNextNode(); } } - // If we have not seen the use block, generate a reload in it. - if (CurrentBlock != E.userBlock()) { - CurrentBlock = E.userBlock(); - CurrentReload = CreateReload(&*CurrentBlock->getFirstInsertionPt(), GEP); - } + auto Index = FrameData.getFieldIndex(Def); + Builder.SetInsertPoint(InsertPt); + auto *G = Builder.CreateConstInBoundsGEP2_32( + FrameTy, FramePtr, 0, Index, Def->getName() + Twine(".spill.addr")); + Builder.CreateStore(Def, G); + + BasicBlock *CurrentBlock = nullptr; + Value *CurrentReload = nullptr; + for (auto *U : E.second) { + // If we have not seen the use block, create a load instruction to reload + // the spilled value from the coroutine frame. Populates the Value pointer + // reference provided with the frame GEP. + if (CurrentBlock != U->getParent()) { + CurrentBlock = U->getParent(); + Builder.SetInsertPoint(&*CurrentBlock->getFirstInsertionPt()); + + auto *GEP = GetFramePointer(E.first); + GEP->setName(E.first->getName() + Twine(".reload.addr")); + CurrentReload = Builder.CreateLoad( + FrameTy->getElementType(FrameData.getFieldIndex(E.first)), GEP, + E.first->getName() + Twine(".reload")); + + TinyPtrVector DIs = FindDbgDeclareUses(Def); + for (DbgDeclareInst *DDI : DIs) { + bool AllowUnresolved = false; + // This dbg.declare is preserved for all coro-split function + // fragments. It will be unreachable in the main function, and + // processed by coro::salvageDebugInfo() by CoroCloner. + DIBuilder(*CurrentBlock->getParent()->getParent(), AllowUnresolved) + .insertDeclare(CurrentReload, DDI->getVariable(), + DDI->getExpression(), DDI->getDebugLoc(), + &*Builder.GetInsertPoint()); + // This dbg.declare is for the main function entry point. It + // will be deleted in all coro-split functions. + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI); + } + } - // If we have a single edge PHINode, remove it and replace it with a reload - // from the coroutine frame. (We already took care of multi edge PHINodes - // by rewriting them in the rewritePHIs function). - if (auto *PN = dyn_cast(E.user())) { - assert(PN->getNumIncomingValues() == 1 && "unexpected number of incoming " - "values in the PHINode"); - PN->replaceAllUsesWith(CurrentReload); - PN->eraseFromParent(); - continue; - } + // If we have a single edge PHINode, remove it and replace it with a + // reload from the coroutine frame. (We already took care of multi edge + // PHINodes by rewriting them in the rewritePHIs function). + if (auto *PN = dyn_cast(U)) { + assert(PN->getNumIncomingValues() == 1 && + "unexpected number of incoming " + "values in the PHINode"); + PN->replaceAllUsesWith(CurrentReload); + PN->eraseFromParent(); + continue; + } - // If we have not seen this GEP instruction, migrate any dbg.declare from - // the alloca to it. - if (CurrentGEP != GEP) { - CurrentGEP = GEP; - TinyPtrVector DIs = FindDbgDeclareUses(CurrentValue); - if (!DIs.empty()) - DIBuilder(*CurrentBlock->getParent()->getParent(), - /*AllowUnresolved*/ false) - .insertDeclare(CurrentGEP, DIs.front()->getVariable(), - DIs.front()->getExpression(), - DIs.front()->getDebugLoc(), DIs.front()); + // Replace all uses of CurrentValue in the current instruction with + // reload. + U->replaceUsesOfWith(Def, CurrentReload); } - - // Replace all uses of CurrentValue in the current instruction with reload. - E.user()->replaceUsesOfWith(CurrentValue, CurrentReload); } BasicBlock *FramePtrBB = FramePtr->getParent(); auto SpillBlock = - FramePtrBB->splitBasicBlock(FramePtr->getNextNode(), "AllocaSpillBB"); + FramePtrBB->splitBasicBlock(FramePtr->getNextNode(), "AllocaSpillBB"); SpillBlock->splitBasicBlock(&SpillBlock->front(), "PostSpill"); Shape.AllocaSpillBlock = SpillBlock; // retcon and retcon.once lowering assumes all uses have been sunk. - if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce) { + if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce || + Shape.ABI == coro::ABI::Async) { // If we found any allocas, replace all of their remaining uses with Geps. Builder.SetInsertPoint(&SpillBlock->front()); - for (auto &P : Allocas) { - auto *G = GetFramePointer(P.second, P.first); + for (const auto &P : FrameData.Allocas) { + AllocaInst *Alloca = P.Alloca; + auto *G = GetFramePointer(Alloca); // We are not using ReplaceInstWithInst(P.first, cast(G)) // here, as we are changing location of the instruction. - G->takeName(P.first); - P.first->replaceAllUsesWith(G); - P.first->eraseFromParent(); + G->takeName(Alloca); + Alloca->replaceAllUsesWith(G); + Alloca->eraseFromParent(); } return FramePtr; } @@ -921,49 +1275,63 @@ static Instruction *insertSpills(const SpillInfo &Spills, coro::Shape &Shape) { // we also delete the original dbg.declare and replace other uses with undef. // Note: We cannot replace the alloca with GEP instructions indiscriminately, // as some of the uses may not be dominated by CoroBegin. - bool MightNeedToCopy = false; Builder.SetInsertPoint(&Shape.AllocaSpillBlock->front()); SmallVector UsersToUpdate; - for (auto &P : Allocas) { - AllocaInst *const A = P.first; - - for (auto *DI : FindDbgDeclareUses(A)) - DI->eraseFromParent(); - replaceDbgUsesWithUndef(A); - + for (const auto &A : FrameData.Allocas) { + AllocaInst *Alloca = A.Alloca; UsersToUpdate.clear(); - for (User *U : A->users()) { + for (User *U : Alloca->users()) { auto *I = cast(U); if (DT.dominates(CB, I)) UsersToUpdate.push_back(I); - else - MightNeedToCopy = true; - } - if (!UsersToUpdate.empty()) { - auto *G = GetFramePointer(P.second, A); - G->takeName(A); - for (Instruction *I : UsersToUpdate) - I->replaceUsesOfWith(A, G); } - } - // If we discovered such uses not dominated by CoroBegin, see if any of them - // preceed coro begin and have instructions that can modify the - // value of the alloca and therefore would require a copying the value into - // the spill slot in the coroutine frame. - if (MightNeedToCopy) { - Builder.SetInsertPoint(FramePtr->getNextNode()); - - for (auto &P : Allocas) { - AllocaInst *const A = P.first; - if (mightWriteIntoAllocaPtr(*A, DT, *CB)) { - if (A->isArrayAllocation()) - report_fatal_error( - "Coroutines cannot handle copying of array allocas yet"); + if (UsersToUpdate.empty()) + continue; + auto *G = GetFramePointer(Alloca); + G->setName(Alloca->getName() + Twine(".reload.addr")); + + SmallPtrSet SeenDbgBBs; + TinyPtrVector DIs = FindDbgDeclareUses(Alloca); + if (!DIs.empty()) + DIBuilder(*Alloca->getModule(), + /*AllowUnresolved*/ false) + .insertDeclare(G, DIs.front()->getVariable(), + DIs.front()->getExpression(), + DIs.front()->getDebugLoc(), DIs.front()); + for (auto *DI : FindDbgDeclareUses(Alloca)) + DI->eraseFromParent(); + replaceDbgUsesWithUndef(Alloca); - auto *G = GetFramePointer(P.second, A); - auto *Value = Builder.CreateLoad(A->getAllocatedType(), A); - Builder.CreateStore(Value, G); - } + for (Instruction *I : UsersToUpdate) + I->replaceUsesOfWith(Alloca, G); + } + Builder.SetInsertPoint(FramePtr->getNextNode()); + for (const auto &A : FrameData.Allocas) { + AllocaInst *Alloca = A.Alloca; + if (A.MayWriteBeforeCoroBegin) { + // isEscaped really means potentially modified before CoroBegin. + if (Alloca->isArrayAllocation()) + report_fatal_error( + "Coroutines cannot handle copying of array allocas yet"); + + auto *G = GetFramePointer(Alloca); + auto *Value = Builder.CreateLoad(Alloca->getAllocatedType(), Alloca); + Builder.CreateStore(Value, G); + } + // For each alias to Alloca created before CoroBegin but used after + // CoroBegin, we recreate them after CoroBegin by appplying the offset + // to the pointer in the frame. + for (const auto &Alias : A.Aliases) { + auto *FramePtr = GetFramePointer(Alloca); + auto *FramePtrRaw = + Builder.CreateBitCast(FramePtr, Type::getInt8PtrTy(C)); + auto *AliasPtr = Builder.CreateGEP( + FramePtrRaw, + ConstantInt::get(Type::getInt64Ty(C), Alias.second.getValue())); + auto *AliasPtrTyped = + Builder.CreateBitCast(AliasPtr, Alias.first->getType()); + Alias.first->replaceUsesWithIf( + AliasPtrTyped, [&](Use &U) { return DT.dominates(CB, U); }); } } return FramePtr; @@ -984,15 +1352,14 @@ static void setUnwindEdgeTo(Instruction *TI, BasicBlock *Succ) { // Replaces all uses of OldPred with the NewPred block in all PHINodes in a // block. static void updatePhiNodes(BasicBlock *DestBB, BasicBlock *OldPred, - BasicBlock *NewPred, - PHINode *LandingPadReplacement) { + BasicBlock *NewPred, PHINode *Until = nullptr) { unsigned BBIdx = 0; for (BasicBlock::iterator I = DestBB->begin(); isa(I); ++I) { PHINode *PN = cast(I); // We manually update the LandingPadReplacement PHINode and it is the last // PHI Node. So, if we find it, we are done. - if (LandingPadReplacement == PN) + if (Until == PN) break; // Reuse the previous value of BBIdx if it lines up. In cases where we @@ -1041,6 +1408,101 @@ static BasicBlock *ehAwareSplitEdge(BasicBlock *BB, BasicBlock *Succ, return NewBB; } +// Moves the values in the PHIs in SuccBB that correspong to PredBB into a new +// PHI in InsertedBB. +static void movePHIValuesToInsertedBlock(BasicBlock *SuccBB, + BasicBlock *InsertedBB, + BasicBlock *PredBB, + PHINode *UntilPHI = nullptr) { + auto *PN = cast(&SuccBB->front()); + do { + int Index = PN->getBasicBlockIndex(InsertedBB); + Value *V = PN->getIncomingValue(Index); + PHINode *InputV = PHINode::Create( + V->getType(), 1, V->getName() + Twine(".") + SuccBB->getName(), + &InsertedBB->front()); + InputV->addIncoming(V, PredBB); + PN->setIncomingValue(Index, InputV); + PN = dyn_cast(PN->getNextNode()); + } while (PN != UntilPHI); +} + +// Rewrites the PHI Nodes in a cleanuppad. +static void rewritePHIsForCleanupPad(BasicBlock *CleanupPadBB, + CleanupPadInst *CleanupPad) { + // For every incoming edge to a CleanupPad we will create a new block holding + // all incoming values in single-value PHI nodes. We will then create another + // block to act as a dispather (as all unwind edges for related EH blocks + // must be the same). + // + // cleanuppad: + // %2 = phi i32[%0, %catchswitch], [%1, %catch.1] + // %3 = cleanuppad within none [] + // + // It will create: + // + // cleanuppad.corodispatch + // %2 = phi i8[0, %catchswitch], [1, %catch.1] + // %3 = cleanuppad within none [] + // switch i8 % 2, label %unreachable + // [i8 0, label %cleanuppad.from.catchswitch + // i8 1, label %cleanuppad.from.catch.1] + // cleanuppad.from.catchswitch: + // %4 = phi i32 [%0, %catchswitch] + // br %label cleanuppad + // cleanuppad.from.catch.1: + // %6 = phi i32 [%1, %catch.1] + // br %label cleanuppad + // cleanuppad: + // %8 = phi i32 [%4, %cleanuppad.from.catchswitch], + // [%6, %cleanuppad.from.catch.1] + + // Unreachable BB, in case switching on an invalid value in the dispatcher. + auto *UnreachBB = BasicBlock::Create( + CleanupPadBB->getContext(), "unreachable", CleanupPadBB->getParent()); + IRBuilder<> Builder(UnreachBB); + Builder.CreateUnreachable(); + + // Create a new cleanuppad which will be the dispatcher. + auto *NewCleanupPadBB = + BasicBlock::Create(CleanupPadBB->getContext(), + CleanupPadBB->getName() + Twine(".corodispatch"), + CleanupPadBB->getParent(), CleanupPadBB); + Builder.SetInsertPoint(NewCleanupPadBB); + auto *SwitchType = Builder.getInt8Ty(); + auto *SetDispatchValuePN = + Builder.CreatePHI(SwitchType, pred_size(CleanupPadBB)); + CleanupPad->removeFromParent(); + CleanupPad->insertAfter(SetDispatchValuePN); + auto *SwitchOnDispatch = Builder.CreateSwitch(SetDispatchValuePN, UnreachBB, + pred_size(CleanupPadBB)); + + int SwitchIndex = 0; + SmallVector Preds(predecessors(CleanupPadBB)); + for (BasicBlock *Pred : Preds) { + // Create a new cleanuppad and move the PHI values to there. + auto *CaseBB = BasicBlock::Create(CleanupPadBB->getContext(), + CleanupPadBB->getName() + + Twine(".from.") + Pred->getName(), + CleanupPadBB->getParent(), CleanupPadBB); + updatePhiNodes(CleanupPadBB, Pred, CaseBB); + CaseBB->setName(CleanupPadBB->getName() + Twine(".from.") + + Pred->getName()); + Builder.SetInsertPoint(CaseBB); + Builder.CreateBr(CleanupPadBB); + movePHIValuesToInsertedBlock(CleanupPadBB, CaseBB, NewCleanupPadBB); + + // Update this Pred to the new unwind point. + setUnwindEdgeTo(Pred->getTerminator(), NewCleanupPadBB); + + // Setup the switch in the dispatcher. + auto *SwitchConstant = ConstantInt::get(SwitchType, SwitchIndex); + SetDispatchValuePN->addIncoming(SwitchConstant, Pred); + SwitchOnDispatch->addCase(SwitchConstant, CaseBB); + SwitchIndex++; + } +} + static void rewritePHIs(BasicBlock &BB) { // For every incoming edge we will create a block holding all // incoming values in a single PHI nodes. @@ -1063,6 +1525,24 @@ static void rewritePHIs(BasicBlock &BB) { // TODO: Simplify PHINodes in the basic block to remove duplicate // predecessors. + // Special case for CleanupPad: all EH blocks must have the same unwind edge + // so we need to create an additional "dispatcher" block. + if (auto *CleanupPad = + dyn_cast_or_null(BB.getFirstNonPHI())) { + SmallVector Preds(predecessors(&BB)); + for (BasicBlock *Pred : Preds) { + if (CatchSwitchInst *CS = + dyn_cast(Pred->getTerminator())) { + // CleanupPad with a CatchSwitch predecessor: therefore this is an + // unwind destination that needs to be handle specially. + assert(CS->getUnwindDest() == &BB); + (void)CS; + rewritePHIsForCleanupPad(&BB, CleanupPad); + return; + } + } + } + LandingPadInst *LandingPad = nullptr; PHINode *ReplPHI = nullptr; if ((LandingPad = dyn_cast_or_null(BB.getFirstNonPHI()))) { @@ -1076,22 +1556,14 @@ static void rewritePHIs(BasicBlock &BB) { // ehAwareSplitEdge cloned it in the transition blocks. } - SmallVector Preds(pred_begin(&BB), pred_end(&BB)); + SmallVector Preds(predecessors(&BB)); for (BasicBlock *Pred : Preds) { auto *IncomingBB = ehAwareSplitEdge(Pred, &BB, LandingPad, ReplPHI); IncomingBB->setName(BB.getName() + Twine(".from.") + Pred->getName()); - auto *PN = cast(&BB.front()); - do { - int Index = PN->getBasicBlockIndex(IncomingBB); - Value *V = PN->getIncomingValue(Index); - PHINode *InputV = PHINode::Create( - V->getType(), 1, V->getName() + Twine(".") + BB.getName(), - &IncomingBB->front()); - InputV->addIncoming(V, Pred); - PN->setIncomingValue(Index, InputV); - PN = dyn_cast(PN->getNextNode()); - } while (PN != ReplPHI); // ReplPHI is either null or the PHI that replaced - // the landing pad. + + // Stop the moving of values at ReplPHI, as this is either null or the PHI + // that replaced the landing pad. + movePHIValuesToInsertedBlock(&BB, IncomingBB, Pred, ReplPHI); } if (LandingPad) { @@ -1130,39 +1602,32 @@ static bool isCoroutineStructureIntrinsic(Instruction &I) { // For every use of the value that is across suspend point, recreate that value // after a suspend point. static void rewriteMaterializableInstructions(IRBuilder<> &IRB, - SpillInfo const &Spills) { - BasicBlock *CurrentBlock = nullptr; - Instruction *CurrentMaterialization = nullptr; - Instruction *CurrentDef = nullptr; - - for (auto const &E : Spills) { - // If it is a new definition, update CurrentXXX variables. - if (CurrentDef != E.def()) { - CurrentDef = cast(E.def()); - CurrentBlock = nullptr; - CurrentMaterialization = nullptr; - } - - // If we have not seen this block, materialize the value. - if (CurrentBlock != E.userBlock()) { - CurrentBlock = E.userBlock(); - CurrentMaterialization = cast(CurrentDef)->clone(); - CurrentMaterialization->setName(CurrentDef->getName()); - CurrentMaterialization->insertBefore( - &*CurrentBlock->getFirstInsertionPt()); - } - - if (auto *PN = dyn_cast(E.user())) { - assert(PN->getNumIncomingValues() == 1 && "unexpected number of incoming " - "values in the PHINode"); - PN->replaceAllUsesWith(CurrentMaterialization); - PN->eraseFromParent(); - continue; + const SpillInfo &Spills) { + for (const auto &E : Spills) { + Value *Def = E.first; + BasicBlock *CurrentBlock = nullptr; + Instruction *CurrentMaterialization = nullptr; + for (Instruction *U : E.second) { + // If we have not seen this block, materialize the value. + if (CurrentBlock != U->getParent()) { + CurrentBlock = U->getParent(); + CurrentMaterialization = cast(Def)->clone(); + CurrentMaterialization->setName(Def->getName()); + CurrentMaterialization->insertBefore( + &*CurrentBlock->getFirstInsertionPt()); + } + if (auto *PN = dyn_cast(U)) { + assert(PN->getNumIncomingValues() == 1 && + "unexpected number of incoming " + "values in the PHINode"); + PN->replaceAllUsesWith(CurrentMaterialization); + PN->eraseFromParent(); + continue; + } + // Replace all uses of Def in the current instruction with the + // CurrentMaterialization for the block. + U->replaceUsesOfWith(Def, CurrentMaterialization); } - - // Replace all uses of CurrentDef in the current instruction with the - // CurrentMaterialization for the block. - E.user()->replaceUsesOfWith(CurrentDef, CurrentMaterialization); } } @@ -1501,7 +1966,8 @@ static void eliminateSwiftError(Function &F, coro::Shape &Shape) { /// retcon and retcon.once conventions assume that all spill uses can be sunk /// after the coro.begin intrinsic. -static void sinkSpillUsesAfterCoroBegin(Function &F, const SpillInfo &Spills, +static void sinkSpillUsesAfterCoroBegin(Function &F, + const FrameDataInfo &FrameData, CoroBeginInst *CoroBegin) { DominatorTree Dom(F); @@ -1509,9 +1975,8 @@ static void sinkSpillUsesAfterCoroBegin(Function &F, const SpillInfo &Spills, SmallVector Worklist; // Collect all users that precede coro.begin. - for (auto const &Entry : Spills) { - auto *SpillDef = Entry.def(); - for (User *U : SpillDef->users()) { + for (auto *Def : FrameData.getAllDefs()) { + for (User *U : Def->users()) { auto Inst = cast(U); if (Inst->getParent() != CoroBegin->getParent() || Dom.dominates(CoroBegin, Inst)) @@ -1522,8 +1987,7 @@ static void sinkSpillUsesAfterCoroBegin(Function &F, const SpillInfo &Spills, } // Recursively collect users before coro.begin. while (!Worklist.empty()) { - auto *Def = Worklist.back(); - Worklist.pop_back(); + auto *Def = Worklist.pop_back_val(); for (User *U : Def->users()) { auto Inst = cast(U); if (Dom.dominates(CoroBegin, Inst)) @@ -1535,17 +1999,14 @@ static void sinkSpillUsesAfterCoroBegin(Function &F, const SpillInfo &Spills, // Sort by dominance. SmallVector InsertionList(ToMove.begin(), ToMove.end()); - std::sort(InsertionList.begin(), InsertionList.end(), - [&Dom](Instruction *A, Instruction *B) -> bool { - // If a dominates b it should preceed (<) b. - return Dom.dominates(A, B); - }); + llvm::sort(InsertionList, [&Dom](Instruction *A, Instruction *B) -> bool { + // If a dominates b it should preceed (<) b. + return Dom.dominates(A, B); + }); Instruction *InsertPt = CoroBegin->getNextNode(); for (Instruction *Inst : InsertionList) Inst->moveBefore(InsertPt); - - return; } /// For each local variable that all of its user are only used inside one of @@ -1567,56 +2028,186 @@ static void sinkLifetimeStartMarkers(Function &F, coro::Shape &Shape, } for (Instruction &I : instructions(F)) { - if (!isa(&I)) + AllocaInst* AI = dyn_cast(&I); + if (!AI) continue; for (BasicBlock *DomBB : DomSet) { bool Valid = true; - SmallVector BCInsts; + SmallVector Lifetimes; - auto isUsedByLifetimeStart = [&](Instruction *I) { - if (isa(I) && I->hasOneUse()) - if (auto *IT = dyn_cast(I->user_back())) - return IT->getIntrinsicID() == Intrinsic::lifetime_start; + auto isLifetimeStart = [](Instruction* I) { + if (auto* II = dyn_cast(I)) + return II->getIntrinsicID() == Intrinsic::lifetime_start; return false; }; - for (User *U : I.users()) { + auto collectLifetimeStart = [&](Instruction *U, AllocaInst *AI) { + if (isLifetimeStart(U)) { + Lifetimes.push_back(U); + return true; + } + if (!U->hasOneUse() || U->stripPointerCasts() != AI) + return false; + if (isLifetimeStart(U->user_back())) { + Lifetimes.push_back(U->user_back()); + return true; + } + return false; + }; + + for (User *U : AI->users()) { Instruction *UI = cast(U); // For all users except lifetime.start markers, if they are all // dominated by one of the basic blocks and do not cross // suspend points as well, then there is no need to spill the // instruction. if (!DT.dominates(DomBB, UI->getParent()) || - Checker.isDefinitionAcrossSuspend(DomBB, U)) { - // Skip bitcast used by lifetime.start markers. - if (isUsedByLifetimeStart(UI)) { - BCInsts.push_back(UI); + Checker.isDefinitionAcrossSuspend(DomBB, UI)) { + // Skip lifetime.start, GEP and bitcast used by lifetime.start + // markers. + if (collectLifetimeStart(UI, AI)) continue; - } Valid = false; break; } } // Sink lifetime.start markers to dominate block when they are // only used outside the region. - if (Valid && BCInsts.size() != 0) { - auto *NewBitcast = BCInsts[0]->clone(); - auto *NewLifetime = cast(BCInsts[0]->user_back())->clone(); - NewLifetime->replaceUsesOfWith(BCInsts[0], NewBitcast); - NewBitcast->insertBefore(DomBB->getTerminator()); + if (Valid && Lifetimes.size() != 0) { + // May be AI itself, when the type of AI is i8* + auto *NewBitCast = [&](AllocaInst *AI) -> Value* { + if (isa(Lifetimes[0]->getOperand(1))) + return AI; + auto *Int8PtrTy = Type::getInt8PtrTy(F.getContext()); + return CastInst::Create(Instruction::BitCast, AI, Int8PtrTy, "", + DomBB->getTerminator()); + }(AI); + + auto *NewLifetime = Lifetimes[0]->clone(); + NewLifetime->replaceUsesOfWith(NewLifetime->getOperand(1), NewBitCast); NewLifetime->insertBefore(DomBB->getTerminator()); // All the outsided lifetime.start markers are no longer necessary. - for (Instruction *S : BCInsts) { - S->user_back()->eraseFromParent(); - } + for (Instruction *S : Lifetimes) + S->eraseFromParent(); + break; } } } } +static void collectFrameAllocas(Function &F, coro::Shape &Shape, + const SuspendCrossingInfo &Checker, + SmallVectorImpl &Allocas) { + // Collect lifetime.start info for each alloca. + using LifetimeStart = SmallPtrSet; + llvm::DenseMap> LifetimeMap; + for (Instruction &I : instructions(F)) { + auto *II = dyn_cast(&I); + if (!II || II->getIntrinsicID() != Intrinsic::lifetime_start) + continue; + + if (auto *OpInst = dyn_cast(II->getOperand(1))) { + if (auto *AI = dyn_cast(OpInst->stripPointerCasts())) { + + if (LifetimeMap.find(AI) == LifetimeMap.end()) + LifetimeMap[AI] = std::make_unique(); + LifetimeMap[AI]->insert(isa(OpInst) ? II : OpInst); + } + } + } + + for (Instruction &I : instructions(F)) { + auto *AI = dyn_cast(&I); + if (!AI) + continue; + // The PromiseAlloca will be specially handled since it needs to be in a + // fixed position in the frame. + if (AI == Shape.SwitchLowering.PromiseAlloca) { + continue; + } + bool ShouldLiveOnFrame = false; + auto Iter = LifetimeMap.find(AI); + if (Iter != LifetimeMap.end()) { + // Check against lifetime.start if the instruction has the info. + for (User *U : I.users()) { + for (auto *S : *Iter->second) + if ((ShouldLiveOnFrame = Checker.isDefinitionAcrossSuspend(*S, U))) + break; + if (ShouldLiveOnFrame) + break; + } + if (!ShouldLiveOnFrame) + continue; + } + // At this point, either ShouldLiveOnFrame is true or we didn't have + // lifetime information. We will need to rely on more precise pointer + // tracking. + DominatorTree DT(F); + AllocaUseVisitor Visitor{F.getParent()->getDataLayout(), DT, + *Shape.CoroBegin, Checker}; + Visitor.visitPtr(*AI); + if (!Visitor.getShouldLiveOnFrame()) + continue; + Allocas.emplace_back(AI, Visitor.getAliasesCopy(), + Visitor.getMayWriteBeforeCoroBegin()); + } +} + +void coro::salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromFramePtr) { + Function *F = DDI->getFunction(); + IRBuilder<> Builder(F->getContext()); + auto InsertPt = F->getEntryBlock().getFirstInsertionPt(); + while (isa(InsertPt)) + ++InsertPt; + Builder.SetInsertPoint(&F->getEntryBlock(), InsertPt); + DIExpression *Expr = DDI->getExpression(); + // Follow the pointer arithmetic all the way to the incoming + // function argument and convert into a DIExpression. + Value *Storage = DDI->getAddress(); + while (Storage) { + if (auto *LdInst = dyn_cast(Storage)) { + Storage = LdInst->getOperand(0); + } else if (auto *StInst = dyn_cast(Storage)) { + Storage = StInst->getOperand(0); + } else if (auto *GEPInst = dyn_cast(Storage)) { + Expr = llvm::salvageDebugInfoImpl(*GEPInst, Expr, + /*WithStackValue=*/false); + Storage = GEPInst->getOperand(0); + } else if (auto *BCInst = dyn_cast(Storage)) + Storage = BCInst->getOperand(0); + else + break; + } + // Store a pointer to the coroutine frame object in an alloca so it + // is available throughout the function when producing unoptimized + // code. Extending the lifetime this way is correct because the + // variable has been declared by a dbg.declare intrinsic. + if (auto Arg = dyn_cast_or_null(Storage)) { + auto &Cached = DbgPtrAllocaCache[Storage]; + if (!Cached) { + Cached = Builder.CreateAlloca(Storage->getType(), 0, nullptr, + Arg->getName() + ".debug"); + Builder.CreateStore(Storage, Cached); + } + Storage = Cached; + } + // The FramePtr object adds one extra layer of indirection that + // needs to be unwrapped. + if (LoadFromFramePtr) + Expr = DIExpression::prepend(Expr, DIExpression::DerefBefore); + auto &VMContext = DDI->getFunction()->getContext(); + DDI->setOperand( + 0, MetadataAsValue::get(VMContext, ValueAsMetadata::get(Storage))); + DDI->setOperand(2, MetadataAsValue::get(VMContext, Expr)); + if (auto *InsertPt = dyn_cast_or_null(Storage)) + DDI->moveAfter(InsertPt); +} + void coro::buildCoroutineFrame(Function &F, Shape &Shape) { eliminateSwiftError(F, Shape); @@ -1635,9 +2226,26 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { } // Put CoroEnds into their own blocks. - for (CoroEndInst *CE : Shape.CoroEnds) + for (AnyCoroEndInst *CE : Shape.CoroEnds) { splitAround(CE, "CoroEnd"); + // Emit the musttail call function in a new block before the CoroEnd. + // We do this here so that the right suspend crossing info is computed for + // the uses of the musttail call function call. (Arguments to the coro.end + // instructions would be ignored) + if (auto *AsyncEnd = dyn_cast(CE)) { + auto *MustTailCallFn = AsyncEnd->getMustTailCallFunction(); + if (!MustTailCallFn) + continue; + IRBuilder<> Builder(AsyncEnd); + SmallVector Args(AsyncEnd->args()); + auto Arguments = ArrayRef(Args).drop_front(3); + auto *Call = createMustTailCall(AsyncEnd->getDebugLoc(), MustTailCallFn, + Arguments, Builder); + splitAround(Call, "MustTailCall.Before.CoroEnd"); + } + } + // Transforms multi-edge PHI Nodes, so that any value feeding into a PHI will // never has its definition separated from the PHI by the suspend point. rewritePHIs(F); @@ -1646,51 +2254,40 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { SuspendCrossingInfo Checker(F, Shape); IRBuilder<> Builder(F.getContext()); - SpillInfo Spills; + FrameDataInfo FrameData; SmallVector LocalAllocas; SmallVector DeadInstructions; - for (int Repeat = 0; Repeat < 4; ++Repeat) { - // See if there are materializable instructions across suspend points. - for (Instruction &I : instructions(F)) - if (materializable(I)) - for (User *U : I.users()) - if (Checker.isDefinitionAcrossSuspend(I, U)) - Spills.emplace_back(&I, U); - - if (Spills.empty()) - break; + { + SpillInfo Spills; + for (int Repeat = 0; Repeat < 4; ++Repeat) { + // See if there are materializable instructions across suspend points. + for (Instruction &I : instructions(F)) + if (materializable(I)) + for (User *U : I.users()) + if (Checker.isDefinitionAcrossSuspend(I, U)) + Spills[&I].push_back(cast(U)); + + if (Spills.empty()) + break; - // Rewrite materializable instructions to be materialized at the use point. - LLVM_DEBUG(dump("Materializations", Spills)); - rewriteMaterializableInstructions(Builder, Spills); - Spills.clear(); + // Rewrite materializable instructions to be materialized at the use + // point. + LLVM_DEBUG(dumpSpills("Materializations", Spills)); + rewriteMaterializableInstructions(Builder, Spills); + Spills.clear(); + } } sinkLifetimeStartMarkers(F, Shape, Checker); - // Collect lifetime.start info for each alloca. - using LifetimeStart = SmallPtrSet; - llvm::DenseMap> LifetimeMap; - for (Instruction &I : instructions(F)) { - auto *II = dyn_cast(&I); - if (!II || II->getIntrinsicID() != Intrinsic::lifetime_start) - continue; - - if (auto *OpInst = dyn_cast(I.getOperand(1))) - if (auto *AI = dyn_cast(OpInst->getOperand(0))) { - - if (LifetimeMap.find(AI) == LifetimeMap.end()) - LifetimeMap[AI] = std::make_unique(); - - LifetimeMap[AI]->insert(OpInst); - } - } + collectFrameAllocas(F, Shape, Checker, FrameData.Allocas); + LLVM_DEBUG(dumpAllocas(FrameData.Allocas)); // Collect the spills for arguments and other not-materializable values. for (Argument &A : F.args()) for (User *U : A.users()) if (Checker.isDefinitionAcrossSuspend(A, U)) - Spills.emplace_back(&A, U); + FrameData.Spills[&A].push_back(cast(U)); for (Instruction &I : instructions(F)) { // Values returned from coroutine structure intrinsics should not be part @@ -1721,43 +2318,33 @@ void coro::buildCoroutineFrame(Function &F, Shape &Shape) { for (User *U : Alloc->users()) { if (Checker.isDefinitionAcrossSuspend(*Alloc, U)) - Spills.emplace_back(Alloc, U); + FrameData.Spills[Alloc].push_back(cast(U)); } continue; } // Ignore alloca.get; we process this as part of coro.alloca.alloc. - if (isa(I)) { + if (isa(I)) continue; - } - auto Iter = LifetimeMap.find(&I); - for (User *U : I.users()) { - bool NeedSpill = false; - - // Check against lifetime.start if the instruction has the info. - if (Iter != LifetimeMap.end()) - for (auto *S : *Iter->second) { - if ((NeedSpill = Checker.isDefinitionAcrossSuspend(*S, U))) - break; - } - else - NeedSpill = Checker.isDefinitionAcrossSuspend(I, U); + if (isa(I)) + continue; - if (NeedSpill) { + for (User *U : I.users()) + if (Checker.isDefinitionAcrossSuspend(I, U)) { // We cannot spill a token. if (I.getType()->isTokenTy()) report_fatal_error( "token definition is separated from the use by a suspend point"); - Spills.emplace_back(&I, U); + FrameData.Spills[&I].push_back(cast(U)); } - } } - LLVM_DEBUG(dump("Spills", Spills)); - if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce) - sinkSpillUsesAfterCoroBegin(F, Spills, Shape.CoroBegin); - Shape.FrameTy = buildFrameType(F, Shape, Spills); - Shape.FramePtr = insertSpills(Spills, Shape); + LLVM_DEBUG(dumpSpills("Spills", FrameData.Spills)); + if (Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce || + Shape.ABI == coro::ABI::Async) + sinkSpillUsesAfterCoroBegin(F, FrameData, Shape.CoroBegin); + Shape.FrameTy = buildFrameType(F, Shape, FrameData); + Shape.FramePtr = insertSpills(FrameData, Shape); lowerLocalAllocas(LocalAllocas, DeadInstructions); for (auto I : DeadInstructions) diff --git a/llvm/lib/Transforms/Coroutines/CoroInstr.h b/llvm/lib/Transforms/Coroutines/CoroInstr.h index 320137526db8..9fa2fd12f80b 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInstr.h +++ b/llvm/lib/Transforms/Coroutines/CoroInstr.h @@ -99,9 +99,9 @@ public: // Methods to support type inquiry through isa, cast, and dyn_cast: static bool classof(const IntrinsicInst *I) { auto ID = I->getIntrinsicID(); - return ID == Intrinsic::coro_id || - ID == Intrinsic::coro_id_retcon || - ID == Intrinsic::coro_id_retcon_once; + return ID == Intrinsic::coro_id || ID == Intrinsic::coro_id_retcon || + ID == Intrinsic::coro_id_retcon_once || + ID == Intrinsic::coro_id_async; } static bool classof(const Value *V) { @@ -273,6 +273,109 @@ public: } }; +/// This represents the llvm.coro.id.async instruction. +class LLVM_LIBRARY_VISIBILITY CoroIdAsyncInst : public AnyCoroIdInst { + enum { SizeArg, AlignArg, StorageArg, AsyncFuncPtrArg }; + +public: + void checkWellFormed() const; + + /// The initial async function context size. The fields of which are reserved + /// for use by the frontend. The frame will be allocated as a tail of this + /// context. + uint64_t getStorageSize() const { + return cast(getArgOperand(SizeArg))->getZExtValue(); + } + + /// The alignment of the initial async function context. + Align getStorageAlignment() const { + return cast(getArgOperand(AlignArg))->getAlignValue(); + } + + /// The async context parameter. + Value *getStorage() const { + return getParent()->getParent()->getArg(getStorageArgumentIndex()); + } + + unsigned getStorageArgumentIndex() const { + auto *Arg = cast(getArgOperand(StorageArg)); + return Arg->getZExtValue(); + } + + /// Return the async function pointer address. This should be the address of + /// a async function pointer struct for the current async function. + /// struct async_function_pointer { + /// uint32_t context_size; + /// uint32_t relative_async_function_pointer; + /// }; + GlobalVariable *getAsyncFunctionPointer() const { + return cast( + getArgOperand(AsyncFuncPtrArg)->stripPointerCasts()); + } + + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + auto ID = I->getIntrinsicID(); + return ID == Intrinsic::coro_id_async; + } + + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +/// This represents the llvm.coro.context.alloc instruction. +class LLVM_LIBRARY_VISIBILITY CoroAsyncContextAllocInst : public IntrinsicInst { + enum { AsyncFuncPtrArg }; + +public: + GlobalVariable *getAsyncFunctionPointer() const { + return cast( + getArgOperand(AsyncFuncPtrArg)->stripPointerCasts()); + } + + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::coro_async_context_alloc; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +/// This represents the llvm.coro.context.dealloc instruction. +class LLVM_LIBRARY_VISIBILITY CoroAsyncContextDeallocInst + : public IntrinsicInst { + enum { AsyncContextArg }; + +public: + Value *getAsyncContext() const { + return getArgOperand(AsyncContextArg)->stripPointerCasts(); + } + + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::coro_async_context_dealloc; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +/// This represents the llvm.coro.async.resume instruction. +/// During lowering this is replaced by the resume function of a suspend point +/// (the continuation function). +class LLVM_LIBRARY_VISIBILITY CoroAsyncResumeInst : public IntrinsicInst { +public: + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::coro_async_resume; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + /// This represents the llvm.coro.frame instruction. class LLVM_LIBRARY_VISIBILITY CoroFrameInst : public IntrinsicInst { public: @@ -366,6 +469,7 @@ public: // Methods to support type inquiry through isa, cast, and dyn_cast: static bool classof(const IntrinsicInst *I) { return I->getIntrinsicID() == Intrinsic::coro_suspend || + I->getIntrinsicID() == Intrinsic::coro_suspend_async || I->getIntrinsicID() == Intrinsic::coro_suspend_retcon; } static bool classof(const Value *V) { @@ -405,6 +509,37 @@ inline CoroSaveInst *AnyCoroSuspendInst::getCoroSave() const { return nullptr; } +/// This represents the llvm.coro.suspend.async instruction. +class LLVM_LIBRARY_VISIBILITY CoroSuspendAsyncInst : public AnyCoroSuspendInst { + enum { ResumeFunctionArg, AsyncContextProjectionArg, MustTailCallFuncArg }; + +public: + void checkWellFormed() const; + + Function *getAsyncContextProjectionFunction() const { + return cast( + getArgOperand(AsyncContextProjectionArg)->stripPointerCasts()); + } + + CoroAsyncResumeInst *getResumeFunction() const { + return cast( + getArgOperand(ResumeFunctionArg)->stripPointerCasts()); + } + + Function *getMustTailCallFunction() const { + return cast( + getArgOperand(MustTailCallFuncArg)->stripPointerCasts()); + } + + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::coro_suspend_async; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + /// This represents the llvm.coro.suspend.retcon instruction. class LLVM_LIBRARY_VISIBILITY CoroSuspendRetconInst : public AnyCoroSuspendInst { public: @@ -442,8 +577,7 @@ public: } }; -/// This represents the llvm.coro.end instruction. -class LLVM_LIBRARY_VISIBILITY CoroEndInst : public IntrinsicInst { +class LLVM_LIBRARY_VISIBILITY AnyCoroEndInst : public IntrinsicInst { enum { FrameArg, UnwindArg }; public: @@ -452,6 +586,19 @@ public: return cast(getArgOperand(UnwindArg))->isOneValue(); } + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + auto ID = I->getIntrinsicID(); + return ID == Intrinsic::coro_end || ID == Intrinsic::coro_end_async; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + +/// This represents the llvm.coro.end instruction. +class LLVM_LIBRARY_VISIBILITY CoroEndInst : public AnyCoroEndInst { +public: // Methods to support type inquiry through isa, cast, and dyn_cast: static bool classof(const IntrinsicInst *I) { return I->getIntrinsicID() == Intrinsic::coro_end; @@ -461,6 +608,30 @@ public: } }; +/// This represents the llvm.coro.end instruction. +class LLVM_LIBRARY_VISIBILITY CoroAsyncEndInst : public AnyCoroEndInst { + enum { FrameArg, UnwindArg, MustTailCallFuncArg }; + +public: + void checkWellFormed() const; + + Function *getMustTailCallFunction() const { + if (getNumArgOperands() < 3) + return nullptr; + + return cast( + getArgOperand(MustTailCallFuncArg)->stripPointerCasts()); + } + + // Methods to support type inquiry through isa, cast, and dyn_cast: + static bool classof(const IntrinsicInst *I) { + return I->getIntrinsicID() == Intrinsic::coro_end_async; + } + static bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + /// This represents the llvm.coro.alloca.alloc instruction. class LLVM_LIBRARY_VISIBILITY CoroAllocaAllocInst : public IntrinsicInst { enum { SizeArg, AlignArg }; diff --git a/llvm/lib/Transforms/Coroutines/CoroInternal.h b/llvm/lib/Transforms/Coroutines/CoroInternal.h index bd76e93c9124..6c0e52f24542 100644 --- a/llvm/lib/Transforms/Coroutines/CoroInternal.h +++ b/llvm/lib/Transforms/Coroutines/CoroInternal.h @@ -34,10 +34,12 @@ void initializeCoroCleanupLegacyPass(PassRegistry &); // CoroElide pass that triggers a restart of the pipeline by CGPassManager. // When CoroSplit pass sees the same coroutine the second time, it splits it up, // adds coroutine subfunctions to the SCC to be processed by IPO pipeline. - +// Async lowering similarily triggers a restart of the pipeline after it has +// split the coroutine. #define CORO_PRESPLIT_ATTR "coroutine.presplit" #define UNPREPARED_FOR_SPLIT "0" #define PREPARED_FOR_SPLIT "1" +#define ASYNC_RESTART_AFTER_SPLIT "2" #define CORO_DEVIRT_TRIGGER_FN "coro.devirt.trigger" @@ -45,11 +47,14 @@ namespace coro { bool declaresIntrinsics(const Module &M, const std::initializer_list); -void replaceAllCoroAllocs(CoroBeginInst *CB, bool Replacement); -void replaceAllCoroFrees(CoroBeginInst *CB, Value *Replacement); void replaceCoroFree(CoroIdInst *CoroId, bool Elide); void updateCallGraph(Function &Caller, ArrayRef Funcs, CallGraph &CG, CallGraphSCC &SCC); +/// Recover a dbg.declare prepared by the frontend and emit an alloca +/// holding a pointer to the coroutine frame. +void salvageDebugInfo( + SmallDenseMap &DbgPtrAllocaCache, + DbgDeclareInst *DDI, bool LoadFromCoroFrame = false); // Keeps data and helper functions for lowering coroutine intrinsics. struct LowererBase { @@ -81,13 +86,18 @@ enum class ABI { /// suspend at most once during its execution, and the return value of /// the continuation is void. RetconOnce, + + /// The "async continuation" lowering, where each suspend point creates a + /// single continuation function. The continuation function is available as an + /// intrinsic. + Async, }; // Holds structural Coroutine Intrinsics for a particular function and other // values used during CoroSplit pass. struct LLVM_LIBRARY_VISIBILITY Shape { CoroBeginInst *CoroBegin; - SmallVector CoroEnds; + SmallVector CoroEnds; SmallVector CoroSizes; SmallVector CoroSuspends; SmallVector SwiftErrorOps; @@ -115,12 +125,13 @@ struct LLVM_LIBRARY_VISIBILITY Shape { Instruction *FramePtr; BasicBlock *AllocaSpillBlock; + bool ReuseFrameSlot; + struct SwitchLoweringStorage { SwitchInst *ResumeSwitch; AllocaInst *PromiseAlloca; BasicBlock *ResumeEntryBlock; unsigned IndexField; - unsigned PromiseField; bool HasFinalSuspend; }; @@ -132,9 +143,23 @@ struct LLVM_LIBRARY_VISIBILITY Shape { bool IsFrameInlineInStorage; }; + struct AsyncLoweringStorage { + FunctionType *AsyncFuncTy; + Value *Context; + unsigned ContextArgNo; + uint64_t ContextHeaderSize; + uint64_t ContextAlignment; + uint64_t FrameOffset; // Start of the frame. + uint64_t ContextSize; // Includes frame size. + GlobalVariable *AsyncFuncPointer; + + Align getContextAlignment() const { return Align(ContextAlignment); } + }; + union { SwitchLoweringStorage SwitchLowering; RetconLoweringStorage RetconLowering; + AsyncLoweringStorage AsyncLowering; }; CoroIdInst *getSwitchCoroId() const { @@ -148,6 +173,11 @@ struct LLVM_LIBRARY_VISIBILITY Shape { return cast(CoroBegin->getId()); } + CoroIdAsyncInst *getAsyncCoroId() const { + assert(ABI == coro::ABI::Async); + return cast(CoroBegin->getId()); + } + unsigned getSwitchIndexField() const { assert(ABI == coro::ABI::Switch); assert(FrameTy && "frame type not assigned"); @@ -177,7 +207,10 @@ struct LLVM_LIBRARY_VISIBILITY Shape { case coro::ABI::Retcon: case coro::ABI::RetconOnce: return RetconLowering.ResumePrototype->getFunctionType(); + case coro::ABI::Async: + return AsyncLowering.AsyncFuncTy; } + llvm_unreachable("Unknown coro::ABI enum"); } @@ -211,6 +244,8 @@ struct LLVM_LIBRARY_VISIBILITY Shape { case coro::ABI::Retcon: case coro::ABI::RetconOnce: return RetconLowering.ResumePrototype->getCallingConv(); + case coro::ABI::Async: + return CallingConv::Swift; } llvm_unreachable("Unknown coro::ABI enum"); } @@ -220,12 +255,6 @@ struct LLVM_LIBRARY_VISIBILITY Shape { return SwitchLowering.PromiseAlloca; return nullptr; } - unsigned getPromiseField() const { - assert(ABI == coro::ABI::Switch); - assert(FrameTy && "frame type not assigned"); - assert(SwitchLowering.PromiseAlloca && "no promise alloca"); - return SwitchLowering.PromiseField; - } /// Allocate memory according to the rules of the active lowering. /// @@ -238,12 +267,16 @@ struct LLVM_LIBRARY_VISIBILITY Shape { void emitDealloc(IRBuilder<> &Builder, Value *Ptr, CallGraph *CG) const; Shape() = default; - explicit Shape(Function &F) { buildFrom(F); } + explicit Shape(Function &F, bool ReuseFrameSlot = false) + : ReuseFrameSlot(ReuseFrameSlot) { + buildFrom(F); + } void buildFrom(Function &F); }; void buildCoroutineFrame(Function &F, Shape &Shape); - +CallInst *createMustTailCall(DebugLoc Loc, Function *MustTailCallFn, + ArrayRef Arguments, IRBuilder<> &); } // End namespace coro. } // End namespace llvm diff --git a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp index 9c4392e7999b..c4d7db9153e2 100644 --- a/llvm/lib/Transforms/Coroutines/CoroSplit.cpp +++ b/llvm/lib/Transforms/Coroutines/CoroSplit.cpp @@ -28,6 +28,7 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" +#include "llvm/Analysis/LazyCallGraph.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -90,7 +91,11 @@ public: /// An individual continuation function. Continuation, + + /// An async resume function. + Async, }; + private: Function &OrigF; Function *NewF; @@ -100,9 +105,9 @@ private: ValueToValueMapTy VMap; IRBuilder<> Builder; Value *NewFramePtr = nullptr; - Value *SwiftErrorSlot = nullptr; - /// The active suspend instruction; meaningful only for continuation ABIs. + /// The active suspend instruction; meaningful only for continuation and async + /// ABIs. AnyCoroSuspendInst *ActiveSuspend = nullptr; public: @@ -117,11 +122,11 @@ public: /// Create a cloner for a continuation lowering. CoroCloner(Function &OrigF, const Twine &Suffix, coro::Shape &Shape, Function *NewF, AnyCoroSuspendInst *ActiveSuspend) - : OrigF(OrigF), NewF(NewF), Suffix(Suffix), Shape(Shape), - FKind(Kind::Continuation), Builder(OrigF.getContext()), - ActiveSuspend(ActiveSuspend) { + : OrigF(OrigF), NewF(NewF), Suffix(Suffix), Shape(Shape), + FKind(Shape.ABI == coro::ABI::Async ? Kind::Async : Kind::Continuation), + Builder(OrigF.getContext()), ActiveSuspend(ActiveSuspend) { assert(Shape.ABI == coro::ABI::Retcon || - Shape.ABI == coro::ABI::RetconOnce); + Shape.ABI == coro::ABI::RetconOnce || Shape.ABI == coro::ABI::Async); assert(NewF && "need existing function for continuation"); assert(ActiveSuspend && "need active suspend point for continuation"); } @@ -136,6 +141,7 @@ public: private: bool isSwitchDestroyFunction() { switch (FKind) { + case Kind::Async: case Kind::Continuation: case Kind::SwitchResume: return false; @@ -146,15 +152,14 @@ private: llvm_unreachable("Unknown CoroCloner::Kind enum"); } - void createDeclaration(); void replaceEntryBlock(); Value *deriveNewFramePointer(); - void replaceRetconSuspendUses(); + void replaceRetconOrAsyncSuspendUses(); void replaceCoroSuspends(); void replaceCoroEnds(); void replaceSwiftErrorOps(); + void salvageDebugInfo(); void handleFinalSuspend(); - void maybeFreeContinuationStorage(); }; } // end anonymous namespace @@ -170,8 +175,53 @@ static void maybeFreeRetconStorage(IRBuilder<> &Builder, Shape.emitDealloc(Builder, FramePtr, CG); } +/// Replace an llvm.coro.end.async. +/// Will inline the must tail call function call if there is one. +/// \returns true if cleanup of the coro.end block is needed, false otherwise. +static bool replaceCoroEndAsync(AnyCoroEndInst *End) { + IRBuilder<> Builder(End); + + auto *EndAsync = dyn_cast(End); + if (!EndAsync) { + Builder.CreateRetVoid(); + return true /*needs cleanup of coro.end block*/; + } + + auto *MustTailCallFunc = EndAsync->getMustTailCallFunction(); + if (!MustTailCallFunc) { + Builder.CreateRetVoid(); + return true /*needs cleanup of coro.end block*/; + } + + // Move the must tail call from the predecessor block into the end block. + auto *CoroEndBlock = End->getParent(); + auto *MustTailCallFuncBlock = CoroEndBlock->getSinglePredecessor(); + assert(MustTailCallFuncBlock && "Must have a single predecessor block"); + auto It = MustTailCallFuncBlock->getTerminator()->getIterator(); + auto *MustTailCall = cast(&*std::prev(It)); + CoroEndBlock->getInstList().splice( + End->getIterator(), MustTailCallFuncBlock->getInstList(), MustTailCall); + + // Insert the return instruction. + Builder.SetInsertPoint(End); + Builder.CreateRetVoid(); + InlineFunctionInfo FnInfo; + + // Remove the rest of the block, by splitting it into an unreachable block. + auto *BB = End->getParent(); + BB->splitBasicBlock(End); + BB->getTerminator()->eraseFromParent(); + + auto InlineRes = InlineFunction(*MustTailCall, FnInfo); + assert(InlineRes.isSuccess() && "Expected inlining to succeed"); + (void)InlineRes; + + // We have cleaned up the coro.end block above. + return false; +} + /// Replace a non-unwind call to llvm.coro.end. -static void replaceFallthroughCoroEnd(CoroEndInst *End, +static void replaceFallthroughCoroEnd(AnyCoroEndInst *End, const coro::Shape &Shape, Value *FramePtr, bool InResume, CallGraph *CG) { // Start inserting right before the coro.end. @@ -188,6 +238,14 @@ static void replaceFallthroughCoroEnd(CoroEndInst *End, Builder.CreateRetVoid(); break; + // In async lowering this returns. + case coro::ABI::Async: { + bool CoroEndBlockNeedsCleanup = replaceCoroEndAsync(End); + if (!CoroEndBlockNeedsCleanup) + return; + break; + } + // In unique continuation lowering, the continuations always return void. // But we may have implicitly allocated storage. case coro::ABI::RetconOnce: @@ -221,8 +279,9 @@ static void replaceFallthroughCoroEnd(CoroEndInst *End, } /// Replace an unwind call to llvm.coro.end. -static void replaceUnwindCoroEnd(CoroEndInst *End, const coro::Shape &Shape, - Value *FramePtr, bool InResume, CallGraph *CG){ +static void replaceUnwindCoroEnd(AnyCoroEndInst *End, const coro::Shape &Shape, + Value *FramePtr, bool InResume, + CallGraph *CG) { IRBuilder<> Builder(End); switch (Shape.ABI) { @@ -231,7 +290,9 @@ static void replaceUnwindCoroEnd(CoroEndInst *End, const coro::Shape &Shape, if (!InResume) return; break; - + // In async lowering this does nothing. + case coro::ABI::Async: + break; // In continuation-lowering, this frees the continuation storage. case coro::ABI::Retcon: case coro::ABI::RetconOnce: @@ -248,7 +309,7 @@ static void replaceUnwindCoroEnd(CoroEndInst *End, const coro::Shape &Shape, } } -static void replaceCoroEnd(CoroEndInst *End, const coro::Shape &Shape, +static void replaceCoroEnd(AnyCoroEndInst *End, const coro::Shape &Shape, Value *FramePtr, bool InResume, CallGraph *CG) { if (End->isUnwind()) replaceUnwindCoroEnd(End, Shape, FramePtr, InResume, CG); @@ -403,20 +464,24 @@ static Function *createCloneDeclaration(Function &OrigF, coro::Shape &Shape, Function::Create(FnTy, GlobalValue::LinkageTypes::InternalLinkage, OrigF.getName() + Suffix); NewF->addParamAttr(0, Attribute::NonNull); - NewF->addParamAttr(0, Attribute::NoAlias); + + // For the async lowering ABI we can't guarantee that the context argument is + // not access via a different pointer not based on the argument. + if (Shape.ABI != coro::ABI::Async) + NewF->addParamAttr(0, Attribute::NoAlias); M->getFunctionList().insert(InsertBefore, NewF); return NewF; } -/// Replace uses of the active llvm.coro.suspend.retcon call with the +/// Replace uses of the active llvm.coro.suspend.retcon/async call with the /// arguments to the continuation function. /// /// This assumes that the builder has a meaningful insertion point. -void CoroCloner::replaceRetconSuspendUses() { - assert(Shape.ABI == coro::ABI::Retcon || - Shape.ABI == coro::ABI::RetconOnce); +void CoroCloner::replaceRetconOrAsyncSuspendUses() { + assert(Shape.ABI == coro::ABI::Retcon || Shape.ABI == coro::ABI::RetconOnce || + Shape.ABI == coro::ABI::Async); auto NewS = VMap[ActiveSuspend]; if (NewS->use_empty()) return; @@ -424,7 +489,11 @@ void CoroCloner::replaceRetconSuspendUses() { // Copy out all the continuation arguments after the buffer pointer into // an easily-indexed data structure for convenience. SmallVector Args; - for (auto I = std::next(NewF->arg_begin()), E = NewF->arg_end(); I != E; ++I) + // The async ABI includes all arguments -- including the first argument. + bool IsAsyncABI = Shape.ABI == coro::ABI::Async; + for (auto I = IsAsyncABI ? NewF->arg_begin() : std::next(NewF->arg_begin()), + E = NewF->arg_end(); + I != E; ++I) Args.push_back(&*I); // If the suspend returns a single scalar value, we can just do a simple @@ -470,6 +539,10 @@ void CoroCloner::replaceCoroSuspends() { SuspendResult = Builder.getInt8(isSwitchDestroyFunction() ? 1 : 0); break; + // In async lowering there are no uses of the result. + case coro::ABI::Async: + return; + // In returned-continuation lowering, the arguments from earlier // continuations are theoretically arbitrary, and they should have been // spilled. @@ -489,10 +562,10 @@ void CoroCloner::replaceCoroSuspends() { } void CoroCloner::replaceCoroEnds() { - for (CoroEndInst *CE : Shape.CoroEnds) { + for (AnyCoroEndInst *CE : Shape.CoroEnds) { // We use a null call graph because there's no call graph node for // the cloned function yet. We'll just be rebuilding that later. - auto NewCE = cast(VMap[CE]); + auto *NewCE = cast(VMap[CE]); replaceCoroEnd(NewCE, Shape, NewFramePtr, /*in resume*/ true, nullptr); } } @@ -559,6 +632,39 @@ void CoroCloner::replaceSwiftErrorOps() { ::replaceSwiftErrorOps(*NewF, Shape, &VMap); } +void CoroCloner::salvageDebugInfo() { + SmallVector Worklist; + SmallDenseMap DbgPtrAllocaCache; + for (auto &BB : *NewF) + for (auto &I : BB) + if (auto *DDI = dyn_cast(&I)) + Worklist.push_back(DDI); + for (DbgDeclareInst *DDI : Worklist) { + // This is a heuristic that detects declares left by CoroFrame. + bool LoadFromFramePtr = !isa(DDI->getAddress()); + coro::salvageDebugInfo(DbgPtrAllocaCache, DDI, LoadFromFramePtr); + } + // Remove all salvaged dbg.declare intrinsics that became + // either unreachable or stale due to the CoroSplit transformation. + auto IsUnreachableBlock = [&](BasicBlock *BB) { + return BB->hasNPredecessors(0) && BB != &NewF->getEntryBlock(); + }; + for (DbgDeclareInst *DDI : Worklist) { + if (IsUnreachableBlock(DDI->getParent())) + DDI->eraseFromParent(); + else if (auto *Alloca = dyn_cast_or_null(DDI->getAddress())) { + // Count all non-debuginfo uses in reachable blocks. + unsigned Uses = 0; + for (auto *User : DDI->getAddress()->users()) + if (auto *I = dyn_cast(User)) + if (!isa(I) && !IsUnreachableBlock(I->getParent())) + ++Uses; + if (!Uses) + DDI->eraseFromParent(); + } + } +} + void CoroCloner::replaceEntryBlock() { // In the original function, the AllocaSpillBlock is a block immediately // following the allocation of the frame object which defines GEPs for @@ -581,15 +687,6 @@ void CoroCloner::replaceEntryBlock() { Builder.CreateUnreachable(); BranchToEntry->eraseFromParent(); - // Move any allocas into Entry that weren't moved into the frame. - for (auto IT = OldEntry->begin(), End = OldEntry->end(); IT != End;) { - Instruction &I = *IT++; - if (!isa(&I) || I.use_empty()) - continue; - - I.moveBefore(*Entry, Entry->getFirstInsertionPt()); - } - // Branch from the entry to the appropriate place. Builder.SetInsertPoint(Entry); switch (Shape.ABI) { @@ -601,19 +698,37 @@ void CoroCloner::replaceEntryBlock() { Builder.CreateBr(SwitchBB); break; } - + case coro::ABI::Async: case coro::ABI::Retcon: case coro::ABI::RetconOnce: { // In continuation ABIs, we want to branch to immediately after the // active suspend point. Earlier phases will have put the suspend in its // own basic block, so just thread our jump directly to its successor. - auto MappedCS = cast(VMap[ActiveSuspend]); + assert((Shape.ABI == coro::ABI::Async && + isa(ActiveSuspend)) || + ((Shape.ABI == coro::ABI::Retcon || + Shape.ABI == coro::ABI::RetconOnce) && + isa(ActiveSuspend))); + auto *MappedCS = cast(VMap[ActiveSuspend]); auto Branch = cast(MappedCS->getNextNode()); assert(Branch->isUnconditional()); Builder.CreateBr(Branch->getSuccessor(0)); break; } } + + // Any alloca that's still being used but not reachable from the new entry + // needs to be moved to the new entry. + Function *F = OldEntry->getParent(); + DominatorTree DT{*F}; + for (auto IT = inst_begin(F), End = inst_end(F); IT != End;) { + Instruction &I = *IT++; + if (!isa(&I) || I.use_empty()) + continue; + if (DT.isReachableFromEntry(I.getParent())) + continue; + I.moveBefore(*Entry, Entry->getFirstInsertionPt()); + } } /// Derive the value of the new frame pointer. @@ -624,7 +739,36 @@ Value *CoroCloner::deriveNewFramePointer() { // In switch-lowering, the argument is the frame pointer. case coro::ABI::Switch: return &*NewF->arg_begin(); - + // In async-lowering, one of the arguments is an async context as determined + // by the `llvm.coro.id.async` intrinsic. We can retrieve the async context of + // the resume function from the async context projection function associated + // with the active suspend. The frame is located as a tail to the async + // context header. + case coro::ABI::Async: { + auto *CalleeContext = NewF->getArg(Shape.AsyncLowering.ContextArgNo); + auto *FramePtrTy = Shape.FrameTy->getPointerTo(); + auto *ProjectionFunc = cast(ActiveSuspend) + ->getAsyncContextProjectionFunction(); + auto DbgLoc = + cast(VMap[ActiveSuspend])->getDebugLoc(); + // Calling i8* (i8*) + auto *CallerContext = Builder.CreateCall( + cast(ProjectionFunc->getType()->getPointerElementType()), + ProjectionFunc, CalleeContext); + CallerContext->setCallingConv(ProjectionFunc->getCallingConv()); + CallerContext->setDebugLoc(DbgLoc); + // The frame is located after the async_context header. + auto &Context = Builder.getContext(); + auto *FramePtrAddr = Builder.CreateConstInBoundsGEP1_32( + Type::getInt8Ty(Context), CallerContext, + Shape.AsyncLowering.FrameOffset, "async.ctx.frameptr"); + // Inline the projection function. + InlineFunctionInfo InlineInfo; + auto InlineRes = InlineFunction(*CallerContext, InlineInfo); + assert(InlineRes.isSuccess()); + (void)InlineRes; + return Builder.CreateBitCast(FramePtrAddr, FramePtrTy); + } // In continuation-lowering, the argument is the opaque storage. case coro::ABI::Retcon: case coro::ABI::RetconOnce: { @@ -707,7 +851,8 @@ void CoroCloner::create() { addFramePointerAttrs(NewAttrs, Context, 0, Shape.FrameSize, Shape.FrameAlign); break; - + case coro::ABI::Async: + break; case coro::ABI::Retcon: case coro::ABI::RetconOnce: // If we have a continuation prototype, just use its attributes, @@ -737,6 +882,12 @@ void CoroCloner::create() { // so we want to leave any returns in place. case coro::ABI::Retcon: break; + // Async lowering will insert musttail call functions at all suspend points + // followed by a return. + // Don't change returns to unreachable because that will trip up the verifier. + // These returns should be unreachable from the clone. + case coro::ABI::Async: + break; } NewF->setAttributes(NewAttrs); @@ -767,14 +918,14 @@ void CoroCloner::create() { if (Shape.SwitchLowering.HasFinalSuspend) handleFinalSuspend(); break; - + case coro::ABI::Async: case coro::ABI::Retcon: case coro::ABI::RetconOnce: // Replace uses of the active suspend with the corresponding // continuation-function arguments. assert(ActiveSuspend != nullptr && "no active suspend when lowering a continuation-style coroutine"); - replaceRetconSuspendUses(); + replaceRetconOrAsyncSuspendUses(); break; } @@ -787,6 +938,9 @@ void CoroCloner::create() { // Remove coro.end intrinsics. replaceCoroEnds(); + // Salvage debug info that points into the coroutine frame. + salvageDebugInfo(); + // Eliminate coro.free from the clones, replacing it with 'null' in cleanup, // to suppress deallocation code. if (Shape.ABI == coro::ABI::Switch) @@ -811,7 +965,25 @@ static void removeCoroEnds(const coro::Shape &Shape, CallGraph *CG) { } } +static void updateAsyncFuncPointerContextSize(coro::Shape &Shape) { + assert(Shape.ABI == coro::ABI::Async); + + auto *FuncPtrStruct = cast( + Shape.AsyncLowering.AsyncFuncPointer->getInitializer()); + auto *OrigRelativeFunOffset = FuncPtrStruct->getOperand(0); + auto *OrigContextSize = FuncPtrStruct->getOperand(1); + auto *NewContextSize = ConstantInt::get(OrigContextSize->getType(), + Shape.AsyncLowering.ContextSize); + auto *NewFuncPtrStruct = ConstantStruct::get( + FuncPtrStruct->getType(), OrigRelativeFunOffset, NewContextSize); + + Shape.AsyncLowering.AsyncFuncPointer->setInitializer(NewFuncPtrStruct); +} + static void replaceFrameSize(coro::Shape &Shape) { + if (Shape.ABI == coro::ABI::Async) + updateAsyncFuncPointerContextSize(Shape); + if (Shape.CoroSizes.empty()) return; @@ -1075,7 +1247,7 @@ static void handleNoSuspendCoroutine(coro::Shape &Shape) { } break; } - + case coro::ABI::Async: case coro::ABI::Retcon: case coro::ABI::RetconOnce: CoroBegin->replaceAllUsesWith(UndefValue::get(CoroBegin->getType())); @@ -1271,6 +1443,133 @@ static void splitSwitchCoroutine(Function &F, coro::Shape &Shape, setCoroInfo(F, Shape, Clones); } +static void replaceAsyncResumeFunction(CoroSuspendAsyncInst *Suspend, + Value *Continuation) { + auto *ResumeIntrinsic = Suspend->getResumeFunction(); + auto &Context = Suspend->getParent()->getParent()->getContext(); + auto *Int8PtrTy = Type::getInt8PtrTy(Context); + + IRBuilder<> Builder(ResumeIntrinsic); + auto *Val = Builder.CreateBitOrPointerCast(Continuation, Int8PtrTy); + ResumeIntrinsic->replaceAllUsesWith(Val); + ResumeIntrinsic->eraseFromParent(); + Suspend->setOperand(0, UndefValue::get(Int8PtrTy)); +} + +/// Coerce the arguments in \p FnArgs according to \p FnTy in \p CallArgs. +static void coerceArguments(IRBuilder<> &Builder, FunctionType *FnTy, + ArrayRef FnArgs, + SmallVectorImpl &CallArgs) { + size_t ArgIdx = 0; + for (auto paramTy : FnTy->params()) { + assert(ArgIdx < FnArgs.size()); + if (paramTy != FnArgs[ArgIdx]->getType()) + CallArgs.push_back( + Builder.CreateBitOrPointerCast(FnArgs[ArgIdx], paramTy)); + else + CallArgs.push_back(FnArgs[ArgIdx]); + ++ArgIdx; + } +} + +CallInst *coro::createMustTailCall(DebugLoc Loc, Function *MustTailCallFn, + ArrayRef Arguments, + IRBuilder<> &Builder) { + auto *FnTy = + cast(MustTailCallFn->getType()->getPointerElementType()); + // Coerce the arguments, llvm optimizations seem to ignore the types in + // vaarg functions and throws away casts in optimized mode. + SmallVector CallArgs; + coerceArguments(Builder, FnTy, Arguments, CallArgs); + + auto *TailCall = Builder.CreateCall(FnTy, MustTailCallFn, CallArgs); + TailCall->setTailCallKind(CallInst::TCK_MustTail); + TailCall->setDebugLoc(Loc); + TailCall->setCallingConv(MustTailCallFn->getCallingConv()); + return TailCall; +} + +static void splitAsyncCoroutine(Function &F, coro::Shape &Shape, + SmallVectorImpl &Clones) { + assert(Shape.ABI == coro::ABI::Async); + assert(Clones.empty()); + // Reset various things that the optimizer might have decided it + // "knows" about the coroutine function due to not seeing a return. + F.removeFnAttr(Attribute::NoReturn); + F.removeAttribute(AttributeList::ReturnIndex, Attribute::NoAlias); + F.removeAttribute(AttributeList::ReturnIndex, Attribute::NonNull); + + auto &Context = F.getContext(); + auto *Int8PtrTy = Type::getInt8PtrTy(Context); + + auto *Id = cast(Shape.CoroBegin->getId()); + IRBuilder<> Builder(Id); + + auto *FramePtr = Id->getStorage(); + FramePtr = Builder.CreateBitOrPointerCast(FramePtr, Int8PtrTy); + FramePtr = Builder.CreateConstInBoundsGEP1_32( + Type::getInt8Ty(Context), FramePtr, Shape.AsyncLowering.FrameOffset, + "async.ctx.frameptr"); + + // Map all uses of llvm.coro.begin to the allocated frame pointer. + { + // Make sure we don't invalidate Shape.FramePtr. + TrackingVH Handle(Shape.FramePtr); + Shape.CoroBegin->replaceAllUsesWith(FramePtr); + Shape.FramePtr = Handle.getValPtr(); + } + + // Create all the functions in order after the main function. + auto NextF = std::next(F.getIterator()); + + // Create a continuation function for each of the suspend points. + Clones.reserve(Shape.CoroSuspends.size()); + for (size_t Idx = 0, End = Shape.CoroSuspends.size(); Idx != End; ++Idx) { + auto *Suspend = cast(Shape.CoroSuspends[Idx]); + + // Create the clone declaration. + auto *Continuation = + createCloneDeclaration(F, Shape, ".resume." + Twine(Idx), NextF); + Clones.push_back(Continuation); + + // Insert a branch to a new return block immediately before the suspend + // point. + auto *SuspendBB = Suspend->getParent(); + auto *NewSuspendBB = SuspendBB->splitBasicBlock(Suspend); + auto *Branch = cast(SuspendBB->getTerminator()); + + // Place it before the first suspend. + auto *ReturnBB = + BasicBlock::Create(F.getContext(), "coro.return", &F, NewSuspendBB); + Branch->setSuccessor(0, ReturnBB); + + IRBuilder<> Builder(ReturnBB); + + // Insert the call to the tail call function and inline it. + auto *Fn = Suspend->getMustTailCallFunction(); + SmallVector Args(Suspend->args()); + auto FnArgs = ArrayRef(Args).drop_front(3); + auto *TailCall = + coro::createMustTailCall(Suspend->getDebugLoc(), Fn, FnArgs, Builder); + Builder.CreateRetVoid(); + InlineFunctionInfo FnInfo; + auto InlineRes = InlineFunction(*TailCall, FnInfo); + assert(InlineRes.isSuccess() && "Expected inlining to succeed"); + (void)InlineRes; + + // Replace the lvm.coro.async.resume intrisic call. + replaceAsyncResumeFunction(Suspend, Continuation); + } + + assert(Clones.size() == Shape.CoroSuspends.size()); + for (size_t Idx = 0, End = Shape.CoroSuspends.size(); Idx != End; ++Idx) { + auto *Suspend = Shape.CoroSuspends[Idx]; + auto *Clone = Clones[Idx]; + + CoroCloner(F, "resume." + Twine(Idx), Shape, Clone, Suspend).create(); + } +} + static void splitRetconCoroutine(Function &F, coro::Shape &Shape, SmallVectorImpl &Clones) { assert(Shape.ABI == coro::ABI::Retcon || @@ -1416,14 +1715,15 @@ namespace { } static coro::Shape splitCoroutine(Function &F, - SmallVectorImpl &Clones) { + SmallVectorImpl &Clones, + bool ReuseFrameSlot) { PrettyStackTraceFunction prettyStackTrace(F); // The suspend-crossing algorithm in buildCoroutineFrame get tripped // up by uses in unreachable blocks, so remove them as a first pass. removeUnreachableBlocks(F); - coro::Shape Shape(F); + coro::Shape Shape(F, ReuseFrameSlot); if (!Shape.CoroBegin) return Shape; @@ -1440,6 +1740,9 @@ static coro::Shape splitCoroutine(Function &F, case coro::ABI::Switch: splitSwitchCoroutine(F, Shape, Clones); break; + case coro::ABI::Async: + splitAsyncCoroutine(F, Shape, Clones); + break; case coro::ABI::Retcon: case coro::ABI::RetconOnce: splitRetconCoroutine(F, Shape, Clones); @@ -1476,40 +1779,46 @@ static void updateCallGraphAfterCoroutineSplit( if (!Shape.CoroBegin) return; - for (llvm::CoroEndInst *End : Shape.CoroEnds) { + for (llvm::AnyCoroEndInst *End : Shape.CoroEnds) { auto &Context = End->getContext(); End->replaceAllUsesWith(ConstantInt::getFalse(Context)); End->eraseFromParent(); } - postSplitCleanup(N.getFunction()); + if (!Clones.empty()) { + switch (Shape.ABI) { + case coro::ABI::Switch: + // Each clone in the Switch lowering is independent of the other clones. + // Let the LazyCallGraph know about each one separately. + for (Function *Clone : Clones) + CG.addSplitFunction(N.getFunction(), *Clone); + break; + case coro::ABI::Async: + case coro::ABI::Retcon: + case coro::ABI::RetconOnce: + // Each clone in the Async/Retcon lowering references of the other clones. + // Let the LazyCallGraph know about all of them at once. + CG.addSplitRefRecursiveFunctions(N.getFunction(), Clones); + break; + } - // To insert the newly created coroutine funclets 'f.resume', 'f.destroy', and - // 'f.cleanup' into the same SCC as the coroutine 'f' they were outlined from, - // we make use of the CallGraphUpdater class, which can modify the internal - // state of the LazyCallGraph. - for (Function *Clone : Clones) - CG.addNewFunctionIntoRefSCC(*Clone, C.getOuterRefSCC()); - - // We've inserted instructions into coroutine 'f' that reference the three new - // coroutine funclets. We must now update the call graph so that reference - // edges between 'f' and its funclets are added to it. LazyCallGraph only - // allows CGSCC passes to insert "trivial" reference edges. We've ensured - // above, by inserting the funclets into the same SCC as the corutine, that - // the edges are trivial. - // - // N.B.: If we didn't update the call graph here, a CGSCCToFunctionPassAdaptor - // later in this CGSCC pass pipeline may be run, triggering a call graph - // update of its own. Function passes run by the adaptor are not permitted to - // add new edges of any kind to the graph, and the new edges inserted by this - // pass would be misattributed to that unrelated function pass. - updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM); + // Let the CGSCC infra handle the changes to the original function. + updateCGAndAnalysisManagerForCGSCCPass(CG, C, N, AM, UR, FAM); + } + + // Do some cleanup and let the CGSCC infra see if we've cleaned up any edges + // to the split functions. + postSplitCleanup(N.getFunction()); + updateCGAndAnalysisManagerForFunctionPass(CG, C, N, AM, UR, FAM); } // When we see the coroutine the first time, we insert an indirect call to a // devirt trigger function and mark the coroutine that it is now ready for // split. -static void prepareForSplit(Function &F, CallGraph &CG) { +// Async lowering uses this after it has split the function to restart the +// pipeline. +static void prepareForSplit(Function &F, CallGraph &CG, + bool MarkForAsyncRestart = false) { Module &M = *F.getParent(); LLVMContext &Context = F.getContext(); #ifndef NDEBUG @@ -1517,7 +1826,9 @@ static void prepareForSplit(Function &F, CallGraph &CG) { assert(DevirtFn && "coro.devirt.trigger function not found"); #endif - F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT); + F.addFnAttr(CORO_PRESPLIT_ATTR, MarkForAsyncRestart + ? ASYNC_RESTART_AFTER_SPLIT + : PREPARED_FOR_SPLIT); // Insert an indirect call sequence that will be devirtualized by CoroElide // pass: @@ -1525,7 +1836,9 @@ static void prepareForSplit(Function &F, CallGraph &CG) { // %1 = bitcast i8* %0 to void(i8*)* // call void %1(i8* null) coro::LowererBase Lowerer(M); - Instruction *InsertPt = F.getEntryBlock().getTerminator(); + Instruction *InsertPt = + MarkForAsyncRestart ? F.getEntryBlock().getFirstNonPHIOrDbgOrLifetime() + : F.getEntryBlock().getTerminator(); auto *Null = ConstantPointerNull::get(Type::getInt8PtrTy(Context)); auto *DevirtFnAddr = Lowerer.makeSubFnCall(Null, CoroSubFnInst::RestartTrigger, InsertPt); @@ -1563,6 +1876,42 @@ static void createDevirtTriggerFunc(CallGraph &CG, CallGraphSCC &SCC) { SCC.initialize(Nodes); } +/// Replace a call to llvm.coro.prepare.retcon. +static void replacePrepare(CallInst *Prepare, LazyCallGraph &CG, + LazyCallGraph::SCC &C) { + auto CastFn = Prepare->getArgOperand(0); // as an i8* + auto Fn = CastFn->stripPointerCasts(); // as its original type + + // Attempt to peephole this pattern: + // %0 = bitcast [[TYPE]] @some_function to i8* + // %1 = call @llvm.coro.prepare.retcon(i8* %0) + // %2 = bitcast %1 to [[TYPE]] + // ==> + // %2 = @some_function + for (auto UI = Prepare->use_begin(), UE = Prepare->use_end(); UI != UE;) { + // Look for bitcasts back to the original function type. + auto *Cast = dyn_cast((UI++)->getUser()); + if (!Cast || Cast->getType() != Fn->getType()) + continue; + + // Replace and remove the cast. + Cast->replaceAllUsesWith(Fn); + Cast->eraseFromParent(); + } + + // Replace any remaining uses with the function as an i8*. + // This can never directly be a callee, so we don't need to update CG. + Prepare->replaceAllUsesWith(CastFn); + Prepare->eraseFromParent(); + + // Kill dead bitcasts. + while (auto *Cast = dyn_cast(CastFn)) { + if (!Cast->use_empty()) + break; + CastFn = Cast->getOperand(0); + Cast->eraseFromParent(); + } +} /// Replace a call to llvm.coro.prepare.retcon. static void replacePrepare(CallInst *Prepare, CallGraph &CG) { auto CastFn = Prepare->getArgOperand(0); // as an i8* @@ -1618,6 +1967,19 @@ static void replacePrepare(CallInst *Prepare, CallGraph &CG) { } } +static bool replaceAllPrepares(Function *PrepareFn, LazyCallGraph &CG, + LazyCallGraph::SCC &C) { + bool Changed = false; + for (auto PI = PrepareFn->use_begin(), PE = PrepareFn->use_end(); PI != PE;) { + // Intrinsics can only be used in calls. + auto *Prepare = cast((PI++)->getUser()); + replacePrepare(Prepare, CG, C); + Changed = true; + } + + return Changed; +} + /// Remove calls to llvm.coro.prepare.retcon, a barrier meant to prevent /// IPO from operating on calls to a retcon coroutine before it's been /// split. This is only safe to do after we've split all retcon @@ -1638,8 +2000,17 @@ static bool replaceAllPrepares(Function *PrepareFn, CallGraph &CG) { } static bool declaresCoroSplitIntrinsics(const Module &M) { - return coro::declaresIntrinsics( - M, {"llvm.coro.begin", "llvm.coro.prepare.retcon"}); + return coro::declaresIntrinsics(M, {"llvm.coro.begin", + "llvm.coro.prepare.retcon", + "llvm.coro.prepare.async"}); +} + +static void addPrepareFunction(const Module &M, + SmallVectorImpl &Fns, + StringRef Name) { + auto *PrepareFn = M.getFunction(Name); + if (PrepareFn && !PrepareFn->use_empty()) + Fns.push_back(PrepareFn); } PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C, @@ -1655,10 +2026,10 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C, if (!declaresCoroSplitIntrinsics(M)) return PreservedAnalyses::all(); - // Check for uses of llvm.coro.prepare.retcon. - const auto *PrepareFn = M.getFunction("llvm.coro.prepare.retcon"); - if (PrepareFn && PrepareFn->use_empty()) - PrepareFn = nullptr; + // Check for uses of llvm.coro.prepare.retcon/async. + SmallVector PrepareFns; + addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.retcon"); + addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.async"); // Find coroutines for processing. SmallVector Coroutines; @@ -1666,12 +2037,14 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C, if (N.getFunction().hasFnAttribute(CORO_PRESPLIT_ATTR)) Coroutines.push_back(&N); - if (Coroutines.empty() && !PrepareFn) + if (Coroutines.empty() && PrepareFns.empty()) return PreservedAnalyses::all(); - if (Coroutines.empty()) - llvm_unreachable("new pass manager cannot yet handle " - "'llvm.coro.prepare.retcon'"); + if (Coroutines.empty()) { + for (auto *PrepareFn : PrepareFns) { + replaceAllPrepares(PrepareFn, CG, C); + } + } // Split all the coroutines. for (LazyCallGraph::Node *N : Coroutines) { @@ -1681,17 +2054,7 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C, LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F.getName() << "' state: " << Value << "\n"); if (Value == UNPREPARED_FOR_SPLIT) { - // Enqueue a second iteration of the CGSCC pipeline. - // N.B.: - // The CoroSplitLegacy pass "triggers" a restart of the CGSCC pass - // pipeline by inserting an indirect function call that the - // CoroElideLegacy pass then replaces with a direct function call. The - // legacy CGSCC pipeline's implicit behavior was as if wrapped in the new - // pass manager abstraction DevirtSCCRepeatedPass. - // - // This pass does not need to "trigger" another run of the pipeline. - // Instead, it simply enqueues the same RefSCC onto the pipeline's - // worklist. + // Enqueue a second iteration of the CGSCC pipeline on this SCC. UR.CWorklist.insert(&C); F.addFnAttr(CORO_PRESPLIT_ATTR, PREPARED_FOR_SPLIT); continue; @@ -1699,13 +2062,23 @@ PreservedAnalyses CoroSplitPass::run(LazyCallGraph::SCC &C, F.removeFnAttr(CORO_PRESPLIT_ATTR); SmallVector Clones; - const coro::Shape Shape = splitCoroutine(F, Clones); + const coro::Shape Shape = splitCoroutine(F, Clones, ReuseFrameSlot); updateCallGraphAfterCoroutineSplit(*N, Shape, Clones, C, CG, AM, UR, FAM); + + if ((Shape.ABI == coro::ABI::Async || Shape.ABI == coro::ABI::Retcon || + Shape.ABI == coro::ABI::RetconOnce) && + !Shape.CoroSuspends.empty()) { + // Run the CGSCC pipeline on the newly split functions. + // All clones will be in the same RefSCC, so choose a random clone. + UR.RCWorklist.insert(CG.lookupRefSCC(CG.get(*Clones[0]))); + } } - if (PrepareFn) - llvm_unreachable("new pass manager cannot yet handle " - "'llvm.coro.prepare.retcon'"); + if (!PrepareFns.empty()) { + for (auto *PrepareFn : PrepareFns) { + replaceAllPrepares(PrepareFn, CG, C); + } + } return PreservedAnalyses::none(); } @@ -1723,11 +2096,13 @@ namespace { struct CoroSplitLegacy : public CallGraphSCCPass { static char ID; // Pass identification, replacement for typeid - CoroSplitLegacy() : CallGraphSCCPass(ID) { + CoroSplitLegacy(bool ReuseFrameSlot = false) + : CallGraphSCCPass(ID), ReuseFrameSlot(ReuseFrameSlot) { initializeCoroSplitLegacyPass(*PassRegistry::getPassRegistry()); } bool Run = false; + bool ReuseFrameSlot; // A coroutine is identified by the presence of coro.begin intrinsic, if // we don't have any, this pass has nothing to do. @@ -1741,10 +2116,10 @@ struct CoroSplitLegacy : public CallGraphSCCPass { return false; // Check for uses of llvm.coro.prepare.retcon. - auto PrepareFn = - SCC.getCallGraph().getModule().getFunction("llvm.coro.prepare.retcon"); - if (PrepareFn && PrepareFn->use_empty()) - PrepareFn = nullptr; + SmallVector PrepareFns; + auto &M = SCC.getCallGraph().getModule(); + addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.retcon"); + addPrepareFunction(M, PrepareFns, "llvm.coro.prepare.async"); // Find coroutines for processing. SmallVector Coroutines; @@ -1753,13 +2128,17 @@ struct CoroSplitLegacy : public CallGraphSCCPass { if (F->hasFnAttribute(CORO_PRESPLIT_ATTR)) Coroutines.push_back(F); - if (Coroutines.empty() && !PrepareFn) + if (Coroutines.empty() && PrepareFns.empty()) return false; CallGraph &CG = getAnalysis().getCallGraph(); - if (Coroutines.empty()) - return replaceAllPrepares(PrepareFn, CG); + if (Coroutines.empty()) { + bool Changed = false; + for (auto *PrepareFn : PrepareFns) + Changed |= replaceAllPrepares(PrepareFn, CG); + return Changed; + } createDevirtTriggerFunc(CG, SCC); @@ -1769,6 +2148,12 @@ struct CoroSplitLegacy : public CallGraphSCCPass { StringRef Value = Attr.getValueAsString(); LLVM_DEBUG(dbgs() << "CoroSplit: Processing coroutine '" << F->getName() << "' state: " << Value << "\n"); + // Async lowering marks coroutines to trigger a restart of the pipeline + // after it has split them. + if (Value == ASYNC_RESTART_AFTER_SPLIT) { + F->removeFnAttr(CORO_PRESPLIT_ATTR); + continue; + } if (Value == UNPREPARED_FOR_SPLIT) { prepareForSplit(*F, CG); continue; @@ -1776,11 +2161,17 @@ struct CoroSplitLegacy : public CallGraphSCCPass { F->removeFnAttr(CORO_PRESPLIT_ATTR); SmallVector Clones; - const coro::Shape Shape = splitCoroutine(*F, Clones); + const coro::Shape Shape = splitCoroutine(*F, Clones, ReuseFrameSlot); updateCallGraphAfterCoroutineSplit(*F, Shape, Clones, CG, SCC); + if (Shape.ABI == coro::ABI::Async) { + // Restart SCC passes. + // Mark function for CoroElide pass. It will devirtualize causing a + // restart of the SCC pipeline. + prepareForSplit(*F, CG, true /*MarkForAsyncRestart*/); + } } - if (PrepareFn) + for (auto *PrepareFn : PrepareFns) replaceAllPrepares(PrepareFn, CG); return true; @@ -1807,4 +2198,6 @@ INITIALIZE_PASS_END( "Split coroutine into a set of functions driving its state machine", false, false) -Pass *llvm::createCoroSplitLegacyPass() { return new CoroSplitLegacy(); } +Pass *llvm::createCoroSplitLegacyPass(bool ReuseFrameSlot) { + return new CoroSplitLegacy(ReuseFrameSlot); +} diff --git a/llvm/lib/Transforms/Coroutines/Coroutines.cpp b/llvm/lib/Transforms/Coroutines/Coroutines.cpp index 87c3a8b0d0cf..6699a5c46313 100644 --- a/llvm/lib/Transforms/Coroutines/Coroutines.cpp +++ b/llvm/lib/Transforms/Coroutines/Coroutines.cpp @@ -69,7 +69,7 @@ static void addCoroutineScalarOptimizerPasses(const PassManagerBuilder &Builder, static void addCoroutineSCCPasses(const PassManagerBuilder &Builder, legacy::PassManagerBase &PM) { - PM.add(createCoroSplitLegacyPass()); + PM.add(createCoroSplitLegacyPass(Builder.OptLevel != 0)); } static void addCoroutineOptimizerLastPasses(const PassManagerBuilder &Builder, @@ -124,17 +124,23 @@ static bool isCoroutineIntrinsicName(StringRef Name) { // NOTE: Must be sorted! static const char *const CoroIntrinsics[] = { "llvm.coro.alloc", + "llvm.coro.async.context.alloc", + "llvm.coro.async.context.dealloc", + "llvm.coro.async.store_resume", "llvm.coro.begin", "llvm.coro.destroy", "llvm.coro.done", "llvm.coro.end", + "llvm.coro.end.async", "llvm.coro.frame", "llvm.coro.free", "llvm.coro.id", + "llvm.coro.id.async", "llvm.coro.id.retcon", "llvm.coro.id.retcon.once", "llvm.coro.noop", "llvm.coro.param", + "llvm.coro.prepare.async", "llvm.coro.prepare.retcon", "llvm.coro.promise", "llvm.coro.resume", @@ -142,6 +148,7 @@ static bool isCoroutineIntrinsicName(StringRef Name) { "llvm.coro.size", "llvm.coro.subfn.addr", "llvm.coro.suspend", + "llvm.coro.suspend.async", "llvm.coro.suspend.retcon", }; return Intrinsic::lookupLLVMIntrinsicByName(CoroIntrinsics, Name) != -1; @@ -269,6 +276,12 @@ void coro::Shape::buildFrom(Function &F) { if (II->use_empty()) UnusedCoroSaves.push_back(cast(II)); break; + case Intrinsic::coro_suspend_async: { + auto *Suspend = cast(II); + Suspend->checkWellFormed(); + CoroSuspends.push_back(Suspend); + break; + } case Intrinsic::coro_suspend_retcon: { auto Suspend = cast(II); CoroSuspends.push_back(Suspend); @@ -304,11 +317,16 @@ void coro::Shape::buildFrom(Function &F) { CoroBegin = CB; break; } + case Intrinsic::coro_end_async: case Intrinsic::coro_end: - CoroEnds.push_back(cast(II)); - if (CoroEnds.back()->isFallthrough()) { + CoroEnds.push_back(cast(II)); + if (auto *AsyncEnd = dyn_cast(II)) { + AsyncEnd->checkWellFormed(); + } + if (CoroEnds.back()->isFallthrough() && isa(II)) { // Make sure that the fallthrough coro.end is the first element in the // CoroEnds vector. + // Note: I don't think this is neccessary anymore. if (CoroEnds.size() > 1) { if (CoroEnds.front()->isFallthrough()) report_fatal_error( @@ -341,7 +359,7 @@ void coro::Shape::buildFrom(Function &F) { } // Replace all coro.ends with unreachable instruction. - for (CoroEndInst *CE : CoroEnds) + for (AnyCoroEndInst *CE : CoroEnds) changeToUnreachable(CE, /*UseLLVMTrap=*/false); return; @@ -371,7 +389,23 @@ void coro::Shape::buildFrom(Function &F) { } break; } - + case Intrinsic::coro_id_async: { + auto *AsyncId = cast(Id); + AsyncId->checkWellFormed(); + this->ABI = coro::ABI::Async; + this->AsyncLowering.Context = AsyncId->getStorage(); + this->AsyncLowering.ContextArgNo = AsyncId->getStorageArgumentIndex(); + this->AsyncLowering.ContextHeaderSize = AsyncId->getStorageSize(); + this->AsyncLowering.ContextAlignment = + AsyncId->getStorageAlignment().value(); + this->AsyncLowering.AsyncFuncPointer = AsyncId->getAsyncFunctionPointer(); + auto &Context = F.getContext(); + auto *Int8PtrTy = Type::getInt8PtrTy(Context); + auto *VoidTy = Type::getVoidTy(Context); + this->AsyncLowering.AsyncFuncTy = + FunctionType::get(VoidTy, {Int8PtrTy, Int8PtrTy, Int8PtrTy}, false); + break; + }; case Intrinsic::coro_id_retcon: case Intrinsic::coro_id_retcon_once: { auto ContinuationId = cast(Id); @@ -512,6 +546,8 @@ Value *coro::Shape::emitAlloc(IRBuilder<> &Builder, Value *Size, addCallToCallGraph(CG, Call, Alloc); return Call; } + case coro::ABI::Async: + llvm_unreachable("can't allocate memory in coro async-lowering"); } llvm_unreachable("Unknown coro::ABI enum"); } @@ -532,6 +568,8 @@ void coro::Shape::emitDealloc(IRBuilder<> &Builder, Value *Ptr, addCallToCallGraph(CG, Call, Dealloc); return; } + case coro::ABI::Async: + llvm_unreachable("can't allocate memory in coro async-lowering"); } llvm_unreachable("Unknown coro::ABI enum"); } @@ -633,6 +671,67 @@ void AnyCoroIdRetconInst::checkWellFormed() const { checkWFDealloc(this, getArgOperand(DeallocArg)); } +static void checkAsyncFuncPointer(const Instruction *I, Value *V) { + auto *AsyncFuncPtrAddr = dyn_cast(V->stripPointerCasts()); + if (!AsyncFuncPtrAddr) + fail(I, "llvm.coro.id.async async function pointer not a global", V); + + auto *StructTy = + cast(AsyncFuncPtrAddr->getType()->getPointerElementType()); + if (StructTy->isOpaque() || !StructTy->isPacked() || + StructTy->getNumElements() != 2 || + !StructTy->getElementType(0)->isIntegerTy(32) || + !StructTy->getElementType(1)->isIntegerTy(32)) + fail(I, + "llvm.coro.id.async async function pointer argument's type is not " + "<{i32, i32}>", + V); +} + +void CoroIdAsyncInst::checkWellFormed() const { + checkConstantInt(this, getArgOperand(SizeArg), + "size argument to coro.id.async must be constant"); + checkConstantInt(this, getArgOperand(AlignArg), + "alignment argument to coro.id.async must be constant"); + checkConstantInt(this, getArgOperand(StorageArg), + "storage argument offset to coro.id.async must be constant"); + checkAsyncFuncPointer(this, getArgOperand(AsyncFuncPtrArg)); +} + +static void checkAsyncContextProjectFunction(const Instruction *I, + Function *F) { + auto *FunTy = cast(F->getType()->getPointerElementType()); + if (!FunTy->getReturnType()->isPointerTy() || + !FunTy->getReturnType()->getPointerElementType()->isIntegerTy(8)) + fail(I, + "llvm.coro.suspend.async resume function projection function must " + "return an i8* type", + F); + if (FunTy->getNumParams() != 1 || !FunTy->getParamType(0)->isPointerTy() || + !FunTy->getParamType(0)->getPointerElementType()->isIntegerTy(8)) + fail(I, + "llvm.coro.suspend.async resume function projection function must " + "take one i8* type as parameter", + F); +} + +void CoroSuspendAsyncInst::checkWellFormed() const { + checkAsyncContextProjectFunction(this, getAsyncContextProjectionFunction()); +} + +void CoroAsyncEndInst::checkWellFormed() const { + auto *MustTailCallFunc = getMustTailCallFunction(); + if (!MustTailCallFunc) + return; + auto *FnTy = + cast(MustTailCallFunc->getType()->getPointerElementType()); + if (FnTy->getNumParams() != (getNumArgOperands() - 3)) + fail(this, + "llvm.coro.end.async must tail call function argument type must " + "match the tail arguments", + MustTailCallFunc); +} + void LLVMAddCoroEarlyPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createCoroEarlyLegacyPass()); } diff --git a/llvm/lib/Transforms/HelloNew/HelloWorld.cpp b/llvm/lib/Transforms/HelloNew/HelloWorld.cpp new file mode 100644 index 000000000000..dea94f8a8f62 --- /dev/null +++ b/llvm/lib/Transforms/HelloNew/HelloWorld.cpp @@ -0,0 +1,17 @@ +//===-- HelloWorld.cpp - Example Transformations --------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/HelloNew/HelloWorld.h" + +using namespace llvm; + +PreservedAnalyses HelloWorldPass::run(Function &F, + FunctionAnalysisManager &AM) { + errs() << F.getName() << "\n"; + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp index 53f9512f86f3..532599b42e0d 100644 --- a/llvm/lib/Transforms/IPO/AlwaysInliner.cpp +++ b/llvm/lib/Transforms/IPO/AlwaysInliner.cpp @@ -13,8 +13,10 @@ #include "llvm/Transforms/IPO/AlwaysInliner.h" #include "llvm/ADT/SetVector.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/InlineCost.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/CallingConv.h" #include "llvm/IR/DataLayout.h" @@ -39,12 +41,19 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M, auto GetAssumptionCache = [&](Function &F) -> AssumptionCache & { return FAM.getResult(F); }; - InlineFunctionInfo IFI(/*cg=*/nullptr, GetAssumptionCache); + auto &PSI = MAM.getResult(M); SmallSetVector Calls; bool Changed = false; SmallVector InlinedFunctions; - for (Function &F : M) + for (Function &F : M) { + // When callee coroutine function is inlined into caller coroutine function + // before coro-split pass, + // coro-early pass can not handle this quiet well. + // So we won't inline the coroutine function if it have not been unsplited + if (F.isPresplitCoroutine()) + continue; + if (!F.isDeclaration() && F.hasFnAttribute(Attribute::AlwaysInline) && isInlineViable(F).isSuccess()) { Calls.clear(); @@ -54,18 +63,41 @@ PreservedAnalyses AlwaysInlinerPass::run(Module &M, if (CB->getCalledFunction() == &F) Calls.insert(CB); - for (CallBase *CB : Calls) - // FIXME: We really shouldn't be able to fail to inline at this point! - // We should do something to log or check the inline failures here. - Changed |= - InlineFunction(*CB, IFI, /*CalleeAAR=*/nullptr, InsertLifetime) - .isSuccess(); + for (CallBase *CB : Calls) { + Function *Caller = CB->getCaller(); + OptimizationRemarkEmitter ORE(Caller); + auto OIC = shouldInline( + *CB, + [&](CallBase &CB) { + return InlineCost::getAlways("always inline attribute"); + }, + ORE); + assert(OIC); + emitInlinedInto(ORE, CB->getDebugLoc(), CB->getParent(), F, *Caller, + *OIC, false, DEBUG_TYPE); + + InlineFunctionInfo IFI( + /*cg=*/nullptr, GetAssumptionCache, &PSI, + &FAM.getResult(*(CB->getCaller())), + &FAM.getResult(F)); + + InlineResult Res = InlineFunction( + *CB, IFI, &FAM.getResult(F), InsertLifetime); + assert(Res.isSuccess() && "unexpected failure to inline"); + (void)Res; + + // Merge the attributes based on the inlining. + AttributeFuncs::mergeAttributesForInlining(*Caller, F); + + Changed = true; + } // Remember to try and delete this function afterward. This both avoids // re-walking the rest of the module and avoids dealing with any iterator // invalidation issues while deleting functions. InlinedFunctions.push_back(&F); } + } // Remove any live functions. erase_if(InlinedFunctions, [&](Function *F) { @@ -158,6 +190,13 @@ InlineCost AlwaysInlinerLegacyPass::getInlineCost(CallBase &CB) { if (!Callee) return InlineCost::getNever("indirect call"); + // When callee coroutine function is inlined into caller coroutine function + // before coro-split pass, + // coro-early pass can not handle this quiet well. + // So we won't inline the coroutine function if it have not been unsplited + if (Callee->isPresplitCoroutine()) + return InlineCost::getNever("unsplited coroutine call"); + // FIXME: We shouldn't even get here for declarations. if (Callee->isDeclaration()) return InlineCost::getNever("no definition"); diff --git a/llvm/lib/Transforms/IPO/Annotation2Metadata.cpp b/llvm/lib/Transforms/IPO/Annotation2Metadata.cpp new file mode 100644 index 000000000000..5ca4e24df8fc --- /dev/null +++ b/llvm/lib/Transforms/IPO/Annotation2Metadata.cpp @@ -0,0 +1,106 @@ +//===-- Annotation2Metadata.cpp - Add !annotation metadata. ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Add !annotation metadata for entries in @llvm.global.anotations, generated +// using __attribute__((annotate("_name"))) on functions in Clang. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/Annotation2Metadata.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/IR/Module.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Transforms/IPO.h" + +using namespace llvm; + +#define DEBUG_TYPE "annotation2metadata" + +static bool convertAnnotation2Metadata(Module &M) { + // Only add !annotation metadata if the corresponding remarks pass is also + // enabled. + if (!OptimizationRemarkEmitter::allowExtraAnalysis(M.getContext(), + "annotation-remarks")) + return false; + + auto *Annotations = M.getGlobalVariable("llvm.global.annotations"); + auto *C = dyn_cast_or_null(Annotations); + if (!C || C->getNumOperands() != 1) + return false; + + C = cast(C->getOperand(0)); + + // Iterate over all entries in C and attach !annotation metadata to suitable + // entries. + for (auto &Op : C->operands()) { + // Look at the operands to check if we can use the entry to generate + // !annotation metadata. + auto *OpC = dyn_cast(&Op); + if (!OpC || OpC->getNumOperands() != 4) + continue; + auto *StrGEP = dyn_cast(OpC->getOperand(1)); + if (!StrGEP || StrGEP->getNumOperands() < 2) + continue; + auto *StrC = dyn_cast(StrGEP->getOperand(0)); + if (!StrC) + continue; + auto *StrData = dyn_cast(StrC->getOperand(0)); + if (!StrData) + continue; + // Look through bitcast. + auto *Bitcast = dyn_cast(OpC->getOperand(0)); + if (!Bitcast || Bitcast->getOpcode() != Instruction::BitCast) + continue; + auto *Fn = dyn_cast(Bitcast->getOperand(0)); + if (!Fn) + continue; + + // Add annotation to all instructions in the function. + for (auto &I : instructions(Fn)) + I.addAnnotationMetadata(StrData->getAsCString()); + } + return true; +} + +namespace { +struct Annotation2MetadataLegacy : public ModulePass { + static char ID; + + Annotation2MetadataLegacy() : ModulePass(ID) { + initializeAnnotation2MetadataLegacyPass(*PassRegistry::getPassRegistry()); + } + + bool runOnModule(Module &M) override { return convertAnnotation2Metadata(M); } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +} // end anonymous namespace + +char Annotation2MetadataLegacy::ID = 0; + +INITIALIZE_PASS_BEGIN(Annotation2MetadataLegacy, DEBUG_TYPE, + "Annotation2Metadata", false, false) +INITIALIZE_PASS_END(Annotation2MetadataLegacy, DEBUG_TYPE, + "Annotation2Metadata", false, false) + +ModulePass *llvm::createAnnotation2MetadataLegacyPass() { + return new Annotation2MetadataLegacy(); +} + +PreservedAnalyses Annotation2MetadataPass::run(Module &M, + ModuleAnalysisManager &AM) { + convertAnnotation2Metadata(M); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp index ad0d7eb51507..7998a1ae5c6e 100644 --- a/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp +++ b/llvm/lib/Transforms/IPO/ArgumentPromotion.cpp @@ -33,11 +33,11 @@ #include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/Twine.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/CGSCCPassManager.h" @@ -142,7 +142,7 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, // Simple byval argument? Just add all the struct element types. Type *AgTy = cast(I->getType())->getElementType(); StructType *STy = cast(AgTy); - Params.insert(Params.end(), STy->element_begin(), STy->element_end()); + llvm::append_range(Params, STy->elements()); ArgAttrVec.insert(ArgAttrVec.end(), STy->getNumElements(), AttributeSet()); ++NumByValArgsPromoted; @@ -153,10 +153,6 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, } else if (I->use_empty()) { // Dead argument (which are always marked as promotable) ++NumArgumentsDead; - - // There may be remaining metadata uses of the argument for things like - // llvm.dbg.value. Replace them with undef. - I->replaceAllUsesWith(UndefValue::get(I->getType())); } else { // Okay, this is being promoted. This means that the only uses are loads // or GEPs which are only used by loads @@ -164,13 +160,19 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, // In this table, we will track which indices are loaded from the argument // (where direct loads are tracked as no indices). ScalarizeTable &ArgIndices = ScalarizedElements[&*I]; - for (User *U : I->users()) { + for (User *U : make_early_inc_range(I->users())) { Instruction *UI = cast(U); Type *SrcTy; if (LoadInst *L = dyn_cast(UI)) SrcTy = L->getType(); else SrcTy = cast(UI)->getSourceElementType(); + // Skip dead GEPs and remove them. + if (isa(UI) && UI->use_empty()) { + UI->eraseFromParent(); + continue; + } + IndicesVector Indices; Indices.reserve(UI->getNumOperands() - 1); // Since loads will only have a single operand, and GEPs only a single @@ -218,9 +220,11 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, Function *NF = Function::Create(NFTy, F->getLinkage(), F->getAddressSpace(), F->getName()); NF->copyAttributesFrom(F); + NF->copyMetadata(F, 0); - // Patch the pointer to LLVM function in debug info descriptor. - NF->setSubprogram(F->getSubprogram()); + // The new function will have the !dbg metadata copied from the original + // function. The original function may not be deleted, and dbg metadata need + // to be unique so we need to drop it. F->setSubprogram(nullptr); LLVM_DEBUG(dbgs() << "ARG PROMOTION: Promoting to:" << *NF << "\n" @@ -414,6 +418,11 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, continue; } + // There potentially are metadata uses for things like llvm.dbg.value. + // Replace them with undef, after handling the other regular uses. + auto RauwUndefMetadata = make_scope_exit( + [&]() { I->replaceAllUsesWith(UndefValue::get(I->getType())); }); + if (I->use_empty()) continue; @@ -433,6 +442,8 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, << "' in function '" << F->getName() << "'\n"); } else { GetElementPtrInst *GEP = cast(I->user_back()); + assert(!GEP->use_empty() && + "GEPs without uses should be cleaned up already"); IndicesVector Operands; Operands.reserve(GEP->getNumIndices()); for (User::op_iterator II = GEP->idx_begin(), IE = GEP->idx_end(); @@ -465,7 +476,6 @@ doPromotion(Function *F, SmallPtrSetImpl &ArgsToPromote, GEP->eraseFromParent(); } } - // Increment I2 past all of the arguments added for this promoted pointer. std::advance(I2, ArgIndices.size()); } @@ -672,11 +682,7 @@ static bool isSafeToPromoteArgument(Argument *Arg, Type *ByValTy, AAResults &AAR if (GEP->use_empty()) { // Dead GEP's cause trouble later. Just remove them if we run into // them. - GEP->eraseFromParent(); - // TODO: This runs the above loop over and over again for dead GEPs - // Couldn't we just do increment the UI iterator earlier and erase the - // use? - return isSafeToPromoteArgument(Arg, ByValTy, AAR, MaxElements); + continue; } if (!UpdateBaseTy(GEP->getSourceElementType())) @@ -816,14 +822,12 @@ static bool canPaddingBeAccessed(Argument *arg) { // Scan through the uses recursively to make sure the pointer is always used // sanely. - SmallVector WorkList; - WorkList.insert(WorkList.end(), arg->user_begin(), arg->user_end()); + SmallVector WorkList(arg->users()); while (!WorkList.empty()) { - Value *V = WorkList.back(); - WorkList.pop_back(); + Value *V = WorkList.pop_back_val(); if (isa(V) || isa(V)) { if (PtrValues.insert(V).second) - WorkList.insert(WorkList.end(), V->user_begin(), V->user_end()); + llvm::append_range(WorkList, V->users()); } else if (StoreInst *Store = dyn_cast(V)) { Stores.push_back(Store); } else if (!isa(V)) { diff --git a/llvm/lib/Transforms/IPO/Attributor.cpp b/llvm/lib/Transforms/IPO/Attributor.cpp index f96dac5f3515..03ad45135001 100644 --- a/llvm/lib/Transforms/IPO/Attributor.cpp +++ b/llvm/lib/Transforms/IPO/Attributor.cpp @@ -15,31 +15,47 @@ #include "llvm/Transforms/IPO/Attributor.h" +#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/Statistic.h" +#include "llvm/ADT/TinyPtrVector.h" +#include "llvm/Analysis/InlineCost.h" #include "llvm/Analysis/LazyValueInfo.h" +#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/MustExecute.h" #include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/GlobalValue.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/NoFolder.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DebugCounter.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/GraphWriter.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include +#include using namespace llvm; #define DEBUG_TYPE "attributor" +DEBUG_COUNTER(ManifestDBGCounter, "attributor-manifest", + "Determine what attributes are manifested in the IR"); + STATISTIC(NumFnDeleted, "Number of function deleted"); STATISTIC(NumFnWithExactDefinition, "Number of functions with exact definitions"); STATISTIC(NumFnWithoutExactDefinition, "Number of functions without exact definitions"); -STATISTIC(NumFnShallowWrapperCreated, "Number of shallow wrappers created"); +STATISTIC(NumFnShallowWrappersCreated, "Number of shallow wrappers created"); STATISTIC(NumAttributesTimedOut, "Number of abstract attributes timed out before fixpoint"); STATISTIC(NumAttributesValidFixpoint, @@ -61,6 +77,14 @@ static cl::opt MaxFixpointIterations("attributor-max-iterations", cl::Hidden, cl::desc("Maximal number of fixpoint iterations."), cl::init(32)); + +static cl::opt MaxInitializationChainLengthX( + "attributor-max-initialization-chain-length", cl::Hidden, + cl::desc( + "Maximal number of chained initializations (to avoid stack overflows)"), + cl::location(MaxInitializationChainLength), cl::init(1024)); +unsigned llvm::MaxInitializationChainLength; + static cl::opt VerifyMaxFixpointIterations( "attributor-max-iterations-verify", cl::Hidden, cl::desc("Verify that max-iterations is a tight bound for a fixpoint"), @@ -79,20 +103,52 @@ static cl::opt "wrappers for non-exact definitions."), cl::init(false)); +static cl::opt + AllowDeepWrapper("attributor-allow-deep-wrappers", cl::Hidden, + cl::desc("Allow the Attributor to use IP information " + "derived from non-exact functions via cloning"), + cl::init(false)); + +// These options can only used for debug builds. +#ifndef NDEBUG static cl::list SeedAllowList("attributor-seed-allow-list", cl::Hidden, - cl::desc("Comma seperated list of attrbute names that are " + cl::desc("Comma seperated list of attribute names that are " "allowed to be seeded."), cl::ZeroOrMore, cl::CommaSeparated); +static cl::list FunctionSeedAllowList( + "attributor-function-seed-allow-list", cl::Hidden, + cl::desc("Comma seperated list of function names that are " + "allowed to be seeded."), + cl::ZeroOrMore, cl::CommaSeparated); +#endif + +static cl::opt + DumpDepGraph("attributor-dump-dep-graph", cl::Hidden, + cl::desc("Dump the dependency graph to dot files."), + cl::init(false)); + +static cl::opt DepGraphDotFileNamePrefix( + "attributor-depgraph-dot-filename-prefix", cl::Hidden, + cl::desc("The prefix used for the CallGraph dot file names.")); + +static cl::opt ViewDepGraph("attributor-view-dep-graph", cl::Hidden, + cl::desc("View the dependency graph."), + cl::init(false)); + +static cl::opt PrintDependencies("attributor-print-dep", cl::Hidden, + cl::desc("Print attribute dependencies"), + cl::init(false)); + /// Logic operators for the change status enum class. /// ///{ -ChangeStatus llvm::operator|(ChangeStatus l, ChangeStatus r) { - return l == ChangeStatus::CHANGED ? l : r; +ChangeStatus llvm::operator|(ChangeStatus L, ChangeStatus R) { + return L == ChangeStatus::CHANGED ? L : R; } -ChangeStatus llvm::operator&(ChangeStatus l, ChangeStatus r) { - return l == ChangeStatus::UNCHANGED ? l : r; +ChangeStatus llvm::operator&(ChangeStatus L, ChangeStatus R) { + return L == ChangeStatus::UNCHANGED ? L : R; } ///} @@ -145,7 +201,7 @@ Argument *IRPosition::getAssociatedArgument() const { // Not an Argument and no argument number means this is not a call site // argument, thus we cannot find a callback argument to return. - int ArgNo = getArgNo(); + int ArgNo = getCallSiteArgNo(); if (ArgNo < 0) return nullptr; @@ -273,6 +329,13 @@ const IRPosition SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { IRPositions.emplace_back(IRP); + // Helper to determine if operand bundles on a call site are benin or + // potentially problematic. We handle only llvm.assume for now. + auto CanIgnoreOperandBundles = [](const CallBase &CB) { + return (isa(CB) && + cast(CB).getIntrinsicID() == Intrinsic ::assume); + }; + const auto *CB = dyn_cast(&IRP.getAnchorValue()); switch (IRP.getPositionKind()) { case IRPosition::IRP_INVALID: @@ -287,7 +350,7 @@ SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { assert(CB && "Expected call site!"); // TODO: We need to look at the operand bundles similar to the redirection // in CallBase. - if (!CB->hasOperandBundles()) + if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) if (const Function *Callee = CB->getCalledFunction()) IRPositions.emplace_back(IRPosition::function(*Callee)); return; @@ -295,7 +358,7 @@ SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { assert(CB && "Expected call site!"); // TODO: We need to look at the operand bundles similar to the redirection // in CallBase. - if (!CB->hasOperandBundles()) { + if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) { if (const Function *Callee = CB->getCalledFunction()) { IRPositions.emplace_back(IRPosition::returned(*Callee)); IRPositions.emplace_back(IRPosition::function(*Callee)); @@ -312,16 +375,16 @@ SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { IRPositions.emplace_back(IRPosition::callsite_function(*CB)); return; case IRPosition::IRP_CALL_SITE_ARGUMENT: { - int ArgNo = IRP.getArgNo(); - assert(CB && ArgNo >= 0 && "Expected call site!"); + assert(CB && "Expected call site!"); // TODO: We need to look at the operand bundles similar to the redirection // in CallBase. - if (!CB->hasOperandBundles()) { + if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) { const Function *Callee = CB->getCalledFunction(); - if (Callee && Callee->arg_size() > unsigned(ArgNo)) - IRPositions.emplace_back(IRPosition::argument(*Callee->getArg(ArgNo))); - if (Callee) + if (Callee) { + if (Argument *Arg = IRP.getAssociatedArgument()) + IRPositions.emplace_back(IRPosition::argument(*Arg)); IRPositions.emplace_back(IRPosition::function(*Callee)); + } } IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue())); return; @@ -459,7 +522,7 @@ void IRPosition::verify() { "Expected call base argument operand for a 'call site argument' " "position"); assert(cast(U->getUser())->getArgOperandNo(U) == - unsigned(getArgNo()) && + unsigned(getCallSiteArgNo()) && "Argument number mismatch!"); assert(U->get() == &getAssociatedValue() && "Associated value mismatch!"); return; @@ -498,8 +561,10 @@ Attributor::getAssumedConstant(const Value &V, const AbstractAttribute &AA, Attributor::~Attributor() { // The abstract attributes are allocated via the BumpPtrAllocator Allocator, // thus we cannot delete them. We can, and want to, destruct them though. - for (AbstractAttribute *AA : AllAbstractAttributes) + for (auto &DepAA : DG.SyntheticRoot.Deps) { + AbstractAttribute *AA = cast(DepAA.getPointer()); AA->~AbstractAttribute(); + } } bool Attributor::isAssumedDead(const AbstractAttribute &AA, @@ -864,13 +929,15 @@ bool Attributor::checkForAllInstructions(function_ref Pred, // TODO: use the function scope once we have call site AAReturnedValues. const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); - const auto &LivenessAA = - getAAFor(QueryingAA, QueryIRP, /* TrackDependence */ false); + const auto *LivenessAA = + CheckBBLivenessOnly ? nullptr + : &(getAAFor(QueryingAA, QueryIRP, + /* TrackDependence */ false)); auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*AssociatedFunction); if (!checkForAllInstructionsImpl(this, OpcodeInstMap, Pred, &QueryingAA, - &LivenessAA, Opcodes, CheckBBLivenessOnly)) + LivenessAA, Opcodes, CheckBBLivenessOnly)) return false; return true; @@ -903,8 +970,9 @@ bool Attributor::checkForAllReadWriteInstructions( } void Attributor::runTillFixpoint() { + TimeTraceScope TimeScope("Attributor::runTillFixpoint"); LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized " - << AllAbstractAttributes.size() + << DG.SyntheticRoot.Deps.size() << " abstract attributes.\n"); // Now that all abstract attributes are collected and initialized we start @@ -914,11 +982,11 @@ void Attributor::runTillFixpoint() { SmallVector ChangedAAs; SetVector Worklist, InvalidAAs; - Worklist.insert(AllAbstractAttributes.begin(), AllAbstractAttributes.end()); + Worklist.insert(DG.SyntheticRoot.begin(), DG.SyntheticRoot.end()); do { // Remember the size to determine new attributes. - size_t NumAAs = AllAbstractAttributes.size(); + size_t NumAAs = DG.SyntheticRoot.Deps.size(); LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter << ", Worklist size: " << Worklist.size() << "\n"); @@ -935,7 +1003,7 @@ void Attributor::runTillFixpoint() { while (!InvalidAA->Deps.empty()) { const auto &Dep = InvalidAA->Deps.back(); InvalidAA->Deps.pop_back(); - AbstractAttribute *DepAA = Dep.getPointer(); + AbstractAttribute *DepAA = cast(Dep.getPointer()); if (Dep.getInt() == unsigned(DepClassTy::OPTIONAL)) { Worklist.insert(DepAA); continue; @@ -953,7 +1021,8 @@ void Attributor::runTillFixpoint() { // changed to the work list. for (AbstractAttribute *ChangedAA : ChangedAAs) while (!ChangedAA->Deps.empty()) { - Worklist.insert(ChangedAA->Deps.back().getPointer()); + Worklist.insert( + cast(ChangedAA->Deps.back().getPointer())); ChangedAA->Deps.pop_back(); } @@ -981,8 +1050,8 @@ void Attributor::runTillFixpoint() { // Add attributes to the changed set if they have been created in the last // iteration. - ChangedAAs.append(AllAbstractAttributes.begin() + NumAAs, - AllAbstractAttributes.end()); + ChangedAAs.append(DG.SyntheticRoot.begin() + NumAAs, + DG.SyntheticRoot.end()); // Reset the work list and repopulate with the changed abstract attributes. // Note that dependent ones are added above. @@ -1015,7 +1084,8 @@ void Attributor::runTillFixpoint() { } while (!ChangedAA->Deps.empty()) { - ChangedAAs.push_back(ChangedAA->Deps.back().getPointer()); + ChangedAAs.push_back( + cast(ChangedAA->Deps.back().getPointer())); ChangedAA->Deps.pop_back(); } } @@ -1037,12 +1107,14 @@ void Attributor::runTillFixpoint() { } ChangeStatus Attributor::manifestAttributes() { - size_t NumFinalAAs = AllAbstractAttributes.size(); + TimeTraceScope TimeScope("Attributor::manifestAttributes"); + size_t NumFinalAAs = DG.SyntheticRoot.Deps.size(); unsigned NumManifested = 0; unsigned NumAtFixpoint = 0; ChangeStatus ManifestChange = ChangeStatus::UNCHANGED; - for (AbstractAttribute *AA : AllAbstractAttributes) { + for (auto &DepAA : DG.SyntheticRoot.Deps) { + AbstractAttribute *AA = cast(DepAA.getPointer()); AbstractState &State = AA->getState(); // If there is not already a fixpoint reached, we can now take the @@ -1059,6 +1131,10 @@ ChangeStatus Attributor::manifestAttributes() { // Skip dead code. if (isAssumedDead(*AA, nullptr, /* CheckBBLivenessOnly */ true)) continue; + // Check if the manifest debug counter that allows skipping manifestation of + // AAs + if (!DebugCounter::shouldExecute(ManifestDBGCounter)) + continue; // Manifest the state and record if we changed the IR. ChangeStatus LocalChange = AA->manifest(*this); if (LocalChange == ChangeStatus::CHANGED && AreStatisticsEnabled()) @@ -1082,11 +1158,14 @@ ChangeStatus Attributor::manifestAttributes() { NumAttributesValidFixpoint += NumAtFixpoint; (void)NumFinalAAs; - if (NumFinalAAs != AllAbstractAttributes.size()) { - for (unsigned u = NumFinalAAs; u < AllAbstractAttributes.size(); ++u) - errs() << "Unexpected abstract attribute: " << *AllAbstractAttributes[u] + if (NumFinalAAs != DG.SyntheticRoot.Deps.size()) { + for (unsigned u = NumFinalAAs; u < DG.SyntheticRoot.Deps.size(); ++u) + errs() << "Unexpected abstract attribute: " + << cast(DG.SyntheticRoot.Deps[u].getPointer()) << " :: " - << AllAbstractAttributes[u]->getIRPosition().getAssociatedValue() + << cast(DG.SyntheticRoot.Deps[u].getPointer()) + ->getIRPosition() + .getAssociatedValue() << "\n"; llvm_unreachable("Expected the final number of abstract attributes to " "remain unchanged!"); @@ -1094,7 +1173,50 @@ ChangeStatus Attributor::manifestAttributes() { return ManifestChange; } +void Attributor::identifyDeadInternalFunctions() { + // Identify dead internal functions and delete them. This happens outside + // the other fixpoint analysis as we might treat potentially dead functions + // as live to lower the number of iterations. If they happen to be dead, the + // below fixpoint loop will identify and eliminate them. + SmallVector InternalFns; + for (Function *F : Functions) + if (F->hasLocalLinkage()) + InternalFns.push_back(F); + + SmallPtrSet LiveInternalFns; + bool FoundLiveInternal = true; + while (FoundLiveInternal) { + FoundLiveInternal = false; + for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) { + Function *F = InternalFns[u]; + if (!F) + continue; + + bool AllCallSitesKnown; + if (checkForAllCallSites( + [&](AbstractCallSite ACS) { + Function *Callee = ACS.getInstruction()->getFunction(); + return ToBeDeletedFunctions.count(Callee) || + (Functions.count(Callee) && Callee->hasLocalLinkage() && + !LiveInternalFns.count(Callee)); + }, + *F, true, nullptr, AllCallSitesKnown)) { + continue; + } + + LiveInternalFns.insert(F); + InternalFns[u] = nullptr; + FoundLiveInternal = true; + } + } + + for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) + if (Function *F = InternalFns[u]) + ToBeDeletedFunctions.insert(F); +} + ChangeStatus Attributor::cleanupIR() { + TimeTraceScope TimeScope("Attributor::cleanupIR"); // Delete stuff at the end to avoid invalid references and a nice order. LLVM_DEBUG(dbgs() << "\n[Attributor] Delete at least " << ToBeDeletedFunctions.size() << " functions and " @@ -1205,50 +1327,45 @@ ChangeStatus Attributor::cleanupIR() { DetatchDeadBlocks(ToBeDeletedBBs, nullptr); } - // Identify dead internal functions and delete them. This happens outside - // the other fixpoint analysis as we might treat potentially dead functions - // as live to lower the number of iterations. If they happen to be dead, the - // below fixpoint loop will identify and eliminate them. - SmallVector InternalFns; - for (Function *F : Functions) - if (F->hasLocalLinkage()) - InternalFns.push_back(F); - - bool FoundDeadFn = true; - while (FoundDeadFn) { - FoundDeadFn = false; - for (unsigned u = 0, e = InternalFns.size(); u < e; ++u) { - Function *F = InternalFns[u]; - if (!F) - continue; - - bool AllCallSitesKnown; - if (!checkForAllCallSites( - [this](AbstractCallSite ACS) { - return ToBeDeletedFunctions.count( - ACS.getInstruction()->getFunction()); - }, - *F, true, nullptr, AllCallSitesKnown)) - continue; - - ToBeDeletedFunctions.insert(F); - InternalFns[u] = nullptr; - FoundDeadFn = true; - } - } + identifyDeadInternalFunctions(); // Rewrite the functions as requested during manifest. ChangeStatus ManifestChange = rewriteFunctionSignatures(CGModifiedFunctions); for (Function *Fn : CGModifiedFunctions) - CGUpdater.reanalyzeFunction(*Fn); + if (!ToBeDeletedFunctions.count(Fn)) + CGUpdater.reanalyzeFunction(*Fn); - for (Function *Fn : ToBeDeletedFunctions) + for (Function *Fn : ToBeDeletedFunctions) { + if (!Functions.count(Fn)) + continue; CGUpdater.removeFunction(*Fn); + } + + if (!ToBeChangedUses.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!ToBeChangedToUnreachableInsts.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!ToBeDeletedFunctions.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!ToBeDeletedBlocks.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!ToBeDeletedInsts.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!InvokeWithDeadSuccessor.empty()) + ManifestChange = ChangeStatus::CHANGED; + + if (!DeadInsts.empty()) + ManifestChange = ChangeStatus::CHANGED; NumFnDeleted += ToBeDeletedFunctions.size(); - LLVM_DEBUG(dbgs() << "[Attributor] Deleted " << NumFnDeleted + LLVM_DEBUG(dbgs() << "[Attributor] Deleted " << ToBeDeletedFunctions.size() << " functions after manifest.\n"); #ifdef EXPENSIVE_CHECKS @@ -1263,14 +1380,37 @@ ChangeStatus Attributor::cleanupIR() { } ChangeStatus Attributor::run() { - SeedingPeriod = false; + TimeTraceScope TimeScope("Attributor::run"); + + Phase = AttributorPhase::UPDATE; runTillFixpoint(); + + // dump graphs on demand + if (DumpDepGraph) + DG.dumpGraph(); + + if (ViewDepGraph) + DG.viewGraph(); + + if (PrintDependencies) + DG.print(); + + Phase = AttributorPhase::MANIFEST; ChangeStatus ManifestChange = manifestAttributes(); + + Phase = AttributorPhase::CLEANUP; ChangeStatus CleanupChange = cleanupIR(); + return ManifestChange | CleanupChange; } ChangeStatus Attributor::updateAA(AbstractAttribute &AA) { + TimeTraceScope TimeScope( + AA.getName() + std::to_string(AA.getIRPosition().getPositionKind()) + + "::updateAA"); + assert(Phase == AttributorPhase::UPDATE && + "We can update AA only in the update stage!"); + // Use a new dependence vector for this update. DependenceVector DV; DependenceStack.push_back(&DV); @@ -1298,23 +1438,7 @@ ChangeStatus Attributor::updateAA(AbstractAttribute &AA) { return CS; } -/// Create a shallow wrapper for \p F such that \p F has internal linkage -/// afterwards. It also sets the original \p F 's name to anonymous -/// -/// A wrapper is a function with the same type (and attributes) as \p F -/// that will only call \p F and return the result, if any. -/// -/// Assuming the declaration of looks like: -/// rty F(aty0 arg0, ..., atyN argN); -/// -/// The wrapper will then look as follows: -/// rty wrapper(aty0 arg0, ..., atyN argN) { -/// return F(arg0, ..., argN); -/// } -/// -static void createShallowWrapper(Function &F) { - assert(AllowShallowWrappers && - "Cannot create a wrapper if it is not allowed!"); +void Attributor::createShallowWrapper(Function &F) { assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!"); Module &M = *F.getParent(); @@ -1347,7 +1471,7 @@ static void createShallowWrapper(Function &F) { BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper); SmallVector Args; - auto FArgIt = F.arg_begin(); + Argument *FArgIt = F.arg_begin(); for (Argument &Arg : Wrapper->args()) { Args.push_back(&Arg); Arg.setName((FArgIt++)->getName()); @@ -1358,7 +1482,57 @@ static void createShallowWrapper(Function &F) { CI->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB); - NumFnShallowWrapperCreated++; + NumFnShallowWrappersCreated++; +} + +/// Make another copy of the function \p F such that the copied version has +/// internal linkage afterwards and can be analysed. Then we replace all uses +/// of the original function to the copied one +/// +/// Only non-exactly defined functions that have `linkonce_odr` or `weak_odr` +/// linkage can be internalized because these linkages guarantee that other +/// definitions with the same name have the same semantics as this one +/// +static Function *internalizeFunction(Function &F) { + assert(AllowDeepWrapper && "Cannot create a copy if not allowed."); + assert(!F.isDeclaration() && !F.hasExactDefinition() && + !GlobalValue::isInterposableLinkage(F.getLinkage()) && + "Trying to internalize function which cannot be internalized."); + + Module &M = *F.getParent(); + FunctionType *FnTy = F.getFunctionType(); + + // create a copy of the current function + Function *Copied = Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), + F.getName() + ".internalized"); + ValueToValueMapTy VMap; + auto *NewFArgIt = Copied->arg_begin(); + for (auto &Arg : F.args()) { + auto ArgName = Arg.getName(); + NewFArgIt->setName(ArgName); + VMap[&Arg] = &(*NewFArgIt++); + } + SmallVector Returns; + + // Copy the body of the original function to the new one + CloneFunctionInto(Copied, &F, VMap, /* ModuleLevelChanges */ false, Returns); + + // Set the linakage and visibility late as CloneFunctionInto has some implicit + // requirements. + Copied->setVisibility(GlobalValue::DefaultVisibility); + Copied->setLinkage(GlobalValue::PrivateLinkage); + + // Copy metadata + SmallVector, 1> MDs; + F.getAllMetadata(MDs); + for (auto MDIt : MDs) + Copied->addMetadata(MDIt.first, *MDIt.second); + + M.getFunctionList().insert(F.getIterator(), Copied); + F.replaceAllUsesWith(Copied); + Copied->setDSOLocal(true); + + return Copied; } bool Attributor::isValidFunctionSignatureRewrite( @@ -1461,9 +1635,17 @@ bool Attributor::registerFunctionSignatureRewrite( } bool Attributor::shouldSeedAttribute(AbstractAttribute &AA) { - if (SeedAllowList.size() == 0) - return true; - return std::count(SeedAllowList.begin(), SeedAllowList.end(), AA.getName()); + bool Result = true; +#ifndef NDEBUG + if (SeedAllowList.size() != 0) + Result = + std::count(SeedAllowList.begin(), SeedAllowList.end(), AA.getName()); + Function *Fn = AA.getAnchorScope(); + if (FunctionSeedAllowList.size() != 0 && Fn) + Result &= std::count(FunctionSeedAllowList.begin(), + FunctionSeedAllowList.end(), Fn->getName()); +#endif + return Result; } ChangeStatus Attributor::rewriteFunctionSignatures( @@ -1474,7 +1656,7 @@ ChangeStatus Attributor::rewriteFunctionSignatures( Function *OldFn = It.getFirst(); // Deleted functions do not require rewrites. - if (ToBeDeletedFunctions.count(OldFn)) + if (!Functions.count(OldFn) || ToBeDeletedFunctions.count(OldFn)) continue; const SmallVectorImpl> &ARIs = @@ -1617,8 +1799,8 @@ ChangeStatus Attributor::rewriteFunctionSignatures( assert(Success && "Assumed call site replacement to succeed!"); // Rewire the arguments. - auto OldFnArgIt = OldFn->arg_begin(); - auto NewFnArgIt = NewFn->arg_begin(); + Argument *OldFnArgIt = OldFn->arg_begin(); + Argument *NewFnArgIt = NewFn->arg_begin(); for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); ++OldArgNum, ++OldFnArgIt) { if (const std::unique_ptr &ARI = @@ -1727,6 +1909,10 @@ void InformationCache::initializeInformationCache(const Function &CF, InlineableFunctions.insert(&F); } +AAResults *InformationCache::getAAResultsForFunction(const Function &F) { + return AG.getAnalysis(F); +} + InformationCache::FunctionInfo::~FunctionInfo() { // The instruction vectors are allocated using a BumpPtrAllocator, we need to // manually destroy them. @@ -1827,6 +2013,9 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) { // Every function might be simplified. getOrCreateAAFor(RetPos); + // Every returned value might be marked noundef. + getOrCreateAAFor(RetPos); + if (ReturnType->isPointerTy()) { // Every function with pointer return type might be marked align. @@ -1853,6 +2042,9 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) { // Every argument might be dead. getOrCreateAAFor(ArgPos); + // Every argument might be marked noundef. + getOrCreateAAFor(ArgPos); + if (Arg.getType()->isPointerTy()) { // Every argument with pointer type might be marked nonnull. getOrCreateAAFor(ArgPos); @@ -1920,6 +2112,9 @@ void Attributor::identifyDefaultAbstractAttributes(Function &F) { // Call site argument might be simplified. getOrCreateAAFor(CBArgPos); + // Every call site argument might be marked "noundef". + getOrCreateAAFor(CBArgPos); + if (!CB.getArgOperand(I)->getType()->isPointerTy()) continue; @@ -2005,7 +2200,8 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) { raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { const Value &AV = Pos.getAssociatedValue(); return OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" - << Pos.getAnchorValue().getName() << "@" << Pos.getArgNo() << "]}"; + << Pos.getAnchorValue().getName() << "@" << Pos.getCallSiteArgNo() + << "]}"; } raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) { @@ -2027,9 +2223,48 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) { return OS; } +raw_ostream &llvm::operator<<(raw_ostream &OS, + const PotentialConstantIntValuesState &S) { + OS << "set-state(< {"; + if (!S.isValidState()) + OS << "full-set"; + else { + for (auto &it : S.getAssumedSet()) + OS << it << ", "; + if (S.undefIsContained()) + OS << "undef "; + } + OS << "} >)"; + + return OS; +} + void AbstractAttribute::print(raw_ostream &OS) const { - OS << "[P: " << getIRPosition() << "][" << getAsStr() << "][S: " << getState() - << "]"; + OS << "["; + OS << getName(); + OS << "] for CtxI "; + + if (auto *I = getCtxI()) { + OS << "'"; + I->print(OS); + OS << "'"; + } else + OS << "<>"; + + OS << " at position " << getIRPosition() << " with state " << getAsStr() + << '\n'; +} + +void AbstractAttribute::printWithDeps(raw_ostream &OS) const { + print(OS); + + for (const auto &DepAA : Deps) { + auto *AA = DepAA.getPointer(); + OS << " updates "; + AA->print(OS); + } + + OS << '\n'; } ///} @@ -2055,7 +2290,31 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, if (AllowShallowWrappers) for (Function *F : Functions) if (!A.isFunctionIPOAmendable(*F)) - createShallowWrapper(*F); + Attributor::createShallowWrapper(*F); + + // Internalize non-exact functions + // TODO: for now we eagerly internalize functions without calculating the + // cost, we need a cost interface to determine whether internalizing + // a function is "benefitial" + if (AllowDeepWrapper) { + unsigned FunSize = Functions.size(); + for (unsigned u = 0; u < FunSize; u++) { + Function *F = Functions[u]; + if (!F->isDeclaration() && !F->isDefinitionExact() && F->getNumUses() && + !GlobalValue::isInterposableLinkage(F->getLinkage())) { + Function *NewF = internalizeFunction(*F); + Functions.insert(NewF); + + // Update call graph + CGUpdater.replaceFunctionWith(*F, *NewF); + for (const Use &U : NewF->uses()) + if (CallBase *CB = dyn_cast(U.getUser())) { + auto *CallerF = CB->getCaller(); + CGUpdater.reanalyzeFunction(*CallerF); + } + } + } + } for (Function *F : Functions) { if (F->hasExactDefinition()) @@ -2064,8 +2323,8 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, NumFnWithoutExactDefinition++; // We look at internal functions only on-demand but if any use is not a - // direct call or outside the current set of analyzed functions, we have to - // do it eagerly. + // direct call or outside the current set of analyzed functions, we have + // to do it eagerly. if (F->hasLocalLinkage()) { if (llvm::all_of(F->uses(), [&Functions](const Use &U) { const auto *CB = dyn_cast(U.getUser()); @@ -2081,11 +2340,41 @@ static bool runAttributorOnFunctions(InformationCache &InfoCache, } ChangeStatus Changed = A.run(); + LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() << " functions, result: " << Changed << ".\n"); return Changed == ChangeStatus::CHANGED; } +void AADepGraph::viewGraph() { llvm::ViewGraph(this, "Dependency Graph"); } + +void AADepGraph::dumpGraph() { + static std::atomic CallTimes; + std::string Prefix; + + if (!DepGraphDotFileNamePrefix.empty()) + Prefix = DepGraphDotFileNamePrefix; + else + Prefix = "dep_graph"; + std::string Filename = + Prefix + "_" + std::to_string(CallTimes.load()) + ".dot"; + + outs() << "Dependency graph dump to " << Filename << ".\n"; + + std::error_code EC; + + raw_fd_ostream File(Filename, EC, sys::fs::OF_Text); + if (!EC) + llvm::WriteGraph(File, this); + + CallTimes++; +} + +void AADepGraph::print() { + for (auto DepAA : SyntheticRoot.Deps) + cast(DepAA.getPointer())->printWithDeps(outs()); +} + PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); @@ -2127,11 +2416,58 @@ PreservedAnalyses AttributorCGSCCPass::run(LazyCallGraph::SCC &C, InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions); if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater)) { // FIXME: Think about passes we will preserve and add them here. - return PreservedAnalyses::none(); + PreservedAnalyses PA; + PA.preserve(); + return PA; } return PreservedAnalyses::all(); } +namespace llvm { + +template <> struct GraphTraits { + using NodeRef = AADepGraphNode *; + using DepTy = PointerIntPair; + using EdgeRef = PointerIntPair; + + static NodeRef getEntryNode(AADepGraphNode *DGN) { return DGN; } + static NodeRef DepGetVal(DepTy &DT) { return DT.getPointer(); } + + using ChildIteratorType = + mapped_iterator::iterator, decltype(&DepGetVal)>; + using ChildEdgeIteratorType = TinyPtrVector::iterator; + + static ChildIteratorType child_begin(NodeRef N) { return N->child_begin(); } + + static ChildIteratorType child_end(NodeRef N) { return N->child_end(); } +}; + +template <> +struct GraphTraits : public GraphTraits { + static NodeRef getEntryNode(AADepGraph *DG) { return DG->GetEntryNode(); } + + using nodes_iterator = + mapped_iterator::iterator, decltype(&DepGetVal)>; + + static nodes_iterator nodes_begin(AADepGraph *DG) { return DG->begin(); } + + static nodes_iterator nodes_end(AADepGraph *DG) { return DG->end(); } +}; + +template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { + DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} + + static std::string getNodeLabel(const AADepGraphNode *Node, + const AADepGraph *DG) { + std::string AAString; + raw_string_ostream O(AAString); + Node->print(O); + return AAString; + } +}; + +} // end namespace llvm + namespace { struct AttributorLegacyPass : public ModulePass { @@ -2163,7 +2499,6 @@ struct AttributorLegacyPass : public ModulePass { }; struct AttributorCGSCCLegacyPass : public CallGraphSCCPass { - CallGraphUpdater CGUpdater; static char ID; AttributorCGSCCLegacyPass() : CallGraphSCCPass(ID) { @@ -2185,6 +2520,7 @@ struct AttributorCGSCCLegacyPass : public CallGraphSCCPass { AnalysisGetter AG; CallGraph &CG = const_cast(SCC.getCallGraph()); + CallGraphUpdater CGUpdater; CGUpdater.initialize(CG, SCC); Module &M = *Functions.back()->getParent(); BumpPtrAllocator Allocator; @@ -2192,8 +2528,6 @@ struct AttributorCGSCCLegacyPass : public CallGraphSCCPass { return runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater); } - bool doFinalization(CallGraph &CG) override { return CGUpdater.finalize(); } - void getAnalysisUsage(AnalysisUsage &AU) const override { // FIXME: Think about passes we will preserve and add them here. AU.addRequired(); diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index 7e9fd61eeb41..d6127a8df628 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -13,15 +13,20 @@ #include "llvm/Transforms/IPO/Attributor.h" +#include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumeBundleQueries.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/LazyValueInfo.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/NoFolder.h" #include "llvm/Support/CommandLine.h" @@ -42,6 +47,16 @@ static cl::opt ManifestInternal( static cl::opt MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128), cl::Hidden); +template <> +unsigned llvm::PotentialConstantIntValuesState::MaxPotentialValues = 0; + +static cl::opt MaxPotentialValues( + "attributor-max-potential-values", cl::Hidden, + cl::desc("Maximum number of potential values to be " + "tracked for each position."), + cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues), + cl::init(7)); + STATISTIC(NumAAs, "Number of abstract attributes created"); // Some helper macros to deal with statistics tracking. @@ -117,6 +132,8 @@ PIPE_OPERATOR(AAMemoryLocation) PIPE_OPERATOR(AAValueConstantRange) PIPE_OPERATOR(AAPrivatizablePtr) PIPE_OPERATOR(AAUndefinedBehavior) +PIPE_OPERATOR(AAPotentialValues) +PIPE_OPERATOR(AANoUndef) #undef PIPE_OPERATOR } // namespace llvm @@ -435,7 +452,7 @@ static void clampReturnedValueStates(Attributor &A, const AAType &QueryingAA, const AAType &AA = A.getAAFor(QueryingAA, RVPos); LLVM_DEBUG(dbgs() << "[Attributor] RV: " << RV << " AA: " << AA.getAsStr() << " @ " << RVPos << "\n"); - const StateType &AAS = static_cast(AA.getState()); + const StateType &AAS = AA.getState(); if (T.hasValue()) *T &= AAS; else @@ -485,7 +502,7 @@ static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA, Optional T; // The argument number which is also the call site argument number. - unsigned ArgNo = QueryingAA.getIRPosition().getArgNo(); + unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo(); auto CallSiteCheck = [&](AbstractCallSite ACS) { const IRPosition &ACSArgPos = IRPosition::callsite_argument(ACS, ArgNo); @@ -497,7 +514,7 @@ static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA, const AAType &AA = A.getAAFor(QueryingAA, ACSArgPos); LLVM_DEBUG(dbgs() << "[Attributor] ACS: " << *ACS.getInstruction() << " AA: " << AA.getAsStr() << " @" << ACSArgPos << "\n"); - const StateType &AAS = static_cast(AA.getState()); + const StateType &AAS = AA.getState(); if (T.hasValue()) *T &= AAS; else @@ -554,8 +571,7 @@ struct AACallSiteReturnedFromReturned : public BaseType { IRPosition FnPos = IRPosition::returned(*AssociatedFunction); const AAType &AA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - S, static_cast(AA.getState())); + return clampStateAndIndicateChange(S, AA.getState()); } }; @@ -722,7 +738,7 @@ struct AANoUnwindCallSite final : AANoUnwindImpl { void initialize(Attributor &A) override { AANoUnwindImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -735,9 +751,7 @@ struct AANoUnwindCallSite final : AANoUnwindImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), - static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -783,7 +797,7 @@ public: ReturnedValues.clear(); Function *F = getAssociatedFunction(); - if (!F) { + if (!F || F->isDeclaration()) { indicatePessimisticFixpoint(); return; } @@ -1052,9 +1066,10 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { // map, NewRVsMap. decltype(ReturnedValues) NewRVsMap; - auto HandleReturnValue = [&](Value *RV, SmallSetVector &RIs) { - LLVM_DEBUG(dbgs() << "[AAReturnedValues] Returned value: " << *RV - << " by #" << RIs.size() << " RIs\n"); + auto HandleReturnValue = [&](Value *RV, + SmallSetVector &RIs) { + LLVM_DEBUG(dbgs() << "[AAReturnedValues] Returned value: " << *RV << " by #" + << RIs.size() << " RIs\n"); CallBase *CB = dyn_cast(RV); if (!CB || UnresolvedCalls.count(CB)) return; @@ -1128,11 +1143,13 @@ ChangeStatus AAReturnedValuesImpl::updateImpl(Attributor &A) { RVState RVS({NewRVsMap, Unused, RetValAAIt.second}); VisitReturnedValue(*CB->getArgOperand(Arg->getArgNo()), RVS, CB); continue; - } else if (isa(RetVal)) { + } + if (isa(RetVal)) { // Call sites are resolved by the callee attribute over time, no need to // do anything for us. continue; - } else if (isa(RetVal)) { + } + if (isa(RetVal)) { // Constants are valid everywhere, we can simply take them. NewRVsMap[RetVal].insert(RIs.begin(), RIs.end()); continue; @@ -1373,7 +1390,7 @@ struct AANoSyncCallSite final : AANoSyncImpl { void initialize(Attributor &A) override { AANoSyncImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -1386,8 +1403,7 @@ struct AANoSyncCallSite final : AANoSyncImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -1439,7 +1455,7 @@ struct AANoFreeCallSite final : AANoFreeImpl { void initialize(Attributor &A) override { AANoFreeImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -1452,8 +1468,7 @@ struct AANoFreeCallSite final : AANoFreeImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -1535,8 +1550,7 @@ struct AANoFreeCallSiteArgument final : AANoFreeFloating { return indicatePessimisticFixpoint(); const IRPosition &ArgPos = IRPosition::argument(*Arg); auto &ArgAA = A.getAAFor(*this, ArgPos); - return clampStateAndIndicateChange( - getState(), static_cast(ArgAA.getState())); + return clampStateAndIndicateChange(getState(), ArgAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -1672,21 +1686,33 @@ struct AANonNullImpl : AANonNull { Value &V = getAssociatedValue(); if (!NullIsDefined && hasAttr({Attribute::NonNull, Attribute::Dereferenceable}, - /* IgnoreSubsumingPositions */ false, &A)) + /* IgnoreSubsumingPositions */ false, &A)) { indicateOptimisticFixpoint(); - else if (isa(V)) + return; + } + + if (isa(V)) { indicatePessimisticFixpoint(); - else - AANonNull::initialize(A); + return; + } + + AANonNull::initialize(A); bool CanBeNull = true; - if (V.getPointerDereferenceableBytes(A.getDataLayout(), CanBeNull)) - if (!CanBeNull) + if (V.getPointerDereferenceableBytes(A.getDataLayout(), CanBeNull)) { + if (!CanBeNull) { indicateOptimisticFixpoint(); + return; + } + } - if (!getState().isAtFixpoint()) - if (Instruction *CtxI = getCtxI()) - followUsesInMBEC(*this, A, getState(), *CtxI); + if (isa(&getAssociatedValue())) { + indicatePessimisticFixpoint(); + return; + } + + if (Instruction *CtxI = getCtxI()) + followUsesInMBEC(*this, A, getState(), *CtxI); } /// See followUsesInMBEC @@ -1717,13 +1743,6 @@ struct AANonNullFloating : public AANonNullImpl { /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { - if (!NullIsDefined) { - const auto &DerefAA = - A.getAAFor(*this, getIRPosition()); - if (DerefAA.getAssumedDereferenceableBytes()) - return ChangeStatus::UNCHANGED; - } - const DataLayout &DL = A.getDataLayout(); DominatorTree *DT = nullptr; @@ -1742,8 +1761,7 @@ struct AANonNullFloating : public AANonNullImpl { T.indicatePessimisticFixpoint(); } else { // Use abstract attribute information. - const AANonNull::StateType &NS = - static_cast(AA.getState()); + const AANonNull::StateType &NS = AA.getState(); T ^= NS; } return T.isValidState(); @@ -1763,9 +1781,14 @@ struct AANonNullFloating : public AANonNullImpl { /// NonNull attribute for function return value. struct AANonNullReturned final - : AAReturnedFromReturnedValues { + : AAReturnedFromReturnedValues { AANonNullReturned(const IRPosition &IRP, Attributor &A) - : AAReturnedFromReturnedValues(IRP, A) {} + : AAReturnedFromReturnedValues(IRP, A) {} + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + return getAssumed() ? "nonnull" : "may-null"; + } /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) } @@ -1879,7 +1902,7 @@ struct AANoRecurseCallSite final : AANoRecurseImpl { void initialize(Attributor &A) override { AANoRecurseImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -1892,9 +1915,7 @@ struct AANoRecurseCallSite final : AANoRecurseImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), - static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -1979,6 +2000,98 @@ struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior { return true; }; + auto InspectCallSiteForUB = [&](Instruction &I) { + // Check whether a callsite always cause UB or not + + // Skip instructions that are already saved. + if (AssumedNoUBInsts.count(&I) || KnownUBInsts.count(&I)) + return true; + + // Check nonnull and noundef argument attribute violation for each + // callsite. + CallBase &CB = cast(I); + Function *Callee = CB.getCalledFunction(); + if (!Callee) + return true; + for (unsigned idx = 0; idx < CB.getNumArgOperands(); idx++) { + // If current argument is known to be simplified to null pointer and the + // corresponding argument position is known to have nonnull attribute, + // the argument is poison. Furthermore, if the argument is poison and + // the position is known to have noundef attriubte, this callsite is + // considered UB. + if (idx >= Callee->arg_size()) + break; + Value *ArgVal = CB.getArgOperand(idx); + if (!ArgVal) + continue; + // Here, we handle three cases. + // (1) Not having a value means it is dead. (we can replace the value + // with undef) + // (2) Simplified to undef. The argument violate noundef attriubte. + // (3) Simplified to null pointer where known to be nonnull. + // The argument is a poison value and violate noundef attribute. + IRPosition CalleeArgumentIRP = IRPosition::callsite_argument(CB, idx); + auto &NoUndefAA = A.getAAFor(*this, CalleeArgumentIRP, + /* TrackDependence */ false); + if (!NoUndefAA.isKnownNoUndef()) + continue; + auto &ValueSimplifyAA = A.getAAFor( + *this, IRPosition::value(*ArgVal), /* TrackDependence */ false); + if (!ValueSimplifyAA.isKnown()) + continue; + Optional SimplifiedVal = + ValueSimplifyAA.getAssumedSimplifiedValue(A); + if (!SimplifiedVal.hasValue() || + isa(*SimplifiedVal.getValue())) { + KnownUBInsts.insert(&I); + continue; + } + if (!ArgVal->getType()->isPointerTy() || + !isa(*SimplifiedVal.getValue())) + continue; + auto &NonNullAA = A.getAAFor(*this, CalleeArgumentIRP, + /* TrackDependence */ false); + if (NonNullAA.isKnownNonNull()) + KnownUBInsts.insert(&I); + } + return true; + }; + + auto InspectReturnInstForUB = + [&](Value &V, const SmallSetVector RetInsts) { + // Check if a return instruction always cause UB or not + // Note: It is guaranteed that the returned position of the anchor + // scope has noundef attribute when this is called. + // We also ensure the return position is not "assumed dead" + // because the returned value was then potentially simplified to + // `undef` in AAReturnedValues without removing the `noundef` + // attribute yet. + + // When the returned position has noundef attriubte, UB occur in the + // following cases. + // (1) Returned value is known to be undef. + // (2) The value is known to be a null pointer and the returned + // position has nonnull attribute (because the returned value is + // poison). + bool FoundUB = false; + if (isa(V)) { + FoundUB = true; + } else { + if (isa(V)) { + auto &NonNullAA = A.getAAFor( + *this, IRPosition::returned(*getAnchorScope()), + /* TrackDependence */ false); + if (NonNullAA.isKnownNonNull()) + FoundUB = true; + } + } + + if (FoundUB) + for (ReturnInst *RI : RetInsts) + KnownUBInsts.insert(RI); + return true; + }; + A.checkForAllInstructions(InspectMemAccessInstForUB, *this, {Instruction::Load, Instruction::Store, Instruction::AtomicCmpXchg, @@ -1986,6 +2099,22 @@ struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior { /* CheckBBLivenessOnly */ true); A.checkForAllInstructions(InspectBrInstForUB, *this, {Instruction::Br}, /* CheckBBLivenessOnly */ true); + A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *this); + + // If the returned position of the anchor scope has noundef attriubte, check + // all returned instructions. + if (!getAnchorScope()->getReturnType()->isVoidTy()) { + const IRPosition &ReturnIRP = IRPosition::returned(*getAnchorScope()); + if (!A.isAssumedDead(ReturnIRP, this, nullptr)) { + auto &RetPosNoUndefAA = + A.getAAFor(*this, ReturnIRP, + /* TrackDependence */ false); + if (RetPosNoUndefAA.isKnownNoUndef()) + A.checkForAllReturnedValuesAndReturnInsts(InspectReturnInstForUB, + *this); + } + } + if (NoUBPrevSize != AssumedNoUBInsts.size() || UBPrevSize != KnownUBInsts.size()) return ChangeStatus::CHANGED; @@ -2153,7 +2282,7 @@ struct AAWillReturnImpl : public AAWillReturn { AAWillReturn::initialize(A); Function *F = getAnchorScope(); - if (!F || !A.isFunctionIPOAmendable(*F) || mayContainUnboundedCycle(*F, A)) + if (!F || F->isDeclaration() || mayContainUnboundedCycle(*F, A)) indicatePessimisticFixpoint(); } @@ -2197,9 +2326,9 @@ struct AAWillReturnCallSite final : AAWillReturnImpl { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - AAWillReturnImpl::initialize(A); + AAWillReturn::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || !A.isFunctionIPOAmendable(*F)) indicatePessimisticFixpoint(); } @@ -2212,9 +2341,7 @@ struct AAWillReturnCallSite final : AAWillReturnImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), - static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -2374,7 +2501,7 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { void initialize(Attributor &A) override { // See callsite argument attribute and callee argument attribute. const auto &CB = cast(getAnchorValue()); - if (CB.paramHasAttr(getArgNo(), Attribute::NoAlias)) + if (CB.paramHasAttr(getCallSiteArgNo(), Attribute::NoAlias)) indicateOptimisticFixpoint(); Value &Val = getAssociatedValue(); if (isa(Val) && @@ -2389,7 +2516,7 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { const AAMemoryBehavior &MemBehaviorAA, const CallBase &CB, unsigned OtherArgNo) { // We do not need to worry about aliasing with the underlying IRP. - if (this->getArgNo() == (int)OtherArgNo) + if (this->getCalleeArgNo() == (int)OtherArgNo) return false; // If it is not a pointer or pointer vector we do not alias. @@ -2451,6 +2578,7 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { A.recordDependence(NoAliasAA, *this, DepClassTy::OPTIONAL); const IRPosition &VIRP = IRPosition::value(getAssociatedValue()); + const Function *ScopeFn = VIRP.getAnchorScope(); auto &NoCaptureAA = A.getAAFor(*this, VIRP, /* TrackDependence */ false); // Check whether the value is captured in the scope using AANoCapture. @@ -2459,16 +2587,18 @@ struct AANoAliasCallSiteArgument final : AANoAliasImpl { auto UsePred = [&](const Use &U, bool &Follow) -> bool { Instruction *UserI = cast(U.getUser()); - // If user if curr instr and only use. - if (UserI == getCtxI() && UserI->hasOneUse()) + // If UserI is the curr instruction and there is a single potential use of + // the value in UserI we allow the use. + // TODO: We should inspect the operands and allow those that cannot alias + // with the value. + if (UserI == getCtxI() && UserI->getNumOperands() == 1) return true; - const Function *ScopeFn = VIRP.getAnchorScope(); if (ScopeFn) { const auto &ReachabilityAA = A.getAAFor(*this, IRPosition::function(*ScopeFn)); - if (!ReachabilityAA.isAssumedReachable(UserI, getCtxI())) + if (!ReachabilityAA.isAssumedReachable(A, *UserI, *getCtxI())) return true; if (auto *CB = dyn_cast(UserI)) { @@ -2554,6 +2684,14 @@ struct AANoAliasReturned final : AANoAliasImpl { AANoAliasReturned(const IRPosition &IRP, Attributor &A) : AANoAliasImpl(IRP, A) {} + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + AANoAliasImpl::initialize(A); + Function *F = getAssociatedFunction(); + if (!F || F->isDeclaration()) + indicatePessimisticFixpoint(); + } + /// See AbstractAttribute::updateImpl(...). virtual ChangeStatus updateImpl(Attributor &A) override { @@ -2595,7 +2733,7 @@ struct AANoAliasCallSiteReturned final : AANoAliasImpl { void initialize(Attributor &A) override { AANoAliasImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -2608,8 +2746,7 @@ struct AANoAliasCallSiteReturned final : AANoAliasImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::returned(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -2799,14 +2936,13 @@ struct AAIsDeadCallSiteArgument : public AAIsDeadValueImpl { return indicatePessimisticFixpoint(); const IRPosition &ArgPos = IRPosition::argument(*Arg); auto &ArgAA = A.getAAFor(*this, ArgPos); - return clampStateAndIndicateChange( - getState(), static_cast(ArgAA.getState())); + return clampStateAndIndicateChange(getState(), ArgAA.getState()); } /// See AbstractAttribute::manifest(...). ChangeStatus manifest(Attributor &A) override { CallBase &CB = cast(getAnchorValue()); - Use &U = CB.getArgOperandUse(getArgNo()); + Use &U = CB.getArgOperandUse(getCallSiteArgNo()); assert(!isa(U.get()) && "Expected undef values to be filtered out!"); UndefValue &UV = *UndefValue::get(U->getType()); @@ -2921,8 +3057,14 @@ struct AAIsDeadFunction : public AAIsDead { void initialize(Attributor &A) override { const Function *F = getAnchorScope(); if (F && !F->isDeclaration()) { - ToBeExploredFrom.insert(&F->getEntryBlock().front()); - assumeLive(A, F->getEntryBlock()); + // We only want to compute liveness once. If the function is not part of + // the SCC, skip it. + if (A.isRunOn(*const_cast(F))) { + ToBeExploredFrom.insert(&F->getEntryBlock().front()); + assumeLive(A, F->getEntryBlock()); + } else { + indicatePessimisticFixpoint(); + } } } @@ -2985,6 +3127,10 @@ struct AAIsDeadFunction : public AAIsDead { /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override; + bool isEdgeDead(const BasicBlock *From, const BasicBlock *To) const override { + return !AssumedLiveEdges.count(std::make_pair(From, To)); + } + /// See AbstractAttribute::trackStatistics() void trackStatistics() const override {} @@ -3062,6 +3208,9 @@ struct AAIsDeadFunction : public AAIsDead { /// Collection of instructions that are known to not transfer control. SmallSetVector KnownDeadEnds; + /// Collection of all assumed live edges + DenseSet> AssumedLiveEdges; + /// Collection of all assumed live BasicBlocks. DenseSet AssumedLiveBlocks; }; @@ -3177,18 +3326,23 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { const Instruction *I = Worklist.pop_back_val(); LLVM_DEBUG(dbgs() << "[AAIsDead] Exploration inst: " << *I << "\n"); + // Fast forward for uninteresting instructions. We could look for UB here + // though. + while (!I->isTerminator() && !isa(I)) { + Change = ChangeStatus::CHANGED; + I = I->getNextNode(); + } + AliveSuccessors.clear(); bool UsedAssumedInformation = false; switch (I->getOpcode()) { // TODO: look for (assumed) UB to backwards propagate "deadness". default: - if (I->isTerminator()) { - for (const BasicBlock *SuccBB : successors(I->getParent())) - AliveSuccessors.push_back(&SuccBB->front()); - } else { - AliveSuccessors.push_back(I->getNextNode()); - } + assert(I->isTerminator() && + "Expected non-terminators to be handled already!"); + for (const BasicBlock *SuccBB : successors(I->getParent())) + AliveSuccessors.push_back(&SuccBB->front()); break; case Instruction::Call: UsedAssumedInformation = identifyAliveSuccessors(A, cast(*I), @@ -3227,6 +3381,9 @@ ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) { "Non-terminator expected to have a single successor!"); Worklist.push_back(AliveSuccessor); } else { + // record the assumed live edge + AssumedLiveEdges.insert( + std::make_pair(I->getParent(), AliveSuccessor->getParent())); if (assumeLive(A, *AliveSuccessor->getParent())) Worklist.push_back(AliveSuccessor); } @@ -3342,7 +3499,6 @@ struct AADereferenceableImpl : AADereferenceable { State.addAccessedBytes(Offset, Size); } } - return; } /// See followUsesInMBEC @@ -3420,12 +3576,11 @@ struct AADereferenceableFloating : AADereferenceableImpl { DerefBytes = Base->getPointerDereferenceableBytes(DL, CanBeNull); T.GlobalState.indicatePessimisticFixpoint(); } else { - const DerefState &DS = static_cast(AA.getState()); + const DerefState &DS = AA.getState(); DerefBytes = DS.DerefBytesState.getAssumed(); T.GlobalState &= DS.GlobalState; } - // For now we do not try to "increase" dereferenceability due to negative // indices as we first have to come up with code to deal with loops and // for overflows of the dereferenceable bytes. @@ -3697,14 +3852,27 @@ struct AAAlignFloating : AAAlignImpl { AAAlign::StateType &T, bool Stripped) -> bool { const auto &AA = A.getAAFor(*this, IRPosition::value(V)); if (!Stripped && this == &AA) { + int64_t Offset; + unsigned Alignment = 1; + if (const Value *Base = + GetPointerBaseWithConstantOffset(&V, Offset, DL)) { + Align PA = Base->getPointerAlignment(DL); + // BasePointerAddr + Offset = Alignment * Q for some integer Q. + // So we can say that the maximum power of two which is a divisor of + // gcd(Offset, Alignment) is an alignment. + + uint32_t gcd = greatestCommonDivisor(uint32_t(abs((int32_t)Offset)), + uint32_t(PA.value())); + Alignment = llvm::PowerOf2Floor(gcd); + } else { + Alignment = V.getPointerAlignment(DL).value(); + } // Use only IR information if we did not strip anything. - Align PA = V.getPointerAlignment(DL); - T.takeKnownMaximum(PA.value()); + T.takeKnownMaximum(Alignment); T.indicatePessimisticFixpoint(); } else { // Use abstract attribute information. - const AAAlign::StateType &DS = - static_cast(AA.getState()); + const AAAlign::StateType &DS = AA.getState(); T ^= DS; } return T.isValidState(); @@ -3727,8 +3895,16 @@ struct AAAlignFloating : AAAlignImpl { /// Align attribute for function return value. struct AAAlignReturned final : AAReturnedFromReturnedValues { - AAAlignReturned(const IRPosition &IRP, Attributor &A) - : AAReturnedFromReturnedValues(IRP, A) {} + using Base = AAReturnedFromReturnedValues; + AAAlignReturned(const IRPosition &IRP, Attributor &A) : Base(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + Base::initialize(A); + Function *F = getAssociatedFunction(); + if (!F || F->isDeclaration()) + indicatePessimisticFixpoint(); + } /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(aligned) } @@ -3802,7 +3978,7 @@ struct AAAlignCallSiteReturned final void initialize(Attributor &A) override { Base::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -3818,7 +3994,7 @@ struct AANoReturnImpl : public AANoReturn { void initialize(Attributor &A) override { AANoReturn::initialize(A); Function *F = getAssociatedFunction(); - if (!F) + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); } @@ -3850,6 +4026,17 @@ struct AANoReturnCallSite final : AANoReturnImpl { AANoReturnCallSite(const IRPosition &IRP, Attributor &A) : AANoReturnImpl(IRP, A) {} + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + AANoReturnImpl::initialize(A); + if (Function *F = getAssociatedFunction()) { + const IRPosition &FnPos = IRPosition::function(*F); + auto &FnAA = A.getAAFor(*this, FnPos); + if (!FnAA.isAssumedNoReturn()) + indicatePessimisticFixpoint(); + } + } + /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { // TODO: Once we have call site specific value information we can provide @@ -3859,9 +4046,7 @@ struct AANoReturnCallSite final : AANoReturnImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), - static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -3894,7 +4079,8 @@ struct AANoCaptureImpl : public AANoCapture { return; } - const Function *F = getArgNo() >= 0 ? getAssociatedFunction() : AnchorScope; + const Function *F = + isArgumentPosition() ? getAssociatedFunction() : AnchorScope; // Check what state the associated function can actually capture. if (F) @@ -3913,7 +4099,7 @@ struct AANoCaptureImpl : public AANoCapture { if (!isAssumedNoCaptureMaybeReturned()) return; - if (getArgNo() >= 0) { + if (isArgumentPosition()) { if (isAssumedNoCapture()) Attrs.emplace_back(Attribute::get(Ctx, Attribute::NoCapture)); else if (ManifestInternal) @@ -3949,7 +4135,7 @@ struct AANoCaptureImpl : public AANoCapture { State.addKnownBits(NOT_CAPTURED_IN_RET); // Check existing "returned" attributes. - int ArgNo = IRP.getArgNo(); + int ArgNo = IRP.getCalleeArgNo(); if (F.doesNotThrow() && ArgNo >= 0) { for (unsigned u = 0, e = F.arg_size(); u < e; ++u) if (F.hasParamAttribute(u, Attribute::Returned)) { @@ -4125,13 +4311,13 @@ private: ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) { const IRPosition &IRP = getIRPosition(); - const Value *V = - getArgNo() >= 0 ? IRP.getAssociatedArgument() : &IRP.getAssociatedValue(); + const Value *V = isArgumentPosition() ? IRP.getAssociatedArgument() + : &IRP.getAssociatedValue(); if (!V) return indicatePessimisticFixpoint(); const Function *F = - getArgNo() >= 0 ? IRP.getAssociatedFunction() : IRP.getAnchorScope(); + isArgumentPosition() ? IRP.getAssociatedFunction() : IRP.getAnchorScope(); assert(F && "Expected a function!"); const IRPosition &FnPos = IRPosition::function(*F); const auto &IsDeadAA = @@ -4248,9 +4434,7 @@ struct AANoCaptureCallSiteArgument final : AANoCaptureImpl { return indicatePessimisticFixpoint(); const IRPosition &ArgPos = IRPosition::argument(*Arg); auto &ArgAA = A.getAAFor(*this, ArgPos); - return clampStateAndIndicateChange( - getState(), - static_cast(ArgAA.getState())); + return clampStateAndIndicateChange(getState(), ArgAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -4366,24 +4550,35 @@ struct AAValueSimplifyImpl : AAValueSimplify { return true; } - bool askSimplifiedValueForAAValueConstantRange(Attributor &A) { + /// Returns a candidate is found or not + template bool askSimplifiedValueFor(Attributor &A) { if (!getAssociatedValue().getType()->isIntegerTy()) return false; - const auto &ValueConstantRangeAA = - A.getAAFor(*this, getIRPosition()); + const auto &AA = + A.getAAFor(*this, getIRPosition(), /* TrackDependence */ false); - Optional COpt = - ValueConstantRangeAA.getAssumedConstantInt(A); - if (COpt.hasValue()) { - if (auto *C = COpt.getValue()) - SimplifiedAssociatedValue = C; - else - return false; - } else { + Optional COpt = AA.getAssumedConstantInt(A); + + if (!COpt.hasValue()) { SimplifiedAssociatedValue = llvm::None; + A.recordDependence(AA, *this, DepClassTy::OPTIONAL); + return true; } - return true; + if (auto *C = COpt.getValue()) { + SimplifiedAssociatedValue = C; + A.recordDependence(AA, *this, DepClassTy::OPTIONAL); + return true; + } + return false; + } + + bool askSimplifiedValueForOtherAAs(Attributor &A) { + if (askSimplifiedValueFor(A)) + return true; + if (askSimplifiedValueFor(A)) + return true; + return false; } /// See AbstractAttribute::manifest(...). @@ -4468,7 +4663,7 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl { auto PredForCallSite = [&](AbstractCallSite ACS) { const IRPosition &ACSArgPos = - IRPosition::callsite_argument(ACS, getArgNo()); + IRPosition::callsite_argument(ACS, getCallSiteArgNo()); // Check if a coresponding argument was found or if it is on not // associated (which can happen for callback calls). if (ACSArgPos.getPositionKind() == IRPosition::IRP_INVALID) @@ -4490,7 +4685,7 @@ struct AAValueSimplifyArgument final : AAValueSimplifyImpl { bool AllCallSitesKnown; if (!A.checkForAllCallSites(PredForCallSite, *this, true, AllCallSitesKnown)) - if (!askSimplifiedValueForAAValueConstantRange(A)) + if (!askSimplifiedValueForOtherAAs(A)) return indicatePessimisticFixpoint(); // If a candicate was found in this update, return CHANGED. @@ -4518,7 +4713,7 @@ struct AAValueSimplifyReturned : AAValueSimplifyImpl { }; if (!A.checkForAllReturnedValues(PredForReturned, *this)) - if (!askSimplifiedValueForAAValueConstantRange(A)) + if (!askSimplifiedValueForOtherAAs(A)) return indicatePessimisticFixpoint(); // If a candicate was found in this update, return CHANGED. @@ -4587,10 +4782,76 @@ struct AAValueSimplifyFloating : AAValueSimplifyImpl { indicatePessimisticFixpoint(); } + /// Check if \p ICmp is an equality comparison (==/!=) with at least one + /// nullptr. If so, try to simplify it using AANonNull on the other operand. + /// Return true if successful, in that case SimplifiedAssociatedValue will be + /// updated and \p Changed is set appropriately. + bool checkForNullPtrCompare(Attributor &A, ICmpInst *ICmp, + ChangeStatus &Changed) { + if (!ICmp) + return false; + if (!ICmp->isEquality()) + return false; + + // This is a comparison with == or !-. We check for nullptr now. + bool Op0IsNull = isa(ICmp->getOperand(0)); + bool Op1IsNull = isa(ICmp->getOperand(1)); + if (!Op0IsNull && !Op1IsNull) + return false; + + LLVMContext &Ctx = ICmp->getContext(); + // Check for `nullptr ==/!= nullptr` first: + if (Op0IsNull && Op1IsNull) { + Value *NewVal = ConstantInt::get( + Type::getInt1Ty(Ctx), ICmp->getPredicate() == CmpInst::ICMP_EQ); + assert(!SimplifiedAssociatedValue.hasValue() && + "Did not expect non-fixed value for constant comparison"); + SimplifiedAssociatedValue = NewVal; + indicateOptimisticFixpoint(); + Changed = ChangeStatus::CHANGED; + return true; + } + + // Left is the nullptr ==/!= non-nullptr case. We'll use AANonNull on the + // non-nullptr operand and if we assume it's non-null we can conclude the + // result of the comparison. + assert((Op0IsNull || Op1IsNull) && + "Expected nullptr versus non-nullptr comparison at this point"); + + // The index is the operand that we assume is not null. + unsigned PtrIdx = Op0IsNull; + auto &PtrNonNullAA = A.getAAFor( + *this, IRPosition::value(*ICmp->getOperand(PtrIdx))); + if (!PtrNonNullAA.isAssumedNonNull()) + return false; + + // The new value depends on the predicate, true for != and false for ==. + Value *NewVal = ConstantInt::get(Type::getInt1Ty(Ctx), + ICmp->getPredicate() == CmpInst::ICMP_NE); + + assert((!SimplifiedAssociatedValue.hasValue() || + SimplifiedAssociatedValue == NewVal) && + "Did not expect to change value for zero-comparison"); + + bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); + SimplifiedAssociatedValue = NewVal; + + if (PtrNonNullAA.isKnownNonNull()) + indicateOptimisticFixpoint(); + + Changed = HasValueBefore ? ChangeStatus::UNCHANGED : ChangeStatus ::CHANGED; + return true; + } + /// See AbstractAttribute::updateImpl(...). ChangeStatus updateImpl(Attributor &A) override { bool HasValueBefore = SimplifiedAssociatedValue.hasValue(); + ChangeStatus Changed; + if (checkForNullPtrCompare(A, dyn_cast(&getAnchorValue()), + Changed)) + return Changed; + auto VisitValueCB = [&](Value &V, const Instruction *CtxI, bool &, bool Stripped) -> bool { auto &AA = A.getAAFor(*this, IRPosition::value(V)); @@ -4608,7 +4869,7 @@ struct AAValueSimplifyFloating : AAValueSimplifyImpl { if (!genericValueTraversal( A, getIRPosition(), *this, Dummy, VisitValueCB, getCtxI(), /* UseValueSimplify */ false)) - if (!askSimplifiedValueForAAValueConstantRange(A)) + if (!askSimplifiedValueForOtherAAs(A)) return indicatePessimisticFixpoint(); // If a candicate was found in this update, return CHANGED. @@ -4683,7 +4944,8 @@ struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating { ? dyn_cast(SimplifiedAssociatedValue.getValue()) : UndefValue::get(V.getType()); if (C) { - Use &U = cast(&getAnchorValue())->getArgOperandUse(getArgNo()); + Use &U = cast(&getAnchorValue()) + ->getArgOperandUse(getCallSiteArgNo()); // We can replace the AssociatedValue with the constant. if (&V != C && V.getType() == C->getType()) { if (A.changeUseAfterManifest(U, *C)) @@ -5002,7 +5264,7 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl { return getAssociatedValue().getType()->getPointerElementType(); Optional Ty; - unsigned ArgNo = getIRPosition().getArgNo(); + unsigned ArgNo = getIRPosition().getCallSiteArgNo(); // Make sure the associated call site argument has the same type at all call // sites and it is an allocation we know is safe to privatize, for now that @@ -5265,8 +5527,9 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl { new StoreInst(F.getArg(ArgNo + u), Ptr, &IP); } } else if (auto *PrivArrayType = dyn_cast(PrivType)) { - Type *PointeePtrTy = PrivArrayType->getElementType()->getPointerTo(); - uint64_t PointeeTySize = DL.getTypeStoreSize(PointeePtrTy); + Type *PointeeTy = PrivArrayType->getElementType(); + Type *PointeePtrTy = PointeeTy->getPointerTo(); + uint64_t PointeeTySize = DL.getTypeStoreSize(PointeeTy); for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) { Value *Ptr = constructPointer(PointeePtrTy, &Base, u * PointeeTySize, IRB, DL); @@ -5312,7 +5575,7 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl { for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) { Value *Ptr = constructPointer(PointeePtrTy, Base, u * PointeeTySize, IRB, DL); - LoadInst *L = new LoadInst(PointeePtrTy, Ptr, "", IP); + LoadInst *L = new LoadInst(PointeeTy, Ptr, "", IP); L->setAlignment(Alignment); ReplacementValues.push_back(L); } @@ -5356,10 +5619,14 @@ struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl { Function &ReplacementFn, Function::arg_iterator ArgIt) { BasicBlock &EntryBB = ReplacementFn.getEntryBlock(); Instruction *IP = &*EntryBB.getFirstInsertionPt(); - auto *AI = new AllocaInst(PrivatizableType.getValue(), 0, - Arg->getName() + ".priv", IP); + Instruction *AI = new AllocaInst(PrivatizableType.getValue(), 0, + Arg->getName() + ".priv", IP); createInitialization(PrivatizableType.getValue(), *AI, ReplacementFn, ArgIt->getArgNo(), *IP); + + if (AI->getType() != Arg->getType()) + AI = + BitCastInst::CreateBitOrPointerCast(AI, Arg->getType(), "", IP); Arg->replaceAllUsesWith(AI); for (CallInst *CI : TailCalls) @@ -5418,8 +5685,7 @@ struct AAPrivatizablePtrFloating : public AAPrivatizablePtrImpl { /// See AAPrivatizablePtrImpl::identifyPrivatizableType(...) Optional identifyPrivatizableType(Attributor &A) override { - Value *Obj = - GetUnderlyingObject(&getAssociatedValue(), A.getInfoCache().getDL()); + Value *Obj = getUnderlyingObject(&getAssociatedValue()); if (!Obj) { LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] No underlying object found!\n"); return nullptr; @@ -5539,7 +5805,7 @@ struct AAMemoryBehaviorImpl : public AAMemoryBehavior { void initialize(Attributor &A) override { intersectAssumedBits(BEST_STATE); getKnownStateFromValue(getIRPosition(), getState()); - IRAttribute::initialize(A); + AAMemoryBehavior::initialize(A); } /// Return the memory behavior information encoded in the IR for \p IRP. @@ -5634,9 +5900,7 @@ struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { AAMemoryBehaviorImpl::initialize(A); - // Initialize the use vector with all direct uses of the associated value. - for (const Use &U : getAssociatedValue().uses()) - Uses.insert(&U); + addUsesOf(A, getAssociatedValue()); } /// See AbstractAttribute::updateImpl(...). @@ -5662,8 +5926,14 @@ private: void analyzeUseIn(Attributor &A, const Use *U, const Instruction *UserI); protected: + /// Add the uses of \p V to the `Uses` set we look at during the update step. + void addUsesOf(Attributor &A, const Value &V); + /// Container for (transitive) uses of the associated argument. - SetVector Uses; + SmallVector Uses; + + /// Set to remember the uses we already traversed. + SmallPtrSet Visited; }; /// Memory behavior attribute for function argument. @@ -5688,9 +5958,7 @@ struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating { if (!Arg || !A.isFunctionIPOAmendable(*(Arg->getParent()))) { indicatePessimisticFixpoint(); } else { - // Initialize the use vector with all direct uses of the associated value. - for (const Use &U : Arg->uses()) - Uses.insert(&U); + addUsesOf(A, *Arg); } } @@ -5725,14 +5993,21 @@ struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument { /// See AbstractAttribute::initialize(...). void initialize(Attributor &A) override { - if (Argument *Arg = getAssociatedArgument()) { - if (Arg->hasByValAttr()) { - addKnownBits(NO_WRITES); - removeKnownBits(NO_READS); - removeAssumedBits(NO_READS); - } + // If we don't have an associated attribute this is either a variadic call + // or an indirect call, either way, nothing to do here. + Argument *Arg = getAssociatedArgument(); + if (!Arg) { + indicatePessimisticFixpoint(); + return; + } + if (Arg->hasByValAttr()) { + addKnownBits(NO_WRITES); + removeKnownBits(NO_READS); + removeAssumedBits(NO_READS); } AAMemoryBehaviorArgument::initialize(A); + if (getAssociatedFunction()->isDeclaration()) + indicatePessimisticFixpoint(); } /// See AbstractAttribute::updateImpl(...). @@ -5744,9 +6019,7 @@ struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument { Argument *Arg = getAssociatedArgument(); const IRPosition &ArgPos = IRPosition::argument(*Arg); auto &ArgAA = A.getAAFor(*this, ArgPos); - return clampStateAndIndicateChange( - getState(), - static_cast(ArgAA.getState())); + return clampStateAndIndicateChange(getState(), ArgAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -5765,6 +6038,14 @@ struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating { AAMemoryBehaviorCallSiteReturned(const IRPosition &IRP, Attributor &A) : AAMemoryBehaviorFloating(IRP, A) {} + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + AAMemoryBehaviorImpl::initialize(A); + Function *F = getAssociatedFunction(); + if (!F || F->isDeclaration()) + indicatePessimisticFixpoint(); + } + /// See AbstractAttribute::manifest(...). ChangeStatus manifest(Attributor &A) override { // We do not annotate returned values. @@ -5814,10 +6095,8 @@ struct AAMemoryBehaviorCallSite final : AAMemoryBehaviorImpl { void initialize(Attributor &A) override { AAMemoryBehaviorImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F || !A.isFunctionIPOAmendable(*F)) { + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); - return; - } } /// See AbstractAttribute::updateImpl(...). @@ -5829,9 +6108,7 @@ struct AAMemoryBehaviorCallSite final : AAMemoryBehaviorImpl { Function *F = getAssociatedFunction(); const IRPosition &FnPos = IRPosition::function(*F); auto &FnAA = A.getAAFor(*this, FnPos); - return clampStateAndIndicateChange( - getState(), - static_cast(FnAA.getState())); + return clampStateAndIndicateChange(getState(), FnAA.getState()); } /// See AbstractAttribute::trackStatistics() @@ -5933,8 +6210,7 @@ ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &A) { // Check if the users of UserI should also be visited. if (followUsersOfUseIn(A, U, UserI)) - for (const Use &UserIUse : UserI->uses()) - Uses.insert(&UserIUse); + addUsesOf(A, *UserI); // If UserI might touch memory we analyze the use in detail. if (UserI->mayReadOrWriteMemory()) @@ -5945,6 +6221,28 @@ ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &A) { : ChangeStatus::UNCHANGED; } +void AAMemoryBehaviorFloating::addUsesOf(Attributor &A, const Value &V) { + SmallVector WL; + for (const Use &U : V.uses()) + WL.push_back(&U); + + while (!WL.empty()) { + const Use *U = WL.pop_back_val(); + if (!Visited.insert(U).second) + continue; + + const Instruction *UserI = cast(U->getUser()); + if (UserI->mayReadOrWriteMemory()) { + Uses.push_back(U); + continue; + } + if (!followUsersOfUseIn(A, U, UserI)) + continue; + for (const Use &UU : UserI->uses()) + WL.push_back(&UU); + } +} + bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &A, const Use *U, const Instruction *UserI) { // The loaded value is unrelated to the pointer argument, no need to @@ -6096,7 +6394,7 @@ struct AAMemoryLocationImpl : public AAMemoryLocation { void initialize(Attributor &A) override { intersectAssumedBits(BEST_STATE); getKnownStateFromValue(A, getIRPosition(), getState()); - IRAttribute::initialize(A); + AAMemoryLocation::initialize(A); } /// Return the memory behavior information encoded in the IR for \p IRP. @@ -6259,6 +6557,13 @@ protected: using AccessSet = SmallSet; AccessSet *AccessKind2Accesses[llvm::CTLog2()]; + /// Categorize the pointer arguments of CB that might access memory in + /// AccessedLoc and update the state and access map accordingly. + void + categorizeArgumentPointerLocations(Attributor &A, CallBase &CB, + AAMemoryLocation::StateType &AccessedLocs, + bool &Changed); + /// Return the kind(s) of location that may be accessed by \p V. AAMemoryLocation::MemoryLocationsKind categorizeAccessedLocations(Attributor &A, Instruction &I, bool &Changed); @@ -6324,6 +6629,7 @@ void AAMemoryLocationImpl::categorizePtrValue( auto VisitValueCB = [&](Value &V, const Instruction *, AAMemoryLocation::StateType &T, bool Stripped) -> bool { + // TODO: recognize the TBAA used for constant accesses. MemoryLocationsKind MLK = NO_LOCATIONS; assert(!isa(V) && "GEPs should have been stripped."); if (isa(V)) @@ -6334,6 +6640,13 @@ void AAMemoryLocationImpl::categorizePtrValue( else MLK = NO_ARGUMENT_MEM; } else if (auto *GV = dyn_cast(&V)) { + // Reading constant memory is not treated as a read "effect" by the + // function attr pass so we won't neither. Constants defined by TBAA are + // similar. (We know we do not write it because it is constant.) + if (auto *GVar = dyn_cast(GV)) + if (GVar->isConstant()) + return true; + if (GV->hasLocalLinkage()) MLK = NO_GLOBAL_INTERNAL_MEM; else @@ -6380,6 +6693,30 @@ void AAMemoryLocationImpl::categorizePtrValue( } } +void AAMemoryLocationImpl::categorizeArgumentPointerLocations( + Attributor &A, CallBase &CB, AAMemoryLocation::StateType &AccessedLocs, + bool &Changed) { + for (unsigned ArgNo = 0, E = CB.getNumArgOperands(); ArgNo < E; ++ArgNo) { + + // Skip non-pointer arguments. + const Value *ArgOp = CB.getArgOperand(ArgNo); + if (!ArgOp->getType()->isPtrOrPtrVectorTy()) + continue; + + // Skip readnone arguments. + const IRPosition &ArgOpIRP = IRPosition::callsite_argument(CB, ArgNo); + const auto &ArgOpMemLocationAA = A.getAAFor( + *this, ArgOpIRP, /* TrackDependence */ true, DepClassTy::OPTIONAL); + + if (ArgOpMemLocationAA.isAssumedReadNone()) + continue; + + // Categorize potentially accessed pointer arguments as if there was an + // access instruction with them as pointer. + categorizePtrValue(A, CB, *ArgOp, AccessedLocs, Changed); + } +} + AAMemoryLocation::MemoryLocationsKind AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &A, Instruction &I, bool &Changed) { @@ -6441,28 +6778,8 @@ AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &A, Instruction &I, // Now handle argument memory if it might be accessed. bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM); - if (HasArgAccesses) { - for (unsigned ArgNo = 0, E = CB->getNumArgOperands(); ArgNo < E; - ++ArgNo) { - - // Skip non-pointer arguments. - const Value *ArgOp = CB->getArgOperand(ArgNo); - if (!ArgOp->getType()->isPtrOrPtrVectorTy()) - continue; - - // Skip readnone arguments. - const IRPosition &ArgOpIRP = IRPosition::callsite_argument(*CB, ArgNo); - const auto &ArgOpMemLocationAA = A.getAAFor( - *this, ArgOpIRP, /* TrackDependence */ true, DepClassTy::OPTIONAL); - - if (ArgOpMemLocationAA.isAssumedReadNone()) - continue; - - // Categorize potentially accessed pointer arguments as if there was an - // access instruction with them as pointer. - categorizePtrValue(A, I, *ArgOp, AccessedLocs, Changed); - } - } + if (HasArgAccesses) + categorizeArgumentPointerLocations(A, *CB, AccessedLocs, Changed); LLVM_DEBUG( dbgs() << "[AAMemoryLocation] Accessed state after argument handling: " @@ -6514,7 +6831,9 @@ struct AAMemoryLocationFunction final : public AAMemoryLocationImpl { LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Accessed locations for " << I << ": " << getMemoryLocationsAsStr(MLK) << "\n"); removeAssumedBits(inverseLocation(MLK, false, false)); - return true; + // Stop once only the valid bit set in the *not assumed location*, thus + // once we don't actually exclude any memory locations in the state. + return getAssumedNotAccessedLocation() != VALID_STATE; }; if (!A.checkForAllReadWriteInstructions(CheckRWInst, *this)) @@ -6546,10 +6865,8 @@ struct AAMemoryLocationCallSite final : AAMemoryLocationImpl { void initialize(Attributor &A) override { AAMemoryLocationImpl::initialize(A); Function *F = getAssociatedFunction(); - if (!F || !A.isFunctionIPOAmendable(*F)) { + if (!F || F->isDeclaration()) indicatePessimisticFixpoint(); - return; - } } /// See AbstractAttribute::updateImpl(...). @@ -6655,7 +6972,6 @@ struct AAValueConstantRangeImpl : AAValueConstantRange { if (!LVI || !CtxI) return getWorstState(getBitWidth()); return LVI->getConstantRange(&getAssociatedValue(), - const_cast(CtxI->getParent()), const_cast(CtxI)); } @@ -6759,10 +7075,13 @@ struct AAValueConstantRangeImpl : AAValueConstantRange { auto &V = getAssociatedValue(); if (!AssumedConstantRange.isEmptySet() && !AssumedConstantRange.isSingleElement()) { - if (Instruction *I = dyn_cast(&V)) + if (Instruction *I = dyn_cast(&V)) { + assert(I == getCtxI() && "Should not annotate an instruction which is " + "not the context instruction"); if (isa(I) || isa(I)) if (setRangeMetadataIfisBetterRange(I, AssumedConstantRange)) Changed = ChangeStatus::CHANGED; + } } return Changed; @@ -6831,6 +7150,9 @@ struct AAValueConstantRangeFloating : AAValueConstantRangeImpl { return; } + if (isa(&V)) + return; + if (isa(&V) || isa(&V) || isa(&V)) return; // If it is a load instruction with range metadata, use it. @@ -7068,11 +7390,641 @@ struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating { AAValueConstantRangeCallSiteArgument(const IRPosition &IRP, Attributor &A) : AAValueConstantRangeFloating(IRP, A) {} + /// See AbstractAttribute::manifest() + ChangeStatus manifest(Attributor &A) override { + return ChangeStatus::UNCHANGED; + } + /// See AbstractAttribute::trackStatistics() void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(value_range) } }; + +/// ------------------ Potential Values Attribute ------------------------- + +struct AAPotentialValuesImpl : AAPotentialValues { + using StateType = PotentialConstantIntValuesState; + + AAPotentialValuesImpl(const IRPosition &IRP, Attributor &A) + : AAPotentialValues(IRP, A) {} + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + std::string Str; + llvm::raw_string_ostream OS(Str); + OS << getState(); + return OS.str(); + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + return indicatePessimisticFixpoint(); + } +}; + +struct AAPotentialValuesArgument final + : AAArgumentFromCallSiteArguments { + using Base = + AAArgumentFromCallSiteArguments; + AAPotentialValuesArgument(const IRPosition &IRP, Attributor &A) + : Base(IRP, A) {} + + /// See AbstractAttribute::initialize(..). + void initialize(Attributor &A) override { + if (!getAnchorScope() || getAnchorScope()->isDeclaration()) { + indicatePessimisticFixpoint(); + } else { + Base::initialize(A); + } + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_ARG_ATTR(potential_values) + } +}; + +struct AAPotentialValuesReturned + : AAReturnedFromReturnedValues { + using Base = + AAReturnedFromReturnedValues; + AAPotentialValuesReturned(const IRPosition &IRP, Attributor &A) + : Base(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_FNRET_ATTR(potential_values) + } +}; + +struct AAPotentialValuesFloating : AAPotentialValuesImpl { + AAPotentialValuesFloating(const IRPosition &IRP, Attributor &A) + : AAPotentialValuesImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(..). + void initialize(Attributor &A) override { + Value &V = getAssociatedValue(); + + if (auto *C = dyn_cast(&V)) { + unionAssumed(C->getValue()); + indicateOptimisticFixpoint(); + return; + } + + if (isa(&V)) { + unionAssumedWithUndef(); + indicateOptimisticFixpoint(); + return; + } + + if (isa(&V) || isa(&V) || isa(&V)) + return; + + if (isa(V) || isa(V)) + return; + + indicatePessimisticFixpoint(); + + LLVM_DEBUG(dbgs() << "[AAPotentialValues] We give up: " + << getAssociatedValue() << "\n"); + } + + static bool calculateICmpInst(const ICmpInst *ICI, const APInt &LHS, + const APInt &RHS) { + ICmpInst::Predicate Pred = ICI->getPredicate(); + switch (Pred) { + case ICmpInst::ICMP_UGT: + return LHS.ugt(RHS); + case ICmpInst::ICMP_SGT: + return LHS.sgt(RHS); + case ICmpInst::ICMP_EQ: + return LHS.eq(RHS); + case ICmpInst::ICMP_UGE: + return LHS.uge(RHS); + case ICmpInst::ICMP_SGE: + return LHS.sge(RHS); + case ICmpInst::ICMP_ULT: + return LHS.ult(RHS); + case ICmpInst::ICMP_SLT: + return LHS.slt(RHS); + case ICmpInst::ICMP_NE: + return LHS.ne(RHS); + case ICmpInst::ICMP_ULE: + return LHS.ule(RHS); + case ICmpInst::ICMP_SLE: + return LHS.sle(RHS); + default: + llvm_unreachable("Invalid ICmp predicate!"); + } + } + + static APInt calculateCastInst(const CastInst *CI, const APInt &Src, + uint32_t ResultBitWidth) { + Instruction::CastOps CastOp = CI->getOpcode(); + switch (CastOp) { + default: + llvm_unreachable("unsupported or not integer cast"); + case Instruction::Trunc: + return Src.trunc(ResultBitWidth); + case Instruction::SExt: + return Src.sext(ResultBitWidth); + case Instruction::ZExt: + return Src.zext(ResultBitWidth); + case Instruction::BitCast: + return Src; + } + } + + static APInt calculateBinaryOperator(const BinaryOperator *BinOp, + const APInt &LHS, const APInt &RHS, + bool &SkipOperation, bool &Unsupported) { + Instruction::BinaryOps BinOpcode = BinOp->getOpcode(); + // Unsupported is set to true when the binary operator is not supported. + // SkipOperation is set to true when UB occur with the given operand pair + // (LHS, RHS). + // TODO: we should look at nsw and nuw keywords to handle operations + // that create poison or undef value. + switch (BinOpcode) { + default: + Unsupported = true; + return LHS; + case Instruction::Add: + return LHS + RHS; + case Instruction::Sub: + return LHS - RHS; + case Instruction::Mul: + return LHS * RHS; + case Instruction::UDiv: + if (RHS.isNullValue()) { + SkipOperation = true; + return LHS; + } + return LHS.udiv(RHS); + case Instruction::SDiv: + if (RHS.isNullValue()) { + SkipOperation = true; + return LHS; + } + return LHS.sdiv(RHS); + case Instruction::URem: + if (RHS.isNullValue()) { + SkipOperation = true; + return LHS; + } + return LHS.urem(RHS); + case Instruction::SRem: + if (RHS.isNullValue()) { + SkipOperation = true; + return LHS; + } + return LHS.srem(RHS); + case Instruction::Shl: + return LHS.shl(RHS); + case Instruction::LShr: + return LHS.lshr(RHS); + case Instruction::AShr: + return LHS.ashr(RHS); + case Instruction::And: + return LHS & RHS; + case Instruction::Or: + return LHS | RHS; + case Instruction::Xor: + return LHS ^ RHS; + } + } + + bool calculateBinaryOperatorAndTakeUnion(const BinaryOperator *BinOp, + const APInt &LHS, const APInt &RHS) { + bool SkipOperation = false; + bool Unsupported = false; + APInt Result = + calculateBinaryOperator(BinOp, LHS, RHS, SkipOperation, Unsupported); + if (Unsupported) + return false; + // If SkipOperation is true, we can ignore this operand pair (L, R). + if (!SkipOperation) + unionAssumed(Result); + return isValidState(); + } + + ChangeStatus updateWithICmpInst(Attributor &A, ICmpInst *ICI) { + auto AssumedBefore = getAssumed(); + Value *LHS = ICI->getOperand(0); + Value *RHS = ICI->getOperand(1); + if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy()) + return indicatePessimisticFixpoint(); + + auto &LHSAA = A.getAAFor(*this, IRPosition::value(*LHS)); + if (!LHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + auto &RHSAA = A.getAAFor(*this, IRPosition::value(*RHS)); + if (!RHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + const DenseSet &LHSAAPVS = LHSAA.getAssumedSet(); + const DenseSet &RHSAAPVS = RHSAA.getAssumedSet(); + + // TODO: make use of undef flag to limit potential values aggressively. + bool MaybeTrue = false, MaybeFalse = false; + const APInt Zero(RHS->getType()->getIntegerBitWidth(), 0); + if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) { + // The result of any comparison between undefs can be soundly replaced + // with undef. + unionAssumedWithUndef(); + } else if (LHSAA.undefIsContained()) { + bool MaybeTrue = false, MaybeFalse = false; + for (const APInt &R : RHSAAPVS) { + bool CmpResult = calculateICmpInst(ICI, Zero, R); + MaybeTrue |= CmpResult; + MaybeFalse |= !CmpResult; + if (MaybeTrue & MaybeFalse) + return indicatePessimisticFixpoint(); + } + } else if (RHSAA.undefIsContained()) { + for (const APInt &L : LHSAAPVS) { + bool CmpResult = calculateICmpInst(ICI, L, Zero); + MaybeTrue |= CmpResult; + MaybeFalse |= !CmpResult; + if (MaybeTrue & MaybeFalse) + return indicatePessimisticFixpoint(); + } + } else { + for (const APInt &L : LHSAAPVS) { + for (const APInt &R : RHSAAPVS) { + bool CmpResult = calculateICmpInst(ICI, L, R); + MaybeTrue |= CmpResult; + MaybeFalse |= !CmpResult; + if (MaybeTrue & MaybeFalse) + return indicatePessimisticFixpoint(); + } + } + } + if (MaybeTrue) + unionAssumed(APInt(/* numBits */ 1, /* val */ 1)); + if (MaybeFalse) + unionAssumed(APInt(/* numBits */ 1, /* val */ 0)); + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + ChangeStatus updateWithSelectInst(Attributor &A, SelectInst *SI) { + auto AssumedBefore = getAssumed(); + Value *LHS = SI->getTrueValue(); + Value *RHS = SI->getFalseValue(); + if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy()) + return indicatePessimisticFixpoint(); + + // TODO: Use assumed simplified condition value + auto &LHSAA = A.getAAFor(*this, IRPosition::value(*LHS)); + if (!LHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + auto &RHSAA = A.getAAFor(*this, IRPosition::value(*RHS)); + if (!RHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) + // select i1 *, undef , undef => undef + unionAssumedWithUndef(); + else { + unionAssumed(LHSAA); + unionAssumed(RHSAA); + } + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + ChangeStatus updateWithCastInst(Attributor &A, CastInst *CI) { + auto AssumedBefore = getAssumed(); + if (!CI->isIntegerCast()) + return indicatePessimisticFixpoint(); + assert(CI->getNumOperands() == 1 && "Expected cast to be unary!"); + uint32_t ResultBitWidth = CI->getDestTy()->getIntegerBitWidth(); + Value *Src = CI->getOperand(0); + auto &SrcAA = A.getAAFor(*this, IRPosition::value(*Src)); + if (!SrcAA.isValidState()) + return indicatePessimisticFixpoint(); + const DenseSet &SrcAAPVS = SrcAA.getAssumedSet(); + if (SrcAA.undefIsContained()) + unionAssumedWithUndef(); + else { + for (const APInt &S : SrcAAPVS) { + APInt T = calculateCastInst(CI, S, ResultBitWidth); + unionAssumed(T); + } + } + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + ChangeStatus updateWithBinaryOperator(Attributor &A, BinaryOperator *BinOp) { + auto AssumedBefore = getAssumed(); + Value *LHS = BinOp->getOperand(0); + Value *RHS = BinOp->getOperand(1); + if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy()) + return indicatePessimisticFixpoint(); + + auto &LHSAA = A.getAAFor(*this, IRPosition::value(*LHS)); + if (!LHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + auto &RHSAA = A.getAAFor(*this, IRPosition::value(*RHS)); + if (!RHSAA.isValidState()) + return indicatePessimisticFixpoint(); + + const DenseSet &LHSAAPVS = LHSAA.getAssumedSet(); + const DenseSet &RHSAAPVS = RHSAA.getAssumedSet(); + const APInt Zero = APInt(LHS->getType()->getIntegerBitWidth(), 0); + + // TODO: make use of undef flag to limit potential values aggressively. + if (LHSAA.undefIsContained() && RHSAA.undefIsContained()) { + if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero)) + return indicatePessimisticFixpoint(); + } else if (LHSAA.undefIsContained()) { + for (const APInt &R : RHSAAPVS) { + if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R)) + return indicatePessimisticFixpoint(); + } + } else if (RHSAA.undefIsContained()) { + for (const APInt &L : LHSAAPVS) { + if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero)) + return indicatePessimisticFixpoint(); + } + } else { + for (const APInt &L : LHSAAPVS) { + for (const APInt &R : RHSAAPVS) { + if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R)) + return indicatePessimisticFixpoint(); + } + } + } + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + ChangeStatus updateWithPHINode(Attributor &A, PHINode *PHI) { + auto AssumedBefore = getAssumed(); + for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) { + Value *IncomingValue = PHI->getIncomingValue(u); + auto &PotentialValuesAA = A.getAAFor( + *this, IRPosition::value(*IncomingValue)); + if (!PotentialValuesAA.isValidState()) + return indicatePessimisticFixpoint(); + if (PotentialValuesAA.undefIsContained()) + unionAssumedWithUndef(); + else + unionAssumed(PotentialValuesAA.getAssumed()); + } + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + Value &V = getAssociatedValue(); + Instruction *I = dyn_cast(&V); + + if (auto *ICI = dyn_cast(I)) + return updateWithICmpInst(A, ICI); + + if (auto *SI = dyn_cast(I)) + return updateWithSelectInst(A, SI); + + if (auto *CI = dyn_cast(I)) + return updateWithCastInst(A, CI); + + if (auto *BinOp = dyn_cast(I)) + return updateWithBinaryOperator(A, BinOp); + + if (auto *PHI = dyn_cast(I)) + return updateWithPHINode(A, PHI); + + return indicatePessimisticFixpoint(); + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_FLOATING_ATTR(potential_values) + } +}; + +struct AAPotentialValuesFunction : AAPotentialValuesImpl { + AAPotentialValuesFunction(const IRPosition &IRP, Attributor &A) + : AAPotentialValuesImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + ChangeStatus updateImpl(Attributor &A) override { + llvm_unreachable("AAPotentialValues(Function|CallSite)::updateImpl will " + "not be called"); + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_FN_ATTR(potential_values) + } +}; + +struct AAPotentialValuesCallSite : AAPotentialValuesFunction { + AAPotentialValuesCallSite(const IRPosition &IRP, Attributor &A) + : AAPotentialValuesFunction(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_CS_ATTR(potential_values) + } +}; + +struct AAPotentialValuesCallSiteReturned + : AACallSiteReturnedFromReturned { + AAPotentialValuesCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AACallSiteReturnedFromReturned(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_CSRET_ATTR(potential_values) + } +}; + +struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating { + AAPotentialValuesCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AAPotentialValuesFloating(IRP, A) {} + + /// See AbstractAttribute::initialize(..). + void initialize(Attributor &A) override { + Value &V = getAssociatedValue(); + + if (auto *C = dyn_cast(&V)) { + unionAssumed(C->getValue()); + indicateOptimisticFixpoint(); + return; + } + + if (isa(&V)) { + unionAssumedWithUndef(); + indicateOptimisticFixpoint(); + return; + } + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + Value &V = getAssociatedValue(); + auto AssumedBefore = getAssumed(); + auto &AA = A.getAAFor(*this, IRPosition::value(V)); + const auto &S = AA.getAssumed(); + unionAssumed(S); + return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED + : ChangeStatus::CHANGED; + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { + STATS_DECLTRACK_CSARG_ATTR(potential_values) + } +}; + +/// ------------------------ NoUndef Attribute --------------------------------- +struct AANoUndefImpl : AANoUndef { + AANoUndefImpl(const IRPosition &IRP, Attributor &A) : AANoUndef(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + if (getIRPosition().hasAttr({Attribute::NoUndef})) { + indicateOptimisticFixpoint(); + return; + } + Value &V = getAssociatedValue(); + if (isa(V)) + indicatePessimisticFixpoint(); + else if (isa(V)) + indicateOptimisticFixpoint(); + else if (getPositionKind() != IRPosition::IRP_RETURNED && + isGuaranteedNotToBeUndefOrPoison(&V)) + indicateOptimisticFixpoint(); + else + AANoUndef::initialize(A); + } + + /// See followUsesInMBEC + bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I, + AANoUndef::StateType &State) { + const Value *UseV = U->get(); + const DominatorTree *DT = nullptr; + AssumptionCache *AC = nullptr; + InformationCache &InfoCache = A.getInfoCache(); + if (Function *F = getAnchorScope()) { + DT = InfoCache.getAnalysisResultForFunction(*F); + AC = InfoCache.getAnalysisResultForFunction(*F); + } + State.setKnown(isGuaranteedNotToBeUndefOrPoison(UseV, AC, I, DT)); + bool TrackUse = false; + // Track use for instructions which must produce undef or poison bits when + // at least one operand contains such bits. + if (isa(*I) || isa(*I)) + TrackUse = true; + return TrackUse; + } + + /// See AbstractAttribute::getAsStr(). + const std::string getAsStr() const override { + return getAssumed() ? "noundef" : "may-undef-or-poison"; + } + + ChangeStatus manifest(Attributor &A) override { + // We don't manifest noundef attribute for dead positions because the + // associated values with dead positions would be replaced with undef + // values. + if (A.isAssumedDead(getIRPosition(), nullptr, nullptr)) + return ChangeStatus::UNCHANGED; + // A position whose simplified value does not have any value is + // considered to be dead. We don't manifest noundef in such positions for + // the same reason above. + auto &ValueSimplifyAA = A.getAAFor( + *this, getIRPosition(), /* TrackDependence */ false); + if (!ValueSimplifyAA.getAssumedSimplifiedValue(A).hasValue()) + return ChangeStatus::UNCHANGED; + return AANoUndef::manifest(A); + } +}; + +struct AANoUndefFloating : public AANoUndefImpl { + AANoUndefFloating(const IRPosition &IRP, Attributor &A) + : AANoUndefImpl(IRP, A) {} + + /// See AbstractAttribute::initialize(...). + void initialize(Attributor &A) override { + AANoUndefImpl::initialize(A); + if (!getState().isAtFixpoint()) + if (Instruction *CtxI = getCtxI()) + followUsesInMBEC(*this, A, getState(), *CtxI); + } + + /// See AbstractAttribute::updateImpl(...). + ChangeStatus updateImpl(Attributor &A) override { + auto VisitValueCB = [&](Value &V, const Instruction *CtxI, + AANoUndef::StateType &T, bool Stripped) -> bool { + const auto &AA = A.getAAFor(*this, IRPosition::value(V)); + if (!Stripped && this == &AA) { + T.indicatePessimisticFixpoint(); + } else { + const AANoUndef::StateType &S = + static_cast(AA.getState()); + T ^= S; + } + return T.isValidState(); + }; + + StateType T; + if (!genericValueTraversal( + A, getIRPosition(), *this, T, VisitValueCB, getCtxI())) + return indicatePessimisticFixpoint(); + + return clampStateAndIndicateChange(getState(), T); + } + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noundef) } +}; + +struct AANoUndefReturned final + : AAReturnedFromReturnedValues { + AANoUndefReturned(const IRPosition &IRP, Attributor &A) + : AAReturnedFromReturnedValues(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noundef) } +}; + +struct AANoUndefArgument final + : AAArgumentFromCallSiteArguments { + AANoUndefArgument(const IRPosition &IRP, Attributor &A) + : AAArgumentFromCallSiteArguments(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noundef) } +}; + +struct AANoUndefCallSiteArgument final : AANoUndefFloating { + AANoUndefCallSiteArgument(const IRPosition &IRP, Attributor &A) + : AANoUndefFloating(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noundef) } +}; + +struct AANoUndefCallSiteReturned final + : AACallSiteReturnedFromReturned { + AANoUndefCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AACallSiteReturnedFromReturned(IRP, A) {} + + /// See AbstractAttribute::trackStatistics() + void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noundef) } +}; } // namespace const char AAReturnedValues::ID = 0; @@ -7096,6 +8048,8 @@ const char AAPrivatizablePtr::ID = 0; const char AAMemoryBehavior::ID = 0; const char AAMemoryLocation::ID = 0; const char AAValueConstantRange::ID = 0; +const char AAPotentialValues::ID = 0; +const char AANoUndef::ID = 0; // Macro magic to create the static generator function for attributes that // follow the naming scheme. @@ -7205,6 +8159,8 @@ CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture) CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueConstantRange) +CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialValues) +CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUndef) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify) CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead) diff --git a/llvm/lib/Transforms/IPO/BlockExtractor.cpp b/llvm/lib/Transforms/IPO/BlockExtractor.cpp index 1d1300c6cd1d..c6e222a096eb 100644 --- a/llvm/lib/Transforms/IPO/BlockExtractor.cpp +++ b/llvm/lib/Transforms/IPO/BlockExtractor.cpp @@ -11,10 +11,12 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/BlockExtractor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" @@ -38,13 +40,10 @@ cl::opt BlockExtractorEraseFuncs("extract-blocks-erase-funcs", cl::desc("Erase the existing functions"), cl::Hidden); namespace { -class BlockExtractor : public ModulePass { - SmallVector, 4> GroupsOfBlocks; - bool EraseFunctions; - /// Map a function name to groups of blocks. - SmallVector>, 4> - BlocksByName; - +class BlockExtractor { +public: + BlockExtractor(bool EraseFunctions) : EraseFunctions(EraseFunctions) {} + bool runOnModule(Module &M); void init(const SmallVectorImpl> &GroupsOfBlocksToExtract) { for (const SmallVectorImpl &GroupOfBlocks : @@ -57,11 +56,26 @@ class BlockExtractor : public ModulePass { loadFile(); } +private: + SmallVector, 4> GroupsOfBlocks; + bool EraseFunctions; + /// Map a function name to groups of blocks. + SmallVector>, 4> + BlocksByName; + + void loadFile(); + void splitLandingPadPreds(Function &F); +}; + +class BlockExtractorLegacyPass : public ModulePass { + BlockExtractor BE; + bool runOnModule(Module &M) override; + public: static char ID; - BlockExtractor(const SmallVectorImpl &BlocksToExtract, - bool EraseFunctions) - : ModulePass(ID), EraseFunctions(EraseFunctions) { + BlockExtractorLegacyPass(const SmallVectorImpl &BlocksToExtract, + bool EraseFunctions) + : ModulePass(ID), BE(EraseFunctions) { // We want one group per element of the input list. SmallVector, 4> MassagedGroupsOfBlocks; for (BasicBlock *BB : BlocksToExtract) { @@ -69,39 +83,38 @@ public: NewGroup.push_back(BB); MassagedGroupsOfBlocks.push_back(NewGroup); } - init(MassagedGroupsOfBlocks); + BE.init(MassagedGroupsOfBlocks); } - BlockExtractor(const SmallVectorImpl> - &GroupsOfBlocksToExtract, - bool EraseFunctions) - : ModulePass(ID), EraseFunctions(EraseFunctions) { - init(GroupsOfBlocksToExtract); + BlockExtractorLegacyPass(const SmallVectorImpl> + &GroupsOfBlocksToExtract, + bool EraseFunctions) + : ModulePass(ID), BE(EraseFunctions) { + BE.init(GroupsOfBlocksToExtract); } - BlockExtractor() : BlockExtractor(SmallVector(), false) {} - bool runOnModule(Module &M) override; - -private: - void loadFile(); - void splitLandingPadPreds(Function &F); + BlockExtractorLegacyPass() + : BlockExtractorLegacyPass(SmallVector(), false) {} }; + } // end anonymous namespace -char BlockExtractor::ID = 0; -INITIALIZE_PASS(BlockExtractor, "extract-blocks", +char BlockExtractorLegacyPass::ID = 0; +INITIALIZE_PASS(BlockExtractorLegacyPass, "extract-blocks", "Extract basic blocks from module", false, false) -ModulePass *llvm::createBlockExtractorPass() { return new BlockExtractor(); } +ModulePass *llvm::createBlockExtractorPass() { + return new BlockExtractorLegacyPass(); +} ModulePass *llvm::createBlockExtractorPass( const SmallVectorImpl &BlocksToExtract, bool EraseFunctions) { - return new BlockExtractor(BlocksToExtract, EraseFunctions); + return new BlockExtractorLegacyPass(BlocksToExtract, EraseFunctions); } ModulePass *llvm::createBlockExtractorPass( const SmallVectorImpl> &GroupsOfBlocksToExtract, bool EraseFunctions) { - return new BlockExtractor(GroupsOfBlocksToExtract, EraseFunctions); + return new BlockExtractorLegacyPass(GroupsOfBlocksToExtract, EraseFunctions); } /// Gets all of the blocks specified in the input file. @@ -233,3 +246,15 @@ bool BlockExtractor::runOnModule(Module &M) { return Changed; } + +bool BlockExtractorLegacyPass::runOnModule(Module &M) { + return BE.runOnModule(M); +} + +PreservedAnalyses BlockExtractorPass::run(Module &M, + ModuleAnalysisManager &AM) { + BlockExtractor BE(false); + BE.init(SmallVector, 0>()); + return BE.runOnModule(M) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp index 54c51b6e7161..0b763e423fe0 100644 --- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp @@ -289,7 +289,7 @@ bool DeadArgumentEliminationPass::RemoveDeadArgumentsFromCallers(Function &Fn) { for (Argument &Arg : Fn.args()) { if (!Arg.hasSwiftErrorAttr() && Arg.use_empty() && - !Arg.hasPassPointeeByValueAttr()) { + !Arg.hasPassPointeeByValueCopyAttr()) { if (Arg.isUsedByMetadata()) { Arg.replaceAllUsesWith(UndefValue::get(Arg.getType())); Changed = true; @@ -357,7 +357,7 @@ DeadArgumentEliminationPass::Liveness DeadArgumentEliminationPass::MarkIfNotLive(RetOrArg Use, UseVector &MaybeLiveUses) { // We're live if our use or its Function is already marked as live. - if (LiveFunctions.count(Use.F) || LiveValues.count(Use)) + if (IsLive(Use)) return Live; // We're maybe live otherwise, but remember that we must become live if @@ -657,10 +657,18 @@ void DeadArgumentEliminationPass::MarkValue(const RetOrArg &RA, Liveness L, MarkLive(RA); break; case MaybeLive: - // Note any uses of this value, so this return value can be - // marked live whenever one of the uses becomes live. - for (const auto &MaybeLiveUse : MaybeLiveUses) - Uses.insert(std::make_pair(MaybeLiveUse, RA)); + assert(!IsLive(RA) && "Use is already live!"); + for (const auto &MaybeLiveUse : MaybeLiveUses) { + if (IsLive(MaybeLiveUse)) { + // A use is live, so this value is live. + MarkLive(RA); + break; + } else { + // Note any uses of this value, so this value can be + // marked live whenever one of the uses becomes live. + Uses.insert(std::make_pair(MaybeLiveUse, RA)); + } + } break; } } @@ -686,17 +694,20 @@ void DeadArgumentEliminationPass::MarkLive(const Function &F) { /// mark any values that are used by this value (according to Uses) live as /// well. void DeadArgumentEliminationPass::MarkLive(const RetOrArg &RA) { - if (LiveFunctions.count(RA.F)) - return; // Function was already marked Live. + if (IsLive(RA)) + return; // Already marked Live. - if (!LiveValues.insert(RA).second) - return; // We were already marked Live. + LiveValues.insert(RA); LLVM_DEBUG(dbgs() << "DeadArgumentEliminationPass - Marking " << RA.getDescription() << " live\n"); PropagateLiveness(RA); } +bool DeadArgumentEliminationPass::IsLive(const RetOrArg &RA) { + return LiveFunctions.count(RA.F) || LiveValues.count(RA); +} + /// PropagateLiveness - Given that RA is a live value, propagate it's liveness /// to any other values it uses (according to Uses). void DeadArgumentEliminationPass::PropagateLiveness(const RetOrArg &RA) { diff --git a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp index 2cb184e8d4f4..1a8bb225a626 100644 --- a/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/ForceFunctionAttrs.cpp @@ -26,6 +26,13 @@ static cl::list "example -force-attribute=foo:noinline. This " "option can be specified multiple times.")); +static cl::list ForceRemoveAttributes( + "force-remove-attribute", cl::Hidden, + cl::desc("Remove an attribute from a function. This should be a " + "pair of 'function-name:attribute-name', for " + "example -force-remove-attribute=foo:noinline. This " + "option can be specified multiple times.")); + static Attribute::AttrKind parseAttrKind(StringRef Kind) { return StringSwitch(Kind) .Case("alwaysinline", Attribute::AlwaysInline) @@ -70,31 +77,49 @@ static Attribute::AttrKind parseAttrKind(StringRef Kind) { } /// If F has any forced attributes given on the command line, add them. -static void addForcedAttributes(Function &F) { - for (auto &S : ForceAttributes) { +/// If F has any forced remove attributes given on the command line, remove +/// them. When both force and force-remove are given to a function, the latter +/// takes precedence. +static void forceAttributes(Function &F) { + auto ParseFunctionAndAttr = [&](StringRef S) { + auto Kind = Attribute::None; auto KV = StringRef(S).split(':'); if (KV.first != F.getName()) - continue; - - auto Kind = parseAttrKind(KV.second); + return Kind; + Kind = parseAttrKind(KV.second); if (Kind == Attribute::None) { LLVM_DEBUG(dbgs() << "ForcedAttribute: " << KV.second << " unknown or not handled!\n"); - continue; } - if (F.hasFnAttribute(Kind)) + return Kind; + }; + + for (auto &S : ForceAttributes) { + auto Kind = ParseFunctionAndAttr(S); + if (Kind == Attribute::None || F.hasFnAttribute(Kind)) continue; F.addFnAttr(Kind); } + + for (auto &S : ForceRemoveAttributes) { + auto Kind = ParseFunctionAndAttr(S); + if (Kind == Attribute::None || !F.hasFnAttribute(Kind)) + continue; + F.removeFnAttr(Kind); + } +} + +static bool hasForceAttributes() { + return !ForceAttributes.empty() || !ForceRemoveAttributes.empty(); } PreservedAnalyses ForceFunctionAttrsPass::run(Module &M, ModuleAnalysisManager &) { - if (ForceAttributes.empty()) + if (!hasForceAttributes()) return PreservedAnalyses::all(); for (Function &F : M.functions()) - addForcedAttributes(F); + forceAttributes(F); // Just conservatively invalidate analyses, this isn't likely to be important. return PreservedAnalyses::none(); @@ -109,11 +134,11 @@ struct ForceFunctionAttrsLegacyPass : public ModulePass { } bool runOnModule(Module &M) override { - if (ForceAttributes.empty()) + if (!hasForceAttributes()) return false; for (Function &F : M.functions()) - addForcedAttributes(F); + forceAttributes(F); // Conservatively assume we changed something. return true; diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp index 4baeaa6e1630..30a1f81ad0e1 100644 --- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp @@ -13,15 +13,16 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/IPO/FunctionAttrs.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/CGSCCPassManager.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" @@ -63,7 +64,7 @@ using namespace llvm; -#define DEBUG_TYPE "functionattrs" +#define DEBUG_TYPE "function-attrs" STATISTIC(NumReadNone, "Number of functions marked readnone"); STATISTIC(NumReadOnly, "Number of functions marked readonly"); @@ -77,6 +78,7 @@ STATISTIC(NumNonNullReturn, "Number of function returns marked nonnull"); STATISTIC(NumNoRecurse, "Number of functions marked as norecurse"); STATISTIC(NumNoUnwind, "Number of functions marked as nounwind"); STATISTIC(NumNoFree, "Number of functions marked as nofree"); +STATISTIC(NumWillReturn, "Number of functions marked as willreturn"); static cl::opt EnableNonnullArgPropagation( "enable-nonnull-arg-prop", cl::init(true), cl::Hidden, @@ -166,7 +168,7 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, bool ThisBody, AAMDNodes AAInfo; I->getAAMetadata(AAInfo); - MemoryLocation Loc(Arg, LocationSize::unknown(), AAInfo); + MemoryLocation Loc = MemoryLocation::getBeforeOrAfter(Arg, AAInfo); // Skip accesses to local or constant memory as they don't impact the // externally visible mod/ref behavior. @@ -281,16 +283,18 @@ static bool addReadAttrs(const SCCNodeSet &SCCNodes, AARGetterT &&AARGetter) { MadeChange = true; // Clear out any existing attributes. - F->removeFnAttr(Attribute::ReadOnly); - F->removeFnAttr(Attribute::ReadNone); - F->removeFnAttr(Attribute::WriteOnly); + AttrBuilder AttrsToRemove; + AttrsToRemove.addAttribute(Attribute::ReadOnly); + AttrsToRemove.addAttribute(Attribute::ReadNone); + AttrsToRemove.addAttribute(Attribute::WriteOnly); if (!WritesMemory && !ReadsMemory) { // Clear out any "access range attributes" if readnone was deduced. - F->removeFnAttr(Attribute::ArgMemOnly); - F->removeFnAttr(Attribute::InaccessibleMemOnly); - F->removeFnAttr(Attribute::InaccessibleMemOrArgMemOnly); + AttrsToRemove.addAttribute(Attribute::ArgMemOnly); + AttrsToRemove.addAttribute(Attribute::InaccessibleMemOnly); + AttrsToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); } + F->removeAttributes(AttributeList::FunctionIndex, AttrsToRemove); // Add in the new attribute. if (WritesMemory && !ReadsMemory) @@ -639,7 +643,7 @@ static bool addArgumentAttrsFromCallsites(Function &F) { if (auto *CB = dyn_cast(&I)) { if (auto *CalledFunc = CB->getCalledFunction()) { for (auto &CSArg : CalledFunc->args()) { - if (!CSArg.hasNonNullAttr()) + if (!CSArg.hasNonNullAttr(/* AllowUndefOrPoison */ false)) continue; // If the non-null callsite argument operand is an argument to 'F' @@ -1216,6 +1220,11 @@ bool AttributeInferer::run(const SCCNodeSet &SCCNodes) { return Changed; } +struct SCCNodesResult { + SCCNodeSet SCCNodes; + bool HasUnknownCall; +}; + } // end anonymous namespace /// Helper for non-Convergent inference predicate InstrBreaksAttribute. @@ -1237,7 +1246,7 @@ static bool InstrBreaksNonThrowing(Instruction &I, const SCCNodeSet &SCCNodes) { // I is a may-throw call to a function inside our SCC. This doesn't // invalidate our current working assumption that the SCC is no-throw; we // just have to scan that other function. - if (SCCNodes.count(Callee) > 0) + if (SCCNodes.contains(Callee)) return false; } } @@ -1257,21 +1266,16 @@ static bool InstrBreaksNoFree(Instruction &I, const SCCNodeSet &SCCNodes) { if (Callee->doesNotFreeMemory()) return false; - if (SCCNodes.count(Callee) > 0) + if (SCCNodes.contains(Callee)) return false; return true; } -/// Infer attributes from all functions in the SCC by scanning every -/// instruction for compliance to the attribute assumptions. Currently it -/// does: -/// - removal of Convergent attribute -/// - addition of NoUnwind attribute +/// Attempt to remove convergent function attribute when possible. /// /// Returns true if any changes to function attributes were made. -static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) { - +static bool inferConvergent(const SCCNodeSet &SCCNodes) { AttributeInferer AI; // Request to remove the convergent attribute from all functions in the SCC @@ -1293,6 +1297,18 @@ static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) { F.setNotConvergent(); }, /* RequiresExactDefinition= */ false}); + // Perform all the requested attribute inference actions. + return AI.run(SCCNodes); +} + +/// Infer attributes from all functions in the SCC by scanning every +/// instruction for compliance to the attribute assumptions. Currently it +/// does: +/// - addition of NoUnwind attribute +/// +/// Returns true if any changes to function attributes were made. +static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) { + AttributeInferer AI; if (!DisableNoUnwindInference) // Request to infer nounwind attribute for all the functions in the SCC if @@ -1343,14 +1359,6 @@ static bool inferAttrsFromFunctionBodies(const SCCNodeSet &SCCNodes) { return AI.run(SCCNodes); } -static bool setDoesNotRecurse(Function &F) { - if (F.doesNotRecurse()) - return false; - F.setDoesNotRecurse(); - ++NumNoRecurse; - return true; -} - static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { // Try and identify functions that do not recurse. @@ -1377,30 +1385,140 @@ static bool addNoRecurseAttrs(const SCCNodeSet &SCCNodes) { // Every call was to a non-recursive function other than this function, and // we have no indirect recursion as the SCC size is one. This function cannot // recurse. - return setDoesNotRecurse(*F); + F->setDoesNotRecurse(); + ++NumNoRecurse; + return true; +} + +static bool instructionDoesNotReturn(Instruction &I) { + if (auto *CB = dyn_cast(&I)) { + Function *Callee = CB->getCalledFunction(); + return Callee && Callee->doesNotReturn(); + } + return false; +} + +// A basic block can only return if it terminates with a ReturnInst and does not +// contain calls to noreturn functions. +static bool basicBlockCanReturn(BasicBlock &BB) { + if (!isa(BB.getTerminator())) + return false; + return none_of(BB, instructionDoesNotReturn); +} + +// Set the noreturn function attribute if possible. +static bool addNoReturnAttrs(const SCCNodeSet &SCCNodes) { + bool Changed = false; + + for (Function *F : SCCNodes) { + if (!F || !F->hasExactDefinition() || F->hasFnAttribute(Attribute::Naked) || + F->doesNotReturn()) + continue; + + // The function can return if any basic blocks can return. + // FIXME: this doesn't handle recursion or unreachable blocks. + if (none_of(*F, basicBlockCanReturn)) { + F->setDoesNotReturn(); + Changed = true; + } + } + + return Changed; +} + +static bool functionWillReturn(const Function &F) { + // Must-progress function without side-effects must return. + if (F.mustProgress() && F.onlyReadsMemory()) + return true; + + // Can only analyze functions with a definition. + if (F.isDeclaration()) + return false; + + // Functions with loops require more sophisticated analysis, as the loop + // may be infinite. For now, don't try to handle them. + SmallVector> Backedges; + FindFunctionBackedges(F, Backedges); + if (!Backedges.empty()) + return false; + + // If there are no loops, then the function is willreturn if all calls in + // it are willreturn. + return all_of(instructions(F), [](const Instruction &I) { + const auto *CB = dyn_cast(&I); + return !CB || CB->hasFnAttr(Attribute::WillReturn); + }); +} + +// Set the willreturn function attribute if possible. +static bool addWillReturn(const SCCNodeSet &SCCNodes) { + bool Changed = false; + + for (Function *F : SCCNodes) { + if (!F || F->willReturn() || !functionWillReturn(*F)) + continue; + + F->setWillReturn(); + NumWillReturn++; + Changed = true; + } + + return Changed; +} + +static SCCNodesResult createSCCNodeSet(ArrayRef Functions) { + SCCNodesResult Res; + Res.HasUnknownCall = false; + for (Function *F : Functions) { + if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked)) { + // Treat any function we're trying not to optimize as if it were an + // indirect call and omit it from the node set used below. + Res.HasUnknownCall = true; + continue; + } + // Track whether any functions in this SCC have an unknown call edge. + // Note: if this is ever a performance hit, we can common it with + // subsequent routines which also do scans over the instructions of the + // function. + if (!Res.HasUnknownCall) { + for (Instruction &I : instructions(*F)) { + if (auto *CB = dyn_cast(&I)) { + if (!CB->getCalledFunction()) { + Res.HasUnknownCall = true; + break; + } + } + } + } + Res.SCCNodes.insert(F); + } + return Res; } template -static bool deriveAttrsInPostOrder(SCCNodeSet &SCCNodes, - AARGetterT &&AARGetter, - bool HasUnknownCall) { +static bool deriveAttrsInPostOrder(ArrayRef Functions, + AARGetterT &&AARGetter) { + SCCNodesResult Nodes = createSCCNodeSet(Functions); bool Changed = false; // Bail if the SCC only contains optnone functions. - if (SCCNodes.empty()) + if (Nodes.SCCNodes.empty()) return Changed; - Changed |= addArgumentReturnedAttrs(SCCNodes); - Changed |= addReadAttrs(SCCNodes, AARGetter); - Changed |= addArgumentAttrs(SCCNodes); + Changed |= addArgumentReturnedAttrs(Nodes.SCCNodes); + Changed |= addReadAttrs(Nodes.SCCNodes, AARGetter); + Changed |= addArgumentAttrs(Nodes.SCCNodes); + Changed |= inferConvergent(Nodes.SCCNodes); + Changed |= addNoReturnAttrs(Nodes.SCCNodes); + Changed |= addWillReturn(Nodes.SCCNodes); // If we have no external nodes participating in the SCC, we can deduce some // more precise attributes as well. - if (!HasUnknownCall) { - Changed |= addNoAliasAttrs(SCCNodes); - Changed |= addNonNullAttrs(SCCNodes); - Changed |= inferAttrsFromFunctionBodies(SCCNodes); - Changed |= addNoRecurseAttrs(SCCNodes); + if (!Nodes.HasUnknownCall) { + Changed |= addNoAliasAttrs(Nodes.SCCNodes); + Changed |= addNonNullAttrs(Nodes.SCCNodes); + Changed |= inferAttrsFromFunctionBodies(Nodes.SCCNodes); + Changed |= addNoRecurseAttrs(Nodes.SCCNodes); } return Changed; @@ -1419,35 +1537,12 @@ PreservedAnalyses PostOrderFunctionAttrsPass::run(LazyCallGraph::SCC &C, return FAM.getResult(F); }; - // Fill SCCNodes with the elements of the SCC. Also track whether there are - // any external or opt-none nodes that will prevent us from optimizing any - // part of the SCC. - SCCNodeSet SCCNodes; - bool HasUnknownCall = false; + SmallVector Functions; for (LazyCallGraph::Node &N : C) { - Function &F = N.getFunction(); - if (F.hasOptNone() || F.hasFnAttribute(Attribute::Naked)) { - // Treat any function we're trying not to optimize as if it were an - // indirect call and omit it from the node set used below. - HasUnknownCall = true; - continue; - } - // Track whether any functions in this SCC have an unknown call edge. - // Note: if this is ever a performance hit, we can common it with - // subsequent routines which also do scans over the instructions of the - // function. - if (!HasUnknownCall) - for (Instruction &I : instructions(F)) - if (auto *CB = dyn_cast(&I)) - if (!CB->getCalledFunction()) { - HasUnknownCall = true; - break; - } - - SCCNodes.insert(&F); + Functions.push_back(&N.getFunction()); } - if (deriveAttrsInPostOrder(SCCNodes, AARGetter, HasUnknownCall)) + if (deriveAttrsInPostOrder(Functions, AARGetter)) return PreservedAnalyses::none(); return PreservedAnalyses::all(); @@ -1477,11 +1572,11 @@ struct PostOrderFunctionAttrsLegacyPass : public CallGraphSCCPass { } // end anonymous namespace char PostOrderFunctionAttrsLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(PostOrderFunctionAttrsLegacyPass, "functionattrs", +INITIALIZE_PASS_BEGIN(PostOrderFunctionAttrsLegacyPass, "function-attrs", "Deduce function attributes", false, false) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) -INITIALIZE_PASS_END(PostOrderFunctionAttrsLegacyPass, "functionattrs", +INITIALIZE_PASS_END(PostOrderFunctionAttrsLegacyPass, "function-attrs", "Deduce function attributes", false, false) Pass *llvm::createPostOrderFunctionAttrsLegacyPass() { @@ -1490,26 +1585,12 @@ Pass *llvm::createPostOrderFunctionAttrsLegacyPass() { template static bool runImpl(CallGraphSCC &SCC, AARGetterT AARGetter) { - - // Fill SCCNodes with the elements of the SCC. Used for quickly looking up - // whether a given CallGraphNode is in this SCC. Also track whether there are - // any external or opt-none nodes that will prevent us from optimizing any - // part of the SCC. - SCCNodeSet SCCNodes; - bool ExternalNode = false; + SmallVector Functions; for (CallGraphNode *I : SCC) { - Function *F = I->getFunction(); - if (!F || F->hasOptNone() || F->hasFnAttribute(Attribute::Naked)) { - // External node or function we're trying not to optimize - we both avoid - // transform them and avoid leveraging information they provide. - ExternalNode = true; - continue; - } - - SCCNodes.insert(F); + Functions.push_back(I->getFunction()); } - return deriveAttrsInPostOrder(SCCNodes, AARGetter, ExternalNode); + return deriveAttrsInPostOrder(Functions, AARGetter); } bool PostOrderFunctionAttrsLegacyPass::runOnSCC(CallGraphSCC &SCC) { @@ -1542,11 +1623,13 @@ struct ReversePostOrderFunctionAttrsLegacyPass : public ModulePass { char ReversePostOrderFunctionAttrsLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(ReversePostOrderFunctionAttrsLegacyPass, "rpo-functionattrs", - "Deduce function attributes in RPO", false, false) +INITIALIZE_PASS_BEGIN(ReversePostOrderFunctionAttrsLegacyPass, + "rpo-function-attrs", "Deduce function attributes in RPO", + false, false) INITIALIZE_PASS_DEPENDENCY(CallGraphWrapperPass) -INITIALIZE_PASS_END(ReversePostOrderFunctionAttrsLegacyPass, "rpo-functionattrs", - "Deduce function attributes in RPO", false, false) +INITIALIZE_PASS_END(ReversePostOrderFunctionAttrsLegacyPass, + "rpo-function-attrs", "Deduce function attributes in RPO", + false, false) Pass *llvm::createReversePostOrderFunctionAttrsPass() { return new ReversePostOrderFunctionAttrsLegacyPass(); @@ -1578,7 +1661,9 @@ static bool addNoRecurseAttrsTopDown(Function &F) { if (!CB || !CB->getParent()->getParent()->doesNotRecurse()) return false; } - return setDoesNotRecurse(F); + F.setDoesNotRecurse(); + ++NumNoRecurse; + return true; } static bool deduceFunctionAttributeInRPO(Module &M, CallGraph &CG) { diff --git a/llvm/lib/Transforms/IPO/FunctionImport.cpp b/llvm/lib/Transforms/IPO/FunctionImport.cpp index 468bf19f2e48..18343030bc6a 100644 --- a/llvm/lib/Transforms/IPO/FunctionImport.cpp +++ b/llvm/lib/Transforms/IPO/FunctionImport.cpp @@ -124,14 +124,8 @@ static cl::opt ComputeDead("compute-dead", cl::init(true), cl::Hidden, cl::desc("Compute dead symbols")); static cl::opt EnableImportMetadata( - "enable-import-metadata", cl::init( -#if !defined(NDEBUG) - true /*Enabled with asserts.*/ -#else - false -#endif - ), - cl::Hidden, cl::desc("Enable import metadata like 'thinlto_src_module'")); + "enable-import-metadata", cl::init(false), cl::Hidden, + cl::desc("Enable import metadata like 'thinlto_src_module'")); /// Summary file to use for function importing when using -function-import from /// the command line. @@ -261,8 +255,8 @@ selectCallee(const ModuleSummaryIndex &Index, namespace { -using EdgeInfo = std::tuple; +using EdgeInfo = + std::tuple; } // anonymous namespace @@ -282,8 +276,9 @@ updateValueInfoForIndirectCalls(const ModuleSummaryIndex &Index, ValueInfo VI) { } static void computeImportForReferencedGlobals( - const FunctionSummary &Summary, const ModuleSummaryIndex &Index, + const GlobalValueSummary &Summary, const ModuleSummaryIndex &Index, const GVSummaryMapTy &DefinedGVSummaries, + SmallVectorImpl &Worklist, FunctionImporter::ImportMapTy &ImportList, StringMap *ExportLists) { for (auto &VI : Summary.refs()) { @@ -321,6 +316,11 @@ static void computeImportForReferencedGlobals( // which is more efficient than adding them here. if (ExportLists) (*ExportLists)[RefSummary->modulePath()].insert(VI); + + // If variable is not writeonly we attempt to recursively analyze + // its references in order to import referenced constants. + if (!Index.isWriteOnly(cast(RefSummary.get()))) + Worklist.emplace_back(RefSummary.get(), 0); break; } } @@ -360,7 +360,7 @@ static void computeImportForFunction( StringMap *ExportLists, FunctionImporter::ImportThresholdsTy &ImportThresholds) { computeImportForReferencedGlobals(Summary, Index, DefinedGVSummaries, - ImportList, ExportLists); + Worklist, ImportList, ExportLists); static int ImportCount = 0; for (auto &Edge : Summary.calls()) { ValueInfo VI = Edge.first; @@ -508,7 +508,7 @@ static void computeImportForFunction( ImportCount++; // Insert the newly imported function to the worklist. - Worklist.emplace_back(ResolvedCalleeSummary, AdjThreshold, VI.getGUID()); + Worklist.emplace_back(ResolvedCalleeSummary, AdjThreshold); } } @@ -549,13 +549,17 @@ static void ComputeImportForModule( // Process the newly imported functions and add callees to the worklist. while (!Worklist.empty()) { - auto FuncInfo = Worklist.pop_back_val(); - auto *Summary = std::get<0>(FuncInfo); - auto Threshold = std::get<1>(FuncInfo); - - computeImportForFunction(*Summary, Index, Threshold, DefinedGVSummaries, - Worklist, ImportList, ExportLists, - ImportThresholds); + auto GVInfo = Worklist.pop_back_val(); + auto *Summary = std::get<0>(GVInfo); + auto Threshold = std::get<1>(GVInfo); + + if (auto *FS = dyn_cast(Summary)) + computeImportForFunction(*FS, Index, Threshold, DefinedGVSummaries, + Worklist, ImportList, ExportLists, + ImportThresholds); + else + computeImportForReferencedGlobals(*Summary, Index, DefinedGVSummaries, + Worklist, ImportList, ExportLists); } // Print stats about functions considered but rejected for importing @@ -884,6 +888,7 @@ void llvm::computeDeadSymbols( while (!Worklist.empty()) { auto VI = Worklist.pop_back_val(); for (auto &Summary : VI.getSummaryList()) { + Summary->setLive(true); if (auto *AS = dyn_cast(Summary.get())) { // If this is an alias, visit the aliasee VI to ensure that all copies // are marked live and it is added to the worklist for further @@ -891,8 +896,6 @@ void llvm::computeDeadSymbols( visit(AS->getAliaseeVI(), true); continue; } - - Summary->setLive(true); for (auto Ref : Summary->refs()) visit(Ref, false); if (auto *FS = dyn_cast(Summary.get())) @@ -1311,7 +1314,7 @@ static bool doImportingForModule(Module &M) { // Next we need to promote to global scope and rename any local values that // are potentially exported to other modules. - if (renameModuleForThinLTO(M, *Index, /*clearDSOOnDeclarations=*/false, + if (renameModuleForThinLTO(M, *Index, /*ClearDSOLocalOnDeclarations=*/false, /*GlobalsToImport=*/nullptr)) { errs() << "Error renaming module\n"; return false; diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp index d9fb820f7cb5..223a05e8ea02 100644 --- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp +++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp @@ -268,6 +268,7 @@ CleanupPointerRootUsers(GlobalVariable *GV, I = J; } while (true); I->eraseFromParent(); + Changed = true; } } @@ -285,7 +286,7 @@ static bool CleanupConstantGlobalUsers( // we delete a constant array, we may also be holding pointer to one of its // elements (or an element of one of its elements if we're dealing with an // array of arrays) in the worklist. - SmallVector WorkList(V->user_begin(), V->user_end()); + SmallVector WorkList(V->users()); while (!WorkList.empty()) { Value *UV = WorkList.pop_back_val(); if (!UV) @@ -468,19 +469,16 @@ static bool CanDoGlobalSRA(GlobalVariable *GV) { /// Copy over the debug info for a variable to its SRA replacements. static void transferSRADebugInfo(GlobalVariable *GV, GlobalVariable *NGV, uint64_t FragmentOffsetInBits, - uint64_t FragmentSizeInBits) { + uint64_t FragmentSizeInBits, + uint64_t VarSize) { SmallVector GVs; GV->getDebugInfo(GVs); for (auto *GVE : GVs) { DIVariable *Var = GVE->getVariable(); - Optional VarSize = Var->getSizeInBits(); - DIExpression *Expr = GVE->getExpression(); // If the FragmentSize is smaller than the variable, // emit a fragment expression. - // If the variable size is unknown a fragment must be - // emitted to be safe. - if (!VarSize || FragmentSizeInBits < *VarSize) { + if (FragmentSizeInBits < VarSize) { if (auto E = DIExpression::createFragmentExpression( Expr, FragmentOffsetInBits, FragmentSizeInBits)) Expr = *E; @@ -505,6 +503,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { assert(GV->hasLocalLinkage()); Constant *Init = GV->getInitializer(); Type *Ty = Init->getType(); + uint64_t VarSize = DL.getTypeSizeInBits(Ty); std::map NewGlobals; @@ -560,7 +559,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { // Copy over the debug info for the variable. uint64_t Size = DL.getTypeAllocSizeInBits(NGV->getValueType()); uint64_t FragmentOffsetInBits = Layout.getElementOffsetInBits(ElementIdx); - transferSRADebugInfo(GV, NGV, FragmentOffsetInBits, Size); + transferSRADebugInfo(GV, NGV, FragmentOffsetInBits, Size, VarSize); } else { uint64_t EltSize = DL.getTypeAllocSize(ElTy); Align EltAlign = DL.getABITypeAlign(ElTy); @@ -573,7 +572,7 @@ static GlobalVariable *SRAGlobal(GlobalVariable *GV, const DataLayout &DL) { if (NewAlign > EltAlign) NGV->setAlignment(NewAlign); transferSRADebugInfo(GV, NGV, FragmentSizeInBits * ElementIdx, - FragmentSizeInBits); + FragmentSizeInBits, VarSize); } } @@ -1881,7 +1880,8 @@ static bool isPointerValueDeadOnEntryToFunction( // and the number of bits loaded in L is less than or equal to // the number of bits stored in S. return DT.dominates(S, L) && - DL.getTypeStoreSize(LTy) <= DL.getTypeStoreSize(STy); + DL.getTypeStoreSize(LTy).getFixedSize() <= + DL.getTypeStoreSize(STy).getFixedSize(); })) return false; } @@ -1933,8 +1933,7 @@ static void makeAllConstantUsesInstructions(Constant *C) { SmallVector UUsers; for (auto *U : Users) { UUsers.clear(); - for (auto *UU : U->users()) - UUsers.push_back(UU); + append_range(UUsers, U->users()); for (auto *UU : UUsers) { Instruction *UI = cast(UU); Instruction *NewU = U->getAsInstruction(); @@ -1991,12 +1990,13 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS, return true; } + bool Changed = false; + // If the global is never loaded (but may be stored to), it is dead. // Delete it now. if (!GS.IsLoaded) { LLVM_DEBUG(dbgs() << "GLOBAL NEVER LOADED: " << *GV << "\n"); - bool Changed; if (isLeakCheckerRoot(GV)) { // Delete any constant stores to the global. Changed = CleanupPointerRootUsers(GV, GetTLI); @@ -2022,11 +2022,14 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS, // Don't actually mark a global constant if it's atomic because atomic loads // are implemented by a trivial cmpxchg in some edge-cases and that usually // requires write access to the variable even if it's not actually changed. - if (GS.Ordering == AtomicOrdering::NotAtomic) + if (GS.Ordering == AtomicOrdering::NotAtomic) { + assert(!GV->isConstant() && "Expected a non-constant global"); GV->setConstant(true); + Changed = true; + } // Clean up any obviously simplifiable users now. - CleanupConstantGlobalUsers(GV, GV->getInitializer(), DL, GetTLI); + Changed |= CleanupConstantGlobalUsers(GV, GV->getInitializer(), DL, GetTLI); // If the global is dead now, just nuke it. if (GV->use_empty()) { @@ -2086,7 +2089,7 @@ processInternalGlobal(GlobalVariable *GV, const GlobalStatus &GS, } } - return false; + return Changed; } /// Analyze the specified global variable and optimize it if possible. If we @@ -2221,8 +2224,7 @@ isValidCandidateForColdCC(Function &F, BlockFrequencyInfo &CallerBFI = GetBFI(*CallerFunc); if (!isColdCallSite(CB, CallerBFI)) return false; - auto It = std::find(AllCallsCold.begin(), AllCallsCold.end(), CallerFunc); - if (It == AllCallsCold.end()) + if (!llvm::is_contained(AllCallsCold, CallerFunc)) return false; } return true; diff --git a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp index d0bd0166534a..aa708ee520b1 100644 --- a/llvm/lib/Transforms/IPO/HotColdSplitting.cpp +++ b/llvm/lib/Transforms/IPO/HotColdSplitting.cpp @@ -29,7 +29,6 @@ #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/CFG.h" @@ -68,7 +67,9 @@ #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include +#include #include +#include #define DEBUG_TYPE "hotcoldsplit" @@ -77,14 +78,29 @@ STATISTIC(NumColdRegionsOutlined, "Number of cold regions outlined."); using namespace llvm; -static cl::opt EnableStaticAnalyis("hot-cold-static-analysis", - cl::init(true), cl::Hidden); +static cl::opt EnableStaticAnalysis("hot-cold-static-analysis", + cl::init(true), cl::Hidden); static cl::opt SplittingThreshold("hotcoldsplit-threshold", cl::init(2), cl::Hidden, cl::desc("Base penalty for splitting cold code (as a " "multiple of TCC_Basic)")); +static cl::opt EnableColdSection( + "enable-cold-section", cl::init(false), cl::Hidden, + cl::desc("Enable placement of extracted cold functions" + " into a separate section after hot-cold splitting.")); + +static cl::opt + ColdSectionName("hotcoldsplit-cold-section-name", cl::init("__llvm_cold"), + cl::Hidden, + cl::desc("Name for the section containing cold functions " + "extracted by hot-cold splitting.")); + +static cl::opt MaxParametersForSplit( + "hotcoldsplit-max-params", cl::init(4), cl::Hidden, + cl::desc("Maximum number of parameters for a split function")); + namespace { // Same as blockEndsInUnreachable in CodeGen/BranchFolding.cpp. Do not modify // this function unless you modify the MBB version as well. @@ -221,11 +237,11 @@ bool HotColdSplitting::shouldOutlineFrom(const Function &F) const { } /// Get the benefit score of outlining \p Region. -static int getOutliningBenefit(ArrayRef Region, - TargetTransformInfo &TTI) { +static InstructionCost getOutliningBenefit(ArrayRef Region, + TargetTransformInfo &TTI) { // Sum up the code size costs of non-terminator instructions. Tight coupling // with \ref getOutliningPenalty is needed to model the costs of terminators. - int Benefit = 0; + InstructionCost Benefit = 0; for (BasicBlock *BB : Region) for (Instruction &I : BB->instructionsWithoutDebug()) if (&I != BB->getTerminator()) @@ -246,18 +262,6 @@ static int getOutliningPenalty(ArrayRef Region, if (SplittingThreshold <= 0) return Penalty; - // The typical code size cost for materializing an argument for the outlined - // call. - LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumInputs << " inputs\n"); - const int CostForArgMaterialization = TargetTransformInfo::TCC_Basic; - Penalty += CostForArgMaterialization * NumInputs; - - // The typical code size cost for an output alloca, its associated store, and - // its associated reload. - LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumOutputs << " outputs\n"); - const int CostForRegionOutput = 3 * TargetTransformInfo::TCC_Basic; - Penalty += CostForRegionOutput * NumOutputs; - // Find the number of distinct exit blocks for the region. Use a conservative // check to determine whether control returns from the region. bool NoBlocksReturn = true; @@ -271,13 +275,55 @@ static int getOutliningPenalty(ArrayRef Region, } for (BasicBlock *SuccBB : successors(BB)) { - if (find(Region, SuccBB) == Region.end()) { + if (!is_contained(Region, SuccBB)) { NoBlocksReturn = false; SuccsOutsideRegion.insert(SuccBB); } } } + // Count the number of phis in exit blocks with >= 2 incoming values from the + // outlining region. These phis are split (\ref severSplitPHINodesOfExits), + // and new outputs are created to supply the split phis. CodeExtractor can't + // report these new outputs until extraction begins, but it's important to + // factor the cost of the outputs into the cost calculation. + unsigned NumSplitExitPhis = 0; + for (BasicBlock *ExitBB : SuccsOutsideRegion) { + for (PHINode &PN : ExitBB->phis()) { + // Find all incoming values from the outlining region. + int NumIncomingVals = 0; + for (unsigned i = 0; i < PN.getNumIncomingValues(); ++i) + if (find(Region, PN.getIncomingBlock(i)) != Region.end()) { + ++NumIncomingVals; + if (NumIncomingVals > 1) { + ++NumSplitExitPhis; + break; + } + } + } + } + + // Apply a penalty for calling the split function. Factor in the cost of + // materializing all of the parameters. + int NumOutputsAndSplitPhis = NumOutputs + NumSplitExitPhis; + int NumParams = NumInputs + NumOutputsAndSplitPhis; + if (NumParams > MaxParametersForSplit) { + LLVM_DEBUG(dbgs() << NumInputs << " inputs and " << NumOutputsAndSplitPhis + << " outputs exceeds parameter limit (" + << MaxParametersForSplit << ")\n"); + return std::numeric_limits::max(); + } + const int CostForArgMaterialization = 2 * TargetTransformInfo::TCC_Basic; + LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumParams << " params\n"); + Penalty += CostForArgMaterialization * NumParams; + + // Apply the typical code size cost for an output alloca and its associated + // reload in the caller. Also penalize the associated store in the callee. + LLVM_DEBUG(dbgs() << "Applying penalty for: " << NumOutputsAndSplitPhis + << " outputs/split phis\n"); + const int CostForRegionOutput = 3 * TargetTransformInfo::TCC_Basic; + Penalty += CostForRegionOutput * NumOutputsAndSplitPhis; + // Apply a `noreturn` bonus. if (NoBlocksReturn) { LLVM_DEBUG(dbgs() << "Applying bonus for: " << Region.size() @@ -287,7 +333,7 @@ static int getOutliningPenalty(ArrayRef Region, // Apply a penalty for having more than one successor outside of the region. // This penalty accounts for the switch needed in the caller. - if (!SuccsOutsideRegion.empty()) { + if (SuccsOutsideRegion.size() > 1) { LLVM_DEBUG(dbgs() << "Applying penalty for: " << SuccsOutsideRegion.size() << " non-region successors\n"); Penalty += (SuccsOutsideRegion.size() - 1) * TargetTransformInfo::TCC_Basic; @@ -312,12 +358,12 @@ Function *HotColdSplitting::extractColdRegion( // splitting. SetVector Inputs, Outputs, Sinks; CE.findInputsOutputs(Inputs, Outputs, Sinks); - int OutliningBenefit = getOutliningBenefit(Region, TTI); + InstructionCost OutliningBenefit = getOutliningBenefit(Region, TTI); int OutliningPenalty = getOutliningPenalty(Region, Inputs.size(), Outputs.size()); LLVM_DEBUG(dbgs() << "Split profitability: benefit = " << OutliningBenefit << ", penalty = " << OutliningPenalty << "\n"); - if (OutliningBenefit <= OutliningPenalty) + if (!OutliningBenefit.isValid() || OutliningBenefit <= OutliningPenalty) return nullptr; Function *OrigF = Region[0]->getParent(); @@ -331,8 +377,12 @@ Function *HotColdSplitting::extractColdRegion( } CI->setIsNoInline(); - if (OrigF->hasSection()) - OutF->setSection(OrigF->getSection()); + if (EnableColdSection) + OutF->setSection(ColdSectionName); + else { + if (OrigF->hasSection()) + OutF->setSection(OrigF->getSection()); + } markFunctionCold(*OutF, BFI != nullptr); @@ -575,7 +625,7 @@ bool HotColdSplitting::outlineColdRegions(Function &F, bool HasProfileSummary) { continue; bool Cold = (BFI && PSI->isColdBlock(BB, BFI)) || - (EnableStaticAnalyis && unlikelyExecuted(*BB)); + (EnableStaticAnalysis && unlikelyExecuted(*BB)); if (!Cold) continue; diff --git a/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp b/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp deleted file mode 100644 index 8d05a72d68da..000000000000 --- a/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp +++ /dev/null @@ -1,308 +0,0 @@ -//===-- IPConstantPropagation.cpp - Propagate constants through calls -----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This pass implements an _extremely_ simple interprocedural constant -// propagation pass. It could certainly be improved in many different ways, -// like using a worklist. This pass makes arguments dead, but does not remove -// them. The existing dead argument elimination pass should be run after this -// to clean up the mess. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/ValueTracking.h" -#include "llvm/IR/AbstractCallSite.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/Module.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" -#include "llvm/Transforms/IPO.h" -using namespace llvm; - -#define DEBUG_TYPE "ipconstprop" - -STATISTIC(NumArgumentsProped, "Number of args turned into constants"); -STATISTIC(NumReturnValProped, "Number of return values turned into constants"); - -namespace { - /// IPCP - The interprocedural constant propagation pass - /// - struct IPCP : public ModulePass { - static char ID; // Pass identification, replacement for typeid - IPCP() : ModulePass(ID) { - initializeIPCPPass(*PassRegistry::getPassRegistry()); - } - - bool runOnModule(Module &M) override; - }; -} - -/// PropagateConstantsIntoArguments - Look at all uses of the specified -/// function. If all uses are direct call sites, and all pass a particular -/// constant in for an argument, propagate that constant in as the argument. -/// -static bool PropagateConstantsIntoArguments(Function &F) { - if (F.arg_empty() || F.use_empty()) return false; // No arguments? Early exit. - - // For each argument, keep track of its constant value and whether it is a - // constant or not. The bool is driven to true when found to be non-constant. - SmallVector, 16> ArgumentConstants; - ArgumentConstants.resize(F.arg_size()); - - unsigned NumNonconstant = 0; - for (Use &U : F.uses()) { - User *UR = U.getUser(); - // Ignore blockaddress uses. - if (isa(UR)) continue; - - // If no abstract call site was created we did not understand the use, bail. - AbstractCallSite ACS(&U); - if (!ACS) - return false; - - // Mismatched argument count is undefined behavior. Simply bail out to avoid - // handling of such situations below (avoiding asserts/crashes). - unsigned NumActualArgs = ACS.getNumArgOperands(); - if (F.isVarArg() ? ArgumentConstants.size() > NumActualArgs - : ArgumentConstants.size() != NumActualArgs) - return false; - - // Check out all of the potentially constant arguments. Note that we don't - // inspect varargs here. - Function::arg_iterator Arg = F.arg_begin(); - for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++Arg) { - - // If this argument is known non-constant, ignore it. - if (ArgumentConstants[i].getInt()) - continue; - - Value *V = ACS.getCallArgOperand(i); - Constant *C = dyn_cast_or_null(V); - - // Mismatched argument type is undefined behavior. Simply bail out to avoid - // handling of such situations below (avoiding asserts/crashes). - if (C && Arg->getType() != C->getType()) - return false; - - // We can only propagate thread independent values through callbacks. - // This is different to direct/indirect call sites because for them we - // know the thread executing the caller and callee is the same. For - // callbacks this is not guaranteed, thus a thread dependent value could - // be different for the caller and callee, making it invalid to propagate. - if (C && ACS.isCallbackCall() && C->isThreadDependent()) { - // Argument became non-constant. If all arguments are non-constant now, - // give up on this function. - if (++NumNonconstant == ArgumentConstants.size()) - return false; - - ArgumentConstants[i].setInt(true); - continue; - } - - if (C && ArgumentConstants[i].getPointer() == nullptr) { - ArgumentConstants[i].setPointer(C); // First constant seen. - } else if (C && ArgumentConstants[i].getPointer() == C) { - // Still the constant value we think it is. - } else if (V == &*Arg) { - // Ignore recursive calls passing argument down. - } else { - // Argument became non-constant. If all arguments are non-constant now, - // give up on this function. - if (++NumNonconstant == ArgumentConstants.size()) - return false; - ArgumentConstants[i].setInt(true); - } - } - } - - // If we got to this point, there is a constant argument! - assert(NumNonconstant != ArgumentConstants.size()); - bool MadeChange = false; - Function::arg_iterator AI = F.arg_begin(); - for (unsigned i = 0, e = ArgumentConstants.size(); i != e; ++i, ++AI) { - // Do we have a constant argument? - if (ArgumentConstants[i].getInt() || AI->use_empty() || - (AI->hasByValAttr() && !F.onlyReadsMemory())) - continue; - - Value *V = ArgumentConstants[i].getPointer(); - if (!V) V = UndefValue::get(AI->getType()); - AI->replaceAllUsesWith(V); - ++NumArgumentsProped; - MadeChange = true; - } - return MadeChange; -} - - -// Check to see if this function returns one or more constants. If so, replace -// all callers that use those return values with the constant value. This will -// leave in the actual return values and instructions, but deadargelim will -// clean that up. -// -// Additionally if a function always returns one of its arguments directly, -// callers will be updated to use the value they pass in directly instead of -// using the return value. -static bool PropagateConstantReturn(Function &F) { - if (F.getReturnType()->isVoidTy()) - return false; // No return value. - - // We can infer and propagate the return value only when we know that the - // definition we'll get at link time is *exactly* the definition we see now. - // For more details, see GlobalValue::mayBeDerefined. - if (!F.isDefinitionExact()) - return false; - - // Don't touch naked functions. The may contain asm returning - // value we don't see, so we may end up interprocedurally propagating - // the return value incorrectly. - if (F.hasFnAttribute(Attribute::Naked)) - return false; - - // Check to see if this function returns a constant. - SmallVector RetVals; - StructType *STy = dyn_cast(F.getReturnType()); - if (STy) - for (unsigned i = 0, e = STy->getNumElements(); i < e; ++i) - RetVals.push_back(UndefValue::get(STy->getElementType(i))); - else - RetVals.push_back(UndefValue::get(F.getReturnType())); - - unsigned NumNonConstant = 0; - for (BasicBlock &BB : F) - if (ReturnInst *RI = dyn_cast(BB.getTerminator())) { - for (unsigned i = 0, e = RetVals.size(); i != e; ++i) { - // Already found conflicting return values? - Value *RV = RetVals[i]; - if (!RV) - continue; - - // Find the returned value - Value *V; - if (!STy) - V = RI->getOperand(0); - else - V = FindInsertedValue(RI->getOperand(0), i); - - if (V) { - // Ignore undefs, we can change them into anything - if (isa(V)) - continue; - - // Try to see if all the rets return the same constant or argument. - if (isa(V) || isa(V)) { - if (isa(RV)) { - // No value found yet? Try the current one. - RetVals[i] = V; - continue; - } - // Returning the same value? Good. - if (RV == V) - continue; - } - } - // Different or no known return value? Don't propagate this return - // value. - RetVals[i] = nullptr; - // All values non-constant? Stop looking. - if (++NumNonConstant == RetVals.size()) - return false; - } - } - - // If we got here, the function returns at least one constant value. Loop - // over all users, replacing any uses of the return value with the returned - // constant. - bool MadeChange = false; - for (Use &U : F.uses()) { - CallBase *CB = dyn_cast(U.getUser()); - - // Not a call instruction or a call instruction that's not calling F - // directly? - if (!CB || !CB->isCallee(&U)) - continue; - - // Call result not used? - if (CB->use_empty()) - continue; - - MadeChange = true; - - if (!STy) { - Value* New = RetVals[0]; - if (Argument *A = dyn_cast(New)) - // Was an argument returned? Then find the corresponding argument in - // the call instruction and use that. - New = CB->getArgOperand(A->getArgNo()); - CB->replaceAllUsesWith(New); - continue; - } - - for (auto I = CB->user_begin(), E = CB->user_end(); I != E;) { - Instruction *Ins = cast(*I); - - // Increment now, so we can remove the use - ++I; - - // Find the index of the retval to replace with - int index = -1; - if (ExtractValueInst *EV = dyn_cast(Ins)) - if (EV->getNumIndices() == 1) - index = *EV->idx_begin(); - - // If this use uses a specific return value, and we have a replacement, - // replace it. - if (index != -1) { - Value *New = RetVals[index]; - if (New) { - if (Argument *A = dyn_cast(New)) - // Was an argument returned? Then find the corresponding argument in - // the call instruction and use that. - New = CB->getArgOperand(A->getArgNo()); - Ins->replaceAllUsesWith(New); - Ins->eraseFromParent(); - } - } - } - } - - if (MadeChange) ++NumReturnValProped; - return MadeChange; -} - -char IPCP::ID = 0; -INITIALIZE_PASS(IPCP, "ipconstprop", - "Interprocedural constant propagation", false, false) - -ModulePass *llvm::createIPConstantPropagationPass() { return new IPCP(); } - -bool IPCP::runOnModule(Module &M) { - if (skipModule(M)) - return false; - - bool Changed = false; - bool LocalChange = true; - - // FIXME: instead of using smart algorithms, we just iterate until we stop - // making changes. - while (LocalChange) { - LocalChange = false; - for (Function &F : M) - if (!F.isDeclaration()) { - // Delete any klingons. - F.removeDeadConstantUsers(); - if (F.hasLocalLinkage()) - LocalChange |= PropagateConstantsIntoArguments(F); - Changed |= PropagateConstantReturn(F); - } - Changed |= LocalChange; - } - return Changed; -} diff --git a/llvm/lib/Transforms/IPO/IPO.cpp b/llvm/lib/Transforms/IPO/IPO.cpp index d37b9236380d..f4c12dd7f4cd 100644 --- a/llvm/lib/Transforms/IPO/IPO.cpp +++ b/llvm/lib/Transforms/IPO/IPO.cpp @@ -25,6 +25,7 @@ using namespace llvm; void llvm::initializeIPO(PassRegistry &Registry) { initializeOpenMPOptLegacyPassPass(Registry); initializeArgPromotionPass(Registry); + initializeAnnotation2MetadataLegacyPass(Registry); initializeCalledValuePropagationLegacyPassPass(Registry); initializeConstantMergeLegacyPassPass(Registry); initializeCrossDSOCFIPass(Registry); @@ -35,13 +36,13 @@ void llvm::initializeIPO(PassRegistry &Registry) { initializeGlobalOptLegacyPassPass(Registry); initializeGlobalSplitPass(Registry); initializeHotColdSplittingLegacyPassPass(Registry); - initializeIPCPPass(Registry); + initializeIROutlinerLegacyPassPass(Registry); initializeAlwaysInlinerLegacyPassPass(Registry); initializeSimpleInlinerPass(Registry); initializeInferFunctionAttrsLegacyPassPass(Registry); initializeInternalizeLegacyPassPass(Registry); - initializeLoopExtractorPass(Registry); - initializeBlockExtractorPass(Registry); + initializeLoopExtractorLegacyPassPass(Registry); + initializeBlockExtractorLegacyPassPass(Registry); initializeSingleLoopExtractorPass(Registry); initializeLowerTypeTestsPass(Registry); initializeMergeFunctionsLegacyPassPass(Registry); @@ -104,10 +105,6 @@ void LLVMAddGlobalOptimizerPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createGlobalOptimizerPass()); } -void LLVMAddIPConstantPropagationPass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createIPConstantPropagationPass()); -} - void LLVMAddPruneEHPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createPruneEHPass()); } diff --git a/llvm/lib/Transforms/IPO/IROutliner.cpp b/llvm/lib/Transforms/IPO/IROutliner.cpp new file mode 100644 index 000000000000..4b6a4f3d8fc4 --- /dev/null +++ b/llvm/lib/Transforms/IPO/IROutliner.cpp @@ -0,0 +1,1764 @@ +//===- IROutliner.cpp -- Outline Similar Regions ----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +// Implementation for the IROutliner which is used by the IROutliner Pass. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/IROutliner.h" +#include "llvm/Analysis/IRSimilarityIdentifier.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/Attributes.h" +#include "llvm/IR/PassManager.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/IPO.h" +#include +#include +#include + +#define DEBUG_TYPE "iroutliner" + +using namespace llvm; +using namespace IRSimilarity; + +// Set to true if the user wants the ir outliner to run on linkonceodr linkage +// functions. This is false by default because the linker can dedupe linkonceodr +// functions. Since the outliner is confined to a single module (modulo LTO), +// this is off by default. It should, however, be the default behavior in +// LTO. +static cl::opt EnableLinkOnceODRIROutlining( + "enable-linkonceodr-ir-outlining", cl::Hidden, + cl::desc("Enable the IR outliner on linkonceodr functions"), + cl::init(false)); + +// This is a debug option to test small pieces of code to ensure that outlining +// works correctly. +static cl::opt NoCostModel( + "ir-outlining-no-cost", cl::init(false), cl::ReallyHidden, + cl::desc("Debug option to outline greedily, without restriction that " + "calculated benefit outweighs cost")); + +/// The OutlinableGroup holds all the overarching information for outlining +/// a set of regions that are structurally similar to one another, such as the +/// types of the overall function, the output blocks, the sets of stores needed +/// and a list of the different regions. This information is used in the +/// deduplication of extracted regions with the same structure. +struct OutlinableGroup { + /// The sections that could be outlined + std::vector Regions; + + /// The argument types for the function created as the overall function to + /// replace the extracted function for each region. + std::vector ArgumentTypes; + /// The FunctionType for the overall function. + FunctionType *OutlinedFunctionType = nullptr; + /// The Function for the collective overall function. + Function *OutlinedFunction = nullptr; + + /// Flag for whether we should not consider this group of OutlinableRegions + /// for extraction. + bool IgnoreGroup = false; + + /// The return block for the overall function. + BasicBlock *EndBB = nullptr; + + /// A set containing the different GVN store sets needed. Each array contains + /// a sorted list of the different values that need to be stored into output + /// registers. + DenseSet> OutputGVNCombinations; + + /// Flag for whether the \ref ArgumentTypes have been defined after the + /// extraction of the first region. + bool InputTypesSet = false; + + /// The number of input values in \ref ArgumentTypes. Anything after this + /// index in ArgumentTypes is an output argument. + unsigned NumAggregateInputs = 0; + + /// The number of instructions that will be outlined by extracting \ref + /// Regions. + InstructionCost Benefit = 0; + /// The number of added instructions needed for the outlining of the \ref + /// Regions. + InstructionCost Cost = 0; + + /// The argument that needs to be marked with the swifterr attribute. If not + /// needed, there is no value. + Optional SwiftErrorArgument; + + /// For the \ref Regions, we look at every Value. If it is a constant, + /// we check whether it is the same in Region. + /// + /// \param [in,out] NotSame contains the global value numbers where the + /// constant is not always the same, and must be passed in as an argument. + void findSameConstants(DenseSet &NotSame); + + /// For the regions, look at each set of GVN stores needed and account for + /// each combination. Add an argument to the argument types if there is + /// more than one combination. + /// + /// \param [in] M - The module we are outlining from. + void collectGVNStoreSets(Module &M); +}; + +/// Move the contents of \p SourceBB to before the last instruction of \p +/// TargetBB. +/// \param SourceBB - the BasicBlock to pull Instructions from. +/// \param TargetBB - the BasicBlock to put Instruction into. +static void moveBBContents(BasicBlock &SourceBB, BasicBlock &TargetBB) { + BasicBlock::iterator BBCurr, BBEnd, BBNext; + for (BBCurr = SourceBB.begin(), BBEnd = SourceBB.end(); BBCurr != BBEnd; + BBCurr = BBNext) { + BBNext = std::next(BBCurr); + BBCurr->moveBefore(TargetBB, TargetBB.end()); + } +} + +void OutlinableRegion::splitCandidate() { + assert(!CandidateSplit && "Candidate already split!"); + + Instruction *StartInst = (*Candidate->begin()).Inst; + Instruction *EndInst = (*Candidate->end()).Inst; + assert(StartInst && EndInst && "Expected a start and end instruction?"); + StartBB = StartInst->getParent(); + PrevBB = StartBB; + + // The basic block gets split like so: + // block: block: + // inst1 inst1 + // inst2 inst2 + // region1 br block_to_outline + // region2 block_to_outline: + // region3 -> region1 + // region4 region2 + // inst3 region3 + // inst4 region4 + // br block_after_outline + // block_after_outline: + // inst3 + // inst4 + + std::string OriginalName = PrevBB->getName().str(); + + StartBB = PrevBB->splitBasicBlock(StartInst, OriginalName + "_to_outline"); + + // This is the case for the inner block since we do not have to include + // multiple blocks. + EndBB = StartBB; + FollowBB = EndBB->splitBasicBlock(EndInst, OriginalName + "_after_outline"); + + CandidateSplit = true; +} + +void OutlinableRegion::reattachCandidate() { + assert(CandidateSplit && "Candidate is not split!"); + + // The basic block gets reattached like so: + // block: block: + // inst1 inst1 + // inst2 inst2 + // br block_to_outline region1 + // block_to_outline: -> region2 + // region1 region3 + // region2 region4 + // region3 inst3 + // region4 inst4 + // br block_after_outline + // block_after_outline: + // inst3 + // inst4 + assert(StartBB != nullptr && "StartBB for Candidate is not defined!"); + assert(FollowBB != nullptr && "StartBB for Candidate is not defined!"); + + // StartBB should only have one predecessor since we put an unconditional + // branch at the end of PrevBB when we split the BasicBlock. + PrevBB = StartBB->getSinglePredecessor(); + assert(PrevBB != nullptr && + "No Predecessor for the region start basic block!"); + + assert(PrevBB->getTerminator() && "Terminator removed from PrevBB!"); + assert(EndBB->getTerminator() && "Terminator removed from EndBB!"); + PrevBB->getTerminator()->eraseFromParent(); + EndBB->getTerminator()->eraseFromParent(); + + moveBBContents(*StartBB, *PrevBB); + + BasicBlock *PlacementBB = PrevBB; + if (StartBB != EndBB) + PlacementBB = EndBB; + moveBBContents(*FollowBB, *PlacementBB); + + PrevBB->replaceSuccessorsPhiUsesWith(StartBB, PrevBB); + PrevBB->replaceSuccessorsPhiUsesWith(FollowBB, PlacementBB); + StartBB->eraseFromParent(); + FollowBB->eraseFromParent(); + + // Make sure to save changes back to the StartBB. + StartBB = PrevBB; + EndBB = nullptr; + PrevBB = nullptr; + FollowBB = nullptr; + + CandidateSplit = false; +} + +/// Find whether \p V matches the Constants previously found for the \p GVN. +/// +/// \param V - The value to check for consistency. +/// \param GVN - The global value number assigned to \p V. +/// \param GVNToConstant - The mapping of global value number to Constants. +/// \returns true if the Value matches the Constant mapped to by V and false if +/// it \p V is a Constant but does not match. +/// \returns None if \p V is not a Constant. +static Optional +constantMatches(Value *V, unsigned GVN, + DenseMap &GVNToConstant) { + // See if we have a constants + Constant *CST = dyn_cast(V); + if (!CST) + return None; + + // Holds a mapping from a global value number to a Constant. + DenseMap::iterator GVNToConstantIt; + bool Inserted; + + + // If we have a constant, try to make a new entry in the GVNToConstant. + std::tie(GVNToConstantIt, Inserted) = + GVNToConstant.insert(std::make_pair(GVN, CST)); + // If it was found and is not equal, it is not the same. We do not + // handle this case yet, and exit early. + if (Inserted || (GVNToConstantIt->second == CST)) + return true; + + return false; +} + +InstructionCost OutlinableRegion::getBenefit(TargetTransformInfo &TTI) { + InstructionCost Benefit = 0; + + // Estimate the benefit of outlining a specific sections of the program. We + // delegate mostly this task to the TargetTransformInfo so that if the target + // has specific changes, we can have a more accurate estimate. + + // However, getInstructionCost delegates the code size calculation for + // arithmetic instructions to getArithmeticInstrCost in + // include/Analysis/TargetTransformImpl.h, where it always estimates that the + // code size for a division and remainder instruction to be equal to 4, and + // everything else to 1. This is not an accurate representation of the + // division instruction for targets that have a native division instruction. + // To be overly conservative, we only add 1 to the number of instructions for + // each division instruction. + for (Instruction &I : *StartBB) { + switch (I.getOpcode()) { + case Instruction::FDiv: + case Instruction::FRem: + case Instruction::SDiv: + case Instruction::SRem: + case Instruction::UDiv: + case Instruction::URem: + Benefit += 1; + break; + default: + Benefit += TTI.getInstructionCost(&I, TargetTransformInfo::TCK_CodeSize); + break; + } + } + + return Benefit; +} + +/// Find whether \p Region matches the global value numbering to Constant +/// mapping found so far. +/// +/// \param Region - The OutlinableRegion we are checking for constants +/// \param GVNToConstant - The mapping of global value number to Constants. +/// \param NotSame - The set of global value numbers that do not have the same +/// constant in each region. +/// \returns true if all Constants are the same in every use of a Constant in \p +/// Region and false if not +static bool +collectRegionsConstants(OutlinableRegion &Region, + DenseMap &GVNToConstant, + DenseSet &NotSame) { + bool ConstantsTheSame = true; + + IRSimilarityCandidate &C = *Region.Candidate; + for (IRInstructionData &ID : C) { + + // Iterate over the operands in an instruction. If the global value number, + // assigned by the IRSimilarityCandidate, has been seen before, we check if + // the the number has been found to be not the same value in each instance. + for (Value *V : ID.OperVals) { + Optional GVNOpt = C.getGVN(V); + assert(GVNOpt.hasValue() && "Expected a GVN for operand?"); + unsigned GVN = GVNOpt.getValue(); + + // Check if this global value has been found to not be the same already. + if (NotSame.contains(GVN)) { + if (isa(V)) + ConstantsTheSame = false; + continue; + } + + // If it has been the same so far, we check the value for if the + // associated Constant value match the previous instances of the same + // global value number. If the global value does not map to a Constant, + // it is considered to not be the same value. + Optional ConstantMatches = constantMatches(V, GVN, GVNToConstant); + if (ConstantMatches.hasValue()) { + if (ConstantMatches.getValue()) + continue; + else + ConstantsTheSame = false; + } + + // While this value is a register, it might not have been previously, + // make sure we don't already have a constant mapped to this global value + // number. + if (GVNToConstant.find(GVN) != GVNToConstant.end()) + ConstantsTheSame = false; + + NotSame.insert(GVN); + } + } + + return ConstantsTheSame; +} + +void OutlinableGroup::findSameConstants(DenseSet &NotSame) { + DenseMap GVNToConstant; + + for (OutlinableRegion *Region : Regions) + collectRegionsConstants(*Region, GVNToConstant, NotSame); +} + +void OutlinableGroup::collectGVNStoreSets(Module &M) { + for (OutlinableRegion *OS : Regions) + OutputGVNCombinations.insert(OS->GVNStores); + + // We are adding an extracted argument to decide between which output path + // to use in the basic block. It is used in a switch statement and only + // needs to be an integer. + if (OutputGVNCombinations.size() > 1) + ArgumentTypes.push_back(Type::getInt32Ty(M.getContext())); +} + +Function *IROutliner::createFunction(Module &M, OutlinableGroup &Group, + unsigned FunctionNameSuffix) { + assert(!Group.OutlinedFunction && "Function is already defined!"); + + Group.OutlinedFunctionType = FunctionType::get( + Type::getVoidTy(M.getContext()), Group.ArgumentTypes, false); + + // These functions will only be called from within the same module, so + // we can set an internal linkage. + Group.OutlinedFunction = Function::Create( + Group.OutlinedFunctionType, GlobalValue::InternalLinkage, + "outlined_ir_func_" + std::to_string(FunctionNameSuffix), M); + + // Transfer the swifterr attribute to the correct function parameter. + if (Group.SwiftErrorArgument.hasValue()) + Group.OutlinedFunction->addParamAttr(Group.SwiftErrorArgument.getValue(), + Attribute::SwiftError); + + Group.OutlinedFunction->addFnAttr(Attribute::OptimizeForSize); + Group.OutlinedFunction->addFnAttr(Attribute::MinSize); + + return Group.OutlinedFunction; +} + +/// Move each BasicBlock in \p Old to \p New. +/// +/// \param [in] Old - the function to move the basic blocks from. +/// \param [in] New - The function to move the basic blocks to. +/// \returns the first return block for the function in New. +static BasicBlock *moveFunctionData(Function &Old, Function &New) { + Function::iterator CurrBB, NextBB, FinalBB; + BasicBlock *NewEnd = nullptr; + std::vector DebugInsts; + for (CurrBB = Old.begin(), FinalBB = Old.end(); CurrBB != FinalBB; + CurrBB = NextBB) { + NextBB = std::next(CurrBB); + CurrBB->removeFromParent(); + CurrBB->insertInto(&New); + Instruction *I = CurrBB->getTerminator(); + if (isa(I)) + NewEnd = &(*CurrBB); + } + + assert(NewEnd && "No return instruction for new function?"); + return NewEnd; +} + +/// Find the the constants that will need to be lifted into arguments +/// as they are not the same in each instance of the region. +/// +/// \param [in] C - The IRSimilarityCandidate containing the region we are +/// analyzing. +/// \param [in] NotSame - The set of global value numbers that do not have a +/// single Constant across all OutlinableRegions similar to \p C. +/// \param [out] Inputs - The list containing the global value numbers of the +/// arguments needed for the region of code. +static void findConstants(IRSimilarityCandidate &C, DenseSet &NotSame, + std::vector &Inputs) { + DenseSet Seen; + // Iterate over the instructions, and find what constants will need to be + // extracted into arguments. + for (IRInstructionDataList::iterator IDIt = C.begin(), EndIDIt = C.end(); + IDIt != EndIDIt; IDIt++) { + for (Value *V : (*IDIt).OperVals) { + // Since these are stored before any outlining, they will be in the + // global value numbering. + unsigned GVN = C.getGVN(V).getValue(); + if (isa(V)) + if (NotSame.contains(GVN) && !Seen.contains(GVN)) { + Inputs.push_back(GVN); + Seen.insert(GVN); + } + } + } +} + +/// Find the GVN for the inputs that have been found by the CodeExtractor. +/// +/// \param [in] C - The IRSimilarityCandidate containing the region we are +/// analyzing. +/// \param [in] CurrentInputs - The set of inputs found by the +/// CodeExtractor. +/// \param [out] EndInputNumbers - The global value numbers for the extracted +/// arguments. +/// \param [in] OutputMappings - The mapping of values that have been replaced +/// by a new output value. +/// \param [out] EndInputs - The global value numbers for the extracted +/// arguments. +static void mapInputsToGVNs(IRSimilarityCandidate &C, + SetVector &CurrentInputs, + const DenseMap &OutputMappings, + std::vector &EndInputNumbers) { + // Get the Global Value Number for each input. We check if the Value has been + // replaced by a different value at output, and use the original value before + // replacement. + for (Value *Input : CurrentInputs) { + assert(Input && "Have a nullptr as an input"); + if (OutputMappings.find(Input) != OutputMappings.end()) + Input = OutputMappings.find(Input)->second; + assert(C.getGVN(Input).hasValue() && + "Could not find a numbering for the given input"); + EndInputNumbers.push_back(C.getGVN(Input).getValue()); + } +} + +/// Find the original value for the \p ArgInput values if any one of them was +/// replaced during a previous extraction. +/// +/// \param [in] ArgInputs - The inputs to be extracted by the code extractor. +/// \param [in] OutputMappings - The mapping of values that have been replaced +/// by a new output value. +/// \param [out] RemappedArgInputs - The remapped values according to +/// \p OutputMappings that will be extracted. +static void +remapExtractedInputs(const ArrayRef ArgInputs, + const DenseMap &OutputMappings, + SetVector &RemappedArgInputs) { + // Get the global value number for each input that will be extracted as an + // argument by the code extractor, remapping if needed for reloaded values. + for (Value *Input : ArgInputs) { + if (OutputMappings.find(Input) != OutputMappings.end()) + Input = OutputMappings.find(Input)->second; + RemappedArgInputs.insert(Input); + } +} + +/// Find the input GVNs and the output values for a region of Instructions. +/// Using the code extractor, we collect the inputs to the extracted function. +/// +/// The \p Region can be identified as needing to be ignored in this function. +/// It should be checked whether it should be ignored after a call to this +/// function. +/// +/// \param [in,out] Region - The region of code to be analyzed. +/// \param [out] InputGVNs - The global value numbers for the extracted +/// arguments. +/// \param [in] NotSame - The global value numbers in the region that do not +/// have the same constant value in the regions structurally similar to +/// \p Region. +/// \param [in] OutputMappings - The mapping of values that have been replaced +/// by a new output value after extraction. +/// \param [out] ArgInputs - The values of the inputs to the extracted function. +/// \param [out] Outputs - The set of values extracted by the CodeExtractor +/// as outputs. +static void getCodeExtractorArguments( + OutlinableRegion &Region, std::vector &InputGVNs, + DenseSet &NotSame, DenseMap &OutputMappings, + SetVector &ArgInputs, SetVector &Outputs) { + IRSimilarityCandidate &C = *Region.Candidate; + + // OverallInputs are the inputs to the region found by the CodeExtractor, + // SinkCands and HoistCands are used by the CodeExtractor to find sunken + // allocas of values whose lifetimes are contained completely within the + // outlined region. PremappedInputs are the arguments found by the + // CodeExtractor, removing conditions such as sunken allocas, but that + // may need to be remapped due to the extracted output values replacing + // the original values. We use DummyOutputs for this first run of finding + // inputs and outputs since the outputs could change during findAllocas, + // the correct set of extracted outputs will be in the final Outputs ValueSet. + SetVector OverallInputs, PremappedInputs, SinkCands, HoistCands, + DummyOutputs; + + // Use the code extractor to get the inputs and outputs, without sunken + // allocas or removing llvm.assumes. + CodeExtractor *CE = Region.CE; + CE->findInputsOutputs(OverallInputs, DummyOutputs, SinkCands); + assert(Region.StartBB && "Region must have a start BasicBlock!"); + Function *OrigF = Region.StartBB->getParent(); + CodeExtractorAnalysisCache CEAC(*OrigF); + BasicBlock *Dummy = nullptr; + + // The region may be ineligible due to VarArgs in the parent function. In this + // case we ignore the region. + if (!CE->isEligible()) { + Region.IgnoreRegion = true; + return; + } + + // Find if any values are going to be sunk into the function when extracted + CE->findAllocas(CEAC, SinkCands, HoistCands, Dummy); + CE->findInputsOutputs(PremappedInputs, Outputs, SinkCands); + + // TODO: Support regions with sunken allocas: values whose lifetimes are + // contained completely within the outlined region. These are not guaranteed + // to be the same in every region, so we must elevate them all to arguments + // when they appear. If these values are not equal, it means there is some + // Input in OverallInputs that was removed for ArgInputs. + if (OverallInputs.size() != PremappedInputs.size()) { + Region.IgnoreRegion = true; + return; + } + + findConstants(C, NotSame, InputGVNs); + + mapInputsToGVNs(C, OverallInputs, OutputMappings, InputGVNs); + + remapExtractedInputs(PremappedInputs.getArrayRef(), OutputMappings, + ArgInputs); + + // Sort the GVNs, since we now have constants included in the \ref InputGVNs + // we need to make sure they are in a deterministic order. + stable_sort(InputGVNs); +} + +/// Look over the inputs and map each input argument to an argument in the +/// overall function for the OutlinableRegions. This creates a way to replace +/// the arguments of the extracted function with the arguments of the new +/// overall function. +/// +/// \param [in,out] Region - The region of code to be analyzed. +/// \param [in] InputsGVNs - The global value numbering of the input values +/// collected. +/// \param [in] ArgInputs - The values of the arguments to the extracted +/// function. +static void +findExtractedInputToOverallInputMapping(OutlinableRegion &Region, + std::vector &InputGVNs, + SetVector &ArgInputs) { + + IRSimilarityCandidate &C = *Region.Candidate; + OutlinableGroup &Group = *Region.Parent; + + // This counts the argument number in the overall function. + unsigned TypeIndex = 0; + + // This counts the argument number in the extracted function. + unsigned OriginalIndex = 0; + + // Find the mapping of the extracted arguments to the arguments for the + // overall function. Since there may be extra arguments in the overall + // function to account for the extracted constants, we have two different + // counters as we find extracted arguments, and as we come across overall + // arguments. + for (unsigned InputVal : InputGVNs) { + Optional InputOpt = C.fromGVN(InputVal); + assert(InputOpt.hasValue() && "Global value number not found?"); + Value *Input = InputOpt.getValue(); + + if (!Group.InputTypesSet) { + Group.ArgumentTypes.push_back(Input->getType()); + // If the input value has a swifterr attribute, make sure to mark the + // argument in the overall function. + if (Input->isSwiftError()) { + assert( + !Group.SwiftErrorArgument.hasValue() && + "Argument already marked with swifterr for this OutlinableGroup!"); + Group.SwiftErrorArgument = TypeIndex; + } + } + + // Check if we have a constant. If we do add it to the overall argument + // number to Constant map for the region, and continue to the next input. + if (Constant *CST = dyn_cast(Input)) { + Region.AggArgToConstant.insert(std::make_pair(TypeIndex, CST)); + TypeIndex++; + continue; + } + + // It is not a constant, we create the mapping from extracted argument list + // to the overall argument list. + assert(ArgInputs.count(Input) && "Input cannot be found!"); + + Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, TypeIndex)); + Region.AggArgToExtracted.insert(std::make_pair(TypeIndex, OriginalIndex)); + OriginalIndex++; + TypeIndex++; + } + + // If the function type definitions for the OutlinableGroup holding the region + // have not been set, set the length of the inputs here. We should have the + // same inputs for all of the different regions contained in the + // OutlinableGroup since they are all structurally similar to one another. + if (!Group.InputTypesSet) { + Group.NumAggregateInputs = TypeIndex; + Group.InputTypesSet = true; + } + + Region.NumExtractedInputs = OriginalIndex; +} + +/// Create a mapping of the output arguments for the \p Region to the output +/// arguments of the overall outlined function. +/// +/// \param [in,out] Region - The region of code to be analyzed. +/// \param [in] Outputs - The values found by the code extractor. +static void +findExtractedOutputToOverallOutputMapping(OutlinableRegion &Region, + ArrayRef Outputs) { + OutlinableGroup &Group = *Region.Parent; + IRSimilarityCandidate &C = *Region.Candidate; + + // This counts the argument number in the extracted function. + unsigned OriginalIndex = Region.NumExtractedInputs; + + // This counts the argument number in the overall function. + unsigned TypeIndex = Group.NumAggregateInputs; + bool TypeFound; + DenseSet AggArgsUsed; + + // Iterate over the output types and identify if there is an aggregate pointer + // type whose base type matches the current output type. If there is, we mark + // that we will use this output register for this value. If not we add another + // type to the overall argument type list. We also store the GVNs used for + // stores to identify which values will need to be moved into an special + // block that holds the stores to the output registers. + for (Value *Output : Outputs) { + TypeFound = false; + // We can do this since it is a result value, and will have a number + // that is necessarily the same. BUT if in the future, the instructions + // do not have to be in same order, but are functionally the same, we will + // have to use a different scheme, as one-to-one correspondence is not + // guaranteed. + unsigned GlobalValue = C.getGVN(Output).getValue(); + unsigned ArgumentSize = Group.ArgumentTypes.size(); + + for (unsigned Jdx = TypeIndex; Jdx < ArgumentSize; Jdx++) { + if (Group.ArgumentTypes[Jdx] != PointerType::getUnqual(Output->getType())) + continue; + + if (AggArgsUsed.contains(Jdx)) + continue; + + TypeFound = true; + AggArgsUsed.insert(Jdx); + Region.ExtractedArgToAgg.insert(std::make_pair(OriginalIndex, Jdx)); + Region.AggArgToExtracted.insert(std::make_pair(Jdx, OriginalIndex)); + Region.GVNStores.push_back(GlobalValue); + break; + } + + // We were unable to find an unused type in the output type set that matches + // the output, so we add a pointer type to the argument types of the overall + // function to handle this output and create a mapping to it. + if (!TypeFound) { + Group.ArgumentTypes.push_back(PointerType::getUnqual(Output->getType())); + AggArgsUsed.insert(Group.ArgumentTypes.size() - 1); + Region.ExtractedArgToAgg.insert( + std::make_pair(OriginalIndex, Group.ArgumentTypes.size() - 1)); + Region.AggArgToExtracted.insert( + std::make_pair(Group.ArgumentTypes.size() - 1, OriginalIndex)); + Region.GVNStores.push_back(GlobalValue); + } + + stable_sort(Region.GVNStores); + OriginalIndex++; + TypeIndex++; + } +} + +void IROutliner::findAddInputsOutputs(Module &M, OutlinableRegion &Region, + DenseSet &NotSame) { + std::vector Inputs; + SetVector ArgInputs, Outputs; + + getCodeExtractorArguments(Region, Inputs, NotSame, OutputMappings, ArgInputs, + Outputs); + + if (Region.IgnoreRegion) + return; + + // Map the inputs found by the CodeExtractor to the arguments found for + // the overall function. + findExtractedInputToOverallInputMapping(Region, Inputs, ArgInputs); + + // Map the outputs found by the CodeExtractor to the arguments found for + // the overall function. + findExtractedOutputToOverallOutputMapping(Region, Outputs.getArrayRef()); +} + +/// Replace the extracted function in the Region with a call to the overall +/// function constructed from the deduplicated similar regions, replacing and +/// remapping the values passed to the extracted function as arguments to the +/// new arguments of the overall function. +/// +/// \param [in] M - The module to outline from. +/// \param [in] Region - The regions of extracted code to be replaced with a new +/// function. +/// \returns a call instruction with the replaced function. +CallInst *replaceCalledFunction(Module &M, OutlinableRegion &Region) { + std::vector NewCallArgs; + DenseMap::iterator ArgPair; + + OutlinableGroup &Group = *Region.Parent; + CallInst *Call = Region.Call; + assert(Call && "Call to replace is nullptr?"); + Function *AggFunc = Group.OutlinedFunction; + assert(AggFunc && "Function to replace with is nullptr?"); + + // If the arguments are the same size, there are not values that need to be + // made argument, or different output registers to handle. We can simply + // replace the called function in this case. + if (AggFunc->arg_size() == Call->arg_size()) { + LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to " + << *AggFunc << " with same number of arguments\n"); + Call->setCalledFunction(AggFunc); + return Call; + } + + // We have a different number of arguments than the new function, so + // we need to use our previously mappings off extracted argument to overall + // function argument, and constants to overall function argument to create the + // new argument list. + for (unsigned AggArgIdx = 0; AggArgIdx < AggFunc->arg_size(); AggArgIdx++) { + + if (AggArgIdx == AggFunc->arg_size() - 1 && + Group.OutputGVNCombinations.size() > 1) { + // If we are on the last argument, and we need to differentiate between + // output blocks, add an integer to the argument list to determine + // what block to take + LLVM_DEBUG(dbgs() << "Set switch block argument to " + << Region.OutputBlockNum << "\n"); + NewCallArgs.push_back(ConstantInt::get(Type::getInt32Ty(M.getContext()), + Region.OutputBlockNum)); + continue; + } + + ArgPair = Region.AggArgToExtracted.find(AggArgIdx); + if (ArgPair != Region.AggArgToExtracted.end()) { + Value *ArgumentValue = Call->getArgOperand(ArgPair->second); + // If we found the mapping from the extracted function to the overall + // function, we simply add it to the argument list. We use the same + // value, it just needs to honor the new order of arguments. + LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value " + << *ArgumentValue << "\n"); + NewCallArgs.push_back(ArgumentValue); + continue; + } + + // If it is a constant, we simply add it to the argument list as a value. + if (Region.AggArgToConstant.find(AggArgIdx) != + Region.AggArgToConstant.end()) { + Constant *CST = Region.AggArgToConstant.find(AggArgIdx)->second; + LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to value " + << *CST << "\n"); + NewCallArgs.push_back(CST); + continue; + } + + // Add a nullptr value if the argument is not found in the extracted + // function. If we cannot find a value, it means it is not in use + // for the region, so we should not pass anything to it. + LLVM_DEBUG(dbgs() << "Setting argument " << AggArgIdx << " to nullptr\n"); + NewCallArgs.push_back(ConstantPointerNull::get( + static_cast(AggFunc->getArg(AggArgIdx)->getType()))); + } + + LLVM_DEBUG(dbgs() << "Replace call to " << *Call << " with call to " + << *AggFunc << " with new set of arguments\n"); + // Create the new call instruction and erase the old one. + Call = CallInst::Create(AggFunc->getFunctionType(), AggFunc, NewCallArgs, "", + Call); + + // It is possible that the call to the outlined function is either the first + // instruction is in the new block, the last instruction, or both. If either + // of these is the case, we need to make sure that we replace the instruction + // in the IRInstructionData struct with the new call. + CallInst *OldCall = Region.Call; + if (Region.NewFront->Inst == OldCall) + Region.NewFront->Inst = Call; + if (Region.NewBack->Inst == OldCall) + Region.NewBack->Inst = Call; + + // Transfer any debug information. + Call->setDebugLoc(Region.Call->getDebugLoc()); + + // Remove the old instruction. + OldCall->eraseFromParent(); + Region.Call = Call; + + // Make sure that the argument in the new function has the SwiftError + // argument. + if (Group.SwiftErrorArgument.hasValue()) + Call->addParamAttr(Group.SwiftErrorArgument.getValue(), + Attribute::SwiftError); + + return Call; +} + +// Within an extracted function, replace the argument uses of the extracted +// region with the arguments of the function for an OutlinableGroup. +// +/// \param [in] Region - The region of extracted code to be changed. +/// \param [in,out] OutputBB - The BasicBlock for the output stores for this +/// region. +static void replaceArgumentUses(OutlinableRegion &Region, + BasicBlock *OutputBB) { + OutlinableGroup &Group = *Region.Parent; + assert(Region.ExtractedFunction && "Region has no extracted function?"); + + for (unsigned ArgIdx = 0; ArgIdx < Region.ExtractedFunction->arg_size(); + ArgIdx++) { + assert(Region.ExtractedArgToAgg.find(ArgIdx) != + Region.ExtractedArgToAgg.end() && + "No mapping from extracted to outlined?"); + unsigned AggArgIdx = Region.ExtractedArgToAgg.find(ArgIdx)->second; + Argument *AggArg = Group.OutlinedFunction->getArg(AggArgIdx); + Argument *Arg = Region.ExtractedFunction->getArg(ArgIdx); + // The argument is an input, so we can simply replace it with the overall + // argument value + if (ArgIdx < Region.NumExtractedInputs) { + LLVM_DEBUG(dbgs() << "Replacing uses of input " << *Arg << " in function " + << *Region.ExtractedFunction << " with " << *AggArg + << " in function " << *Group.OutlinedFunction << "\n"); + Arg->replaceAllUsesWith(AggArg); + continue; + } + + // If we are replacing an output, we place the store value in its own + // block inside the overall function before replacing the use of the output + // in the function. + assert(Arg->hasOneUse() && "Output argument can only have one use"); + User *InstAsUser = Arg->user_back(); + assert(InstAsUser && "User is nullptr!"); + + Instruction *I = cast(InstAsUser); + I->setDebugLoc(DebugLoc()); + LLVM_DEBUG(dbgs() << "Move store for instruction " << *I << " to " + << *OutputBB << "\n"); + + I->moveBefore(*OutputBB, OutputBB->end()); + + LLVM_DEBUG(dbgs() << "Replacing uses of output " << *Arg << " in function " + << *Region.ExtractedFunction << " with " << *AggArg + << " in function " << *Group.OutlinedFunction << "\n"); + Arg->replaceAllUsesWith(AggArg); + } +} + +/// Within an extracted function, replace the constants that need to be lifted +/// into arguments with the actual argument. +/// +/// \param Region [in] - The region of extracted code to be changed. +void replaceConstants(OutlinableRegion &Region) { + OutlinableGroup &Group = *Region.Parent; + // Iterate over the constants that need to be elevated into arguments + for (std::pair &Const : Region.AggArgToConstant) { + unsigned AggArgIdx = Const.first; + Function *OutlinedFunction = Group.OutlinedFunction; + assert(OutlinedFunction && "Overall Function is not defined?"); + Constant *CST = Const.second; + Argument *Arg = Group.OutlinedFunction->getArg(AggArgIdx); + // Identify the argument it will be elevated to, and replace instances of + // that constant in the function. + + // TODO: If in the future constants do not have one global value number, + // i.e. a constant 1 could be mapped to several values, this check will + // have to be more strict. It cannot be using only replaceUsesWithIf. + + LLVM_DEBUG(dbgs() << "Replacing uses of constant " << *CST + << " in function " << *OutlinedFunction << " with " + << *Arg << "\n"); + CST->replaceUsesWithIf(Arg, [OutlinedFunction](Use &U) { + if (Instruction *I = dyn_cast(U.getUser())) + return I->getFunction() == OutlinedFunction; + return false; + }); + } +} + +/// For the given function, find all the nondebug or lifetime instructions, +/// and return them as a vector. Exclude any blocks in \p ExludeBlocks. +/// +/// \param [in] F - The function we collect the instructions from. +/// \param [in] ExcludeBlocks - BasicBlocks to ignore. +/// \returns the list of instructions extracted. +static std::vector +collectRelevantInstructions(Function &F, + DenseSet &ExcludeBlocks) { + std::vector RelevantInstructions; + + for (BasicBlock &BB : F) { + if (ExcludeBlocks.contains(&BB)) + continue; + + for (Instruction &Inst : BB) { + if (Inst.isLifetimeStartOrEnd()) + continue; + if (isa(Inst)) + continue; + + RelevantInstructions.push_back(&Inst); + } + } + + return RelevantInstructions; +} + +/// It is possible that there is a basic block that already performs the same +/// stores. This returns a duplicate block, if it exists +/// +/// \param OutputBB [in] the block we are looking for a duplicate of. +/// \param OutputStoreBBs [in] The existing output blocks. +/// \returns an optional value with the number output block if there is a match. +Optional +findDuplicateOutputBlock(BasicBlock *OutputBB, + ArrayRef OutputStoreBBs) { + + bool WrongInst = false; + bool WrongSize = false; + unsigned MatchingNum = 0; + for (BasicBlock *CompBB : OutputStoreBBs) { + WrongInst = false; + if (CompBB->size() - 1 != OutputBB->size()) { + WrongSize = true; + MatchingNum++; + continue; + } + + WrongSize = false; + BasicBlock::iterator NIt = OutputBB->begin(); + for (Instruction &I : *CompBB) { + if (isa(&I)) + continue; + + if (!I.isIdenticalTo(&(*NIt))) { + WrongInst = true; + break; + } + + NIt++; + } + if (!WrongInst && !WrongSize) + return MatchingNum; + + MatchingNum++; + } + + return None; +} + +/// For the outlined section, move needed the StoreInsts for the output +/// registers into their own block. Then, determine if there is a duplicate +/// output block already created. +/// +/// \param [in] OG - The OutlinableGroup of regions to be outlined. +/// \param [in] Region - The OutlinableRegion that is being analyzed. +/// \param [in,out] OutputBB - the block that stores for this region will be +/// placed in. +/// \param [in] EndBB - the final block of the extracted function. +/// \param [in] OutputMappings - OutputMappings the mapping of values that have +/// been replaced by a new output value. +/// \param [in,out] OutputStoreBBs - The existing output blocks. +static void +alignOutputBlockWithAggFunc(OutlinableGroup &OG, OutlinableRegion &Region, + BasicBlock *OutputBB, BasicBlock *EndBB, + const DenseMap &OutputMappings, + std::vector &OutputStoreBBs) { + DenseSet ValuesToFind(Region.GVNStores.begin(), + Region.GVNStores.end()); + + // We iterate over the instructions in the extracted function, and find the + // global value number of the instructions. If we find a value that should + // be contained in a store, we replace the uses of the value with the value + // from the overall function, so that the store is storing the correct + // value from the overall function. + DenseSet ExcludeBBs(OutputStoreBBs.begin(), + OutputStoreBBs.end()); + ExcludeBBs.insert(OutputBB); + std::vector ExtractedFunctionInsts = + collectRelevantInstructions(*(Region.ExtractedFunction), ExcludeBBs); + std::vector OverallFunctionInsts = + collectRelevantInstructions(*OG.OutlinedFunction, ExcludeBBs); + + assert(ExtractedFunctionInsts.size() == OverallFunctionInsts.size() && + "Number of relevant instructions not equal!"); + + unsigned NumInstructions = ExtractedFunctionInsts.size(); + for (unsigned Idx = 0; Idx < NumInstructions; Idx++) { + Value *V = ExtractedFunctionInsts[Idx]; + + if (OutputMappings.find(V) != OutputMappings.end()) + V = OutputMappings.find(V)->second; + Optional GVN = Region.Candidate->getGVN(V); + + // If we have found one of the stored values for output, replace the value + // with the corresponding one from the overall function. + if (GVN.hasValue() && ValuesToFind.erase(GVN.getValue())) { + V->replaceAllUsesWith(OverallFunctionInsts[Idx]); + if (ValuesToFind.size() == 0) + break; + } + + if (ValuesToFind.size() == 0) + break; + } + + assert(ValuesToFind.size() == 0 && "Not all store values were handled!"); + + // If the size of the block is 0, then there are no stores, and we do not + // need to save this block. + if (OutputBB->size() == 0) { + Region.OutputBlockNum = -1; + OutputBB->eraseFromParent(); + return; + } + + // Determine is there is a duplicate block. + Optional MatchingBB = + findDuplicateOutputBlock(OutputBB, OutputStoreBBs); + + // If there is, we remove the new output block. If it does not, + // we add it to our list of output blocks. + if (MatchingBB.hasValue()) { + LLVM_DEBUG(dbgs() << "Set output block for region in function" + << Region.ExtractedFunction << " to " + << MatchingBB.getValue()); + + Region.OutputBlockNum = MatchingBB.getValue(); + OutputBB->eraseFromParent(); + return; + } + + Region.OutputBlockNum = OutputStoreBBs.size(); + + LLVM_DEBUG(dbgs() << "Create output block for region in" + << Region.ExtractedFunction << " to " + << *OutputBB); + OutputStoreBBs.push_back(OutputBB); + BranchInst::Create(EndBB, OutputBB); +} + +/// Create the switch statement for outlined function to differentiate between +/// all the output blocks. +/// +/// For the outlined section, determine if an outlined block already exists that +/// matches the needed stores for the extracted section. +/// \param [in] M - The module we are outlining from. +/// \param [in] OG - The group of regions to be outlined. +/// \param [in] OS - The region that is being analyzed. +/// \param [in] EndBB - The final block of the extracted function. +/// \param [in,out] OutputStoreBBs - The existing output blocks. +void createSwitchStatement(Module &M, OutlinableGroup &OG, BasicBlock *EndBB, + ArrayRef OutputStoreBBs) { + // We only need the switch statement if there is more than one store + // combination. + if (OG.OutputGVNCombinations.size() > 1) { + Function *AggFunc = OG.OutlinedFunction; + // Create a final block + BasicBlock *ReturnBlock = + BasicBlock::Create(M.getContext(), "final_block", AggFunc); + Instruction *Term = EndBB->getTerminator(); + Term->moveBefore(*ReturnBlock, ReturnBlock->end()); + // Put the switch statement in the old end basic block for the function with + // a fall through to the new return block + LLVM_DEBUG(dbgs() << "Create switch statement in " << *AggFunc << " for " + << OutputStoreBBs.size() << "\n"); + SwitchInst *SwitchI = + SwitchInst::Create(AggFunc->getArg(AggFunc->arg_size() - 1), + ReturnBlock, OutputStoreBBs.size(), EndBB); + + unsigned Idx = 0; + for (BasicBlock *BB : OutputStoreBBs) { + SwitchI->addCase(ConstantInt::get(Type::getInt32Ty(M.getContext()), Idx), + BB); + Term = BB->getTerminator(); + Term->setSuccessor(0, ReturnBlock); + Idx++; + } + return; + } + + // If there needs to be stores, move them from the output block to the end + // block to save on branching instructions. + if (OutputStoreBBs.size() == 1) { + LLVM_DEBUG(dbgs() << "Move store instructions to the end block in " + << *OG.OutlinedFunction << "\n"); + BasicBlock *OutputBlock = OutputStoreBBs[0]; + Instruction *Term = OutputBlock->getTerminator(); + Term->eraseFromParent(); + Term = EndBB->getTerminator(); + moveBBContents(*OutputBlock, *EndBB); + Term->moveBefore(*EndBB, EndBB->end()); + OutputBlock->eraseFromParent(); + } +} + +/// Fill the new function that will serve as the replacement function for all of +/// the extracted regions of a certain structure from the first region in the +/// list of regions. Replace this first region's extracted function with the +/// new overall function. +/// +/// \param [in] M - The module we are outlining from. +/// \param [in] CurrentGroup - The group of regions to be outlined. +/// \param [in,out] OutputStoreBBs - The output blocks for each different +/// set of stores needed for the different functions. +/// \param [in,out] FuncsToRemove - Extracted functions to erase from module +/// once outlining is complete. +static void fillOverallFunction(Module &M, OutlinableGroup &CurrentGroup, + std::vector &OutputStoreBBs, + std::vector &FuncsToRemove) { + OutlinableRegion *CurrentOS = CurrentGroup.Regions[0]; + + // Move first extracted function's instructions into new function. + LLVM_DEBUG(dbgs() << "Move instructions from " + << *CurrentOS->ExtractedFunction << " to instruction " + << *CurrentGroup.OutlinedFunction << "\n"); + + CurrentGroup.EndBB = moveFunctionData(*CurrentOS->ExtractedFunction, + *CurrentGroup.OutlinedFunction); + + // Transfer the attributes from the function to the new function. + for (Attribute A : + CurrentOS->ExtractedFunction->getAttributes().getFnAttributes()) + CurrentGroup.OutlinedFunction->addFnAttr(A); + + // Create an output block for the first extracted function. + BasicBlock *NewBB = BasicBlock::Create( + M.getContext(), Twine("output_block_") + Twine(static_cast(0)), + CurrentGroup.OutlinedFunction); + CurrentOS->OutputBlockNum = 0; + + replaceArgumentUses(*CurrentOS, NewBB); + replaceConstants(*CurrentOS); + + // If the new basic block has no new stores, we can erase it from the module. + // It it does, we create a branch instruction to the last basic block from the + // new one. + if (NewBB->size() == 0) { + CurrentOS->OutputBlockNum = -1; + NewBB->eraseFromParent(); + } else { + BranchInst::Create(CurrentGroup.EndBB, NewBB); + OutputStoreBBs.push_back(NewBB); + } + + // Replace the call to the extracted function with the outlined function. + CurrentOS->Call = replaceCalledFunction(M, *CurrentOS); + + // We only delete the extracted functions at the end since we may need to + // reference instructions contained in them for mapping purposes. + FuncsToRemove.push_back(CurrentOS->ExtractedFunction); +} + +void IROutliner::deduplicateExtractedSections( + Module &M, OutlinableGroup &CurrentGroup, + std::vector &FuncsToRemove, unsigned &OutlinedFunctionNum) { + createFunction(M, CurrentGroup, OutlinedFunctionNum); + + std::vector OutputStoreBBs; + + OutlinableRegion *CurrentOS; + + fillOverallFunction(M, CurrentGroup, OutputStoreBBs, FuncsToRemove); + + for (unsigned Idx = 1; Idx < CurrentGroup.Regions.size(); Idx++) { + CurrentOS = CurrentGroup.Regions[Idx]; + AttributeFuncs::mergeAttributesForOutlining(*CurrentGroup.OutlinedFunction, + *CurrentOS->ExtractedFunction); + + // Create a new BasicBlock to hold the needed store instructions. + BasicBlock *NewBB = BasicBlock::Create( + M.getContext(), "output_block_" + std::to_string(Idx), + CurrentGroup.OutlinedFunction); + replaceArgumentUses(*CurrentOS, NewBB); + + alignOutputBlockWithAggFunc(CurrentGroup, *CurrentOS, NewBB, + CurrentGroup.EndBB, OutputMappings, + OutputStoreBBs); + + CurrentOS->Call = replaceCalledFunction(M, *CurrentOS); + FuncsToRemove.push_back(CurrentOS->ExtractedFunction); + } + + // Create a switch statement to handle the different output schemes. + createSwitchStatement(M, CurrentGroup, CurrentGroup.EndBB, OutputStoreBBs); + + OutlinedFunctionNum++; +} + +void IROutliner::pruneIncompatibleRegions( + std::vector &CandidateVec, + OutlinableGroup &CurrentGroup) { + bool PreviouslyOutlined; + + // Sort from beginning to end, so the IRSimilarityCandidates are in order. + stable_sort(CandidateVec, [](const IRSimilarityCandidate &LHS, + const IRSimilarityCandidate &RHS) { + return LHS.getStartIdx() < RHS.getStartIdx(); + }); + + unsigned CurrentEndIdx = 0; + for (IRSimilarityCandidate &IRSC : CandidateVec) { + PreviouslyOutlined = false; + unsigned StartIdx = IRSC.getStartIdx(); + unsigned EndIdx = IRSC.getEndIdx(); + + for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++) + if (Outlined.contains(Idx)) { + PreviouslyOutlined = true; + break; + } + + if (PreviouslyOutlined) + continue; + + // TODO: If in the future we can outline across BasicBlocks, we will need to + // check all BasicBlocks contained in the region. + if (IRSC.getStartBB()->hasAddressTaken()) + continue; + + if (IRSC.front()->Inst->getFunction()->hasLinkOnceODRLinkage() && + !OutlineFromLinkODRs) + continue; + + // Greedily prune out any regions that will overlap with already chosen + // regions. + if (CurrentEndIdx != 0 && StartIdx <= CurrentEndIdx) + continue; + + bool BadInst = any_of(IRSC, [this](IRInstructionData &ID) { + // We check if there is a discrepancy between the InstructionDataList + // and the actual next instruction in the module. If there is, it means + // that an extra instruction was added, likely by the CodeExtractor. + + // Since we do not have any similarity data about this particular + // instruction, we cannot confidently outline it, and must discard this + // candidate. + if (std::next(ID.getIterator())->Inst != + ID.Inst->getNextNonDebugInstruction()) + return true; + return !this->InstructionClassifier.visit(ID.Inst); + }); + + if (BadInst) + continue; + + OutlinableRegion *OS = new (RegionAllocator.Allocate()) + OutlinableRegion(IRSC, CurrentGroup); + CurrentGroup.Regions.push_back(OS); + + CurrentEndIdx = EndIdx; + } +} + +InstructionCost +IROutliner::findBenefitFromAllRegions(OutlinableGroup &CurrentGroup) { + InstructionCost RegionBenefit = 0; + for (OutlinableRegion *Region : CurrentGroup.Regions) { + TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent()); + // We add the number of instructions in the region to the benefit as an + // estimate as to how much will be removed. + RegionBenefit += Region->getBenefit(TTI); + LLVM_DEBUG(dbgs() << "Adding: " << RegionBenefit + << " saved instructions to overfall benefit.\n"); + } + + return RegionBenefit; +} + +InstructionCost +IROutliner::findCostOutputReloads(OutlinableGroup &CurrentGroup) { + InstructionCost OverallCost = 0; + for (OutlinableRegion *Region : CurrentGroup.Regions) { + TargetTransformInfo &TTI = getTTI(*Region->StartBB->getParent()); + + // Each output incurs a load after the call, so we add that to the cost. + for (unsigned OutputGVN : Region->GVNStores) { + Optional OV = Region->Candidate->fromGVN(OutputGVN); + assert(OV.hasValue() && "Could not find value for GVN?"); + Value *V = OV.getValue(); + InstructionCost LoadCost = + TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0, + TargetTransformInfo::TCK_CodeSize); + + LLVM_DEBUG(dbgs() << "Adding: " << LoadCost + << " instructions to cost for output of type " + << *V->getType() << "\n"); + OverallCost += LoadCost; + } + } + + return OverallCost; +} + +/// 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; + + for (const ArrayRef &OutputUse : + CurrentGroup.OutputGVNCombinations) { + IRSimilarityCandidate &Candidate = *CurrentGroup.Regions[0]->Candidate; + for (unsigned GVN : OutputUse) { + Optional OV = Candidate.fromGVN(GVN); + assert(OV.hasValue() && "Could not find value for GVN?"); + Value *V = OV.getValue(); + InstructionCost StoreCost = + TTI.getMemoryOpCost(Instruction::Load, V->getType(), Align(1), 0, + TargetTransformInfo::TCK_CodeSize); + + // An instruction cost is added for each store set that needs to occur for + // various output combinations inside the function, plus a branch to + // return to the exit block. + LLVM_DEBUG(dbgs() << "Adding: " << StoreCost + << " instructions to cost for output of type " + << *V->getType() << "\n"); + OutputCost += StoreCost; + } + + InstructionCost BranchCost = + TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize); + LLVM_DEBUG(dbgs() << "Adding " << BranchCost << " to the current cost for" + << " a branch instruction\n"); + OutputCost += BranchCost; + } + + // If there is more than one output scheme, we must have a comparison and + // branch for each different item in the switch statement. + if (CurrentGroup.OutputGVNCombinations.size() > 1) { + InstructionCost ComparisonCost = TTI.getCmpSelInstrCost( + Instruction::ICmp, Type::getInt32Ty(M.getContext()), + Type::getInt32Ty(M.getContext()), CmpInst::BAD_ICMP_PREDICATE, + TargetTransformInfo::TCK_CodeSize); + InstructionCost BranchCost = + TTI.getCFInstrCost(Instruction::Br, TargetTransformInfo::TCK_CodeSize); + + unsigned DifferentBlocks = CurrentGroup.OutputGVNCombinations.size(); + InstructionCost TotalCost = ComparisonCost * BranchCost * DifferentBlocks; + + LLVM_DEBUG(dbgs() << "Adding: " << TotalCost + << " instructions for each switch case for each different" + << " output path in a function\n"); + OutputCost += TotalCost; + } + + return OutputCost; +} + +void IROutliner::findCostBenefit(Module &M, OutlinableGroup &CurrentGroup) { + InstructionCost RegionBenefit = findBenefitFromAllRegions(CurrentGroup); + CurrentGroup.Benefit += RegionBenefit; + LLVM_DEBUG(dbgs() << "Current Benefit: " << CurrentGroup.Benefit << "\n"); + + InstructionCost OutputReloadCost = findCostOutputReloads(CurrentGroup); + CurrentGroup.Cost += OutputReloadCost; + LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n"); + + InstructionCost AverageRegionBenefit = + RegionBenefit / CurrentGroup.Regions.size(); + unsigned OverallArgumentNum = CurrentGroup.ArgumentTypes.size(); + unsigned NumRegions = CurrentGroup.Regions.size(); + TargetTransformInfo &TTI = + getTTI(*CurrentGroup.Regions[0]->Candidate->getFunction()); + + // We add one region to the cost once, to account for the instructions added + // inside of the newly created function. + LLVM_DEBUG(dbgs() << "Adding: " << AverageRegionBenefit + << " instructions to cost for body of new function.\n"); + CurrentGroup.Cost += AverageRegionBenefit; + LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n"); + + // For each argument, we must add an instruction for loading the argument + // out of the register and into a value inside of the newly outlined function. + LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum + << " instructions to cost for each argument in the new" + << " function.\n"); + CurrentGroup.Cost += + OverallArgumentNum * TargetTransformInfo::TCC_Basic; + LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n"); + + // Each argument needs to either be loaded into a register or onto the stack. + // Some arguments will only be loaded into the stack once the argument + // registers are filled. + LLVM_DEBUG(dbgs() << "Adding: " << OverallArgumentNum + << " instructions to cost for each argument in the new" + << " function " << NumRegions << " times for the " + << "needed argument handling at the call site.\n"); + CurrentGroup.Cost += + 2 * OverallArgumentNum * TargetTransformInfo::TCC_Basic * NumRegions; + LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n"); + + CurrentGroup.Cost += findCostForOutputBlocks(M, CurrentGroup, TTI); + LLVM_DEBUG(dbgs() << "Current Cost: " << CurrentGroup.Cost << "\n"); +} + +void IROutliner::updateOutputMapping(OutlinableRegion &Region, + ArrayRef Outputs, + LoadInst *LI) { + // For and load instructions following the call + Value *Operand = LI->getPointerOperand(); + Optional OutputIdx = None; + // Find if the operand it is an output register. + for (unsigned ArgIdx = Region.NumExtractedInputs; + ArgIdx < Region.Call->arg_size(); ArgIdx++) { + if (Operand == Region.Call->getArgOperand(ArgIdx)) { + OutputIdx = ArgIdx - Region.NumExtractedInputs; + break; + } + } + + // If we found an output register, place a mapping of the new value + // to the original in the mapping. + if (!OutputIdx.hasValue()) + return; + + if (OutputMappings.find(Outputs[OutputIdx.getValue()]) == + OutputMappings.end()) { + LLVM_DEBUG(dbgs() << "Mapping extracted output " << *LI << " to " + << *Outputs[OutputIdx.getValue()] << "\n"); + OutputMappings.insert(std::make_pair(LI, Outputs[OutputIdx.getValue()])); + } else { + Value *Orig = OutputMappings.find(Outputs[OutputIdx.getValue()])->second; + LLVM_DEBUG(dbgs() << "Mapping extracted output " << *Orig << " to " + << *Outputs[OutputIdx.getValue()] << "\n"); + OutputMappings.insert(std::make_pair(LI, Orig)); + } +} + +bool IROutliner::extractSection(OutlinableRegion &Region) { + SetVector ArgInputs, Outputs, SinkCands; + Region.CE->findInputsOutputs(ArgInputs, Outputs, SinkCands); + + assert(Region.StartBB && "StartBB for the OutlinableRegion is nullptr!"); + assert(Region.FollowBB && "FollowBB for the OutlinableRegion is nullptr!"); + Function *OrigF = Region.StartBB->getParent(); + CodeExtractorAnalysisCache CEAC(*OrigF); + Region.ExtractedFunction = Region.CE->extractCodeRegion(CEAC); + + // If the extraction was successful, find the BasicBlock, and reassign the + // OutlinableRegion blocks + if (!Region.ExtractedFunction) { + LLVM_DEBUG(dbgs() << "CodeExtractor failed to outline " << Region.StartBB + << "\n"); + Region.reattachCandidate(); + return false; + } + + BasicBlock *RewrittenBB = Region.FollowBB->getSinglePredecessor(); + Region.StartBB = RewrittenBB; + Region.EndBB = RewrittenBB; + + // The sequences of outlinable regions has now changed. We must fix the + // IRInstructionDataList for consistency. Although they may not be illegal + // instructions, they should not be compared with anything else as they + // should not be outlined in this round. So marking these as illegal is + // allowed. + IRInstructionDataList *IDL = Region.Candidate->front()->IDL; + Instruction *BeginRewritten = &*RewrittenBB->begin(); + Instruction *EndRewritten = &*RewrittenBB->begin(); + Region.NewFront = new (InstDataAllocator.Allocate()) IRInstructionData( + *BeginRewritten, InstructionClassifier.visit(*BeginRewritten), *IDL); + Region.NewBack = new (InstDataAllocator.Allocate()) IRInstructionData( + *EndRewritten, InstructionClassifier.visit(*EndRewritten), *IDL); + + // Insert the first IRInstructionData of the new region in front of the + // first IRInstructionData of the IRSimilarityCandidate. + IDL->insert(Region.Candidate->begin(), *Region.NewFront); + // Insert the first IRInstructionData of the new region after the + // last IRInstructionData of the IRSimilarityCandidate. + IDL->insert(Region.Candidate->end(), *Region.NewBack); + // Remove the IRInstructionData from the IRSimilarityCandidate. + IDL->erase(Region.Candidate->begin(), std::prev(Region.Candidate->end())); + + assert(RewrittenBB != nullptr && + "Could not find a predecessor after extraction!"); + + // Iterate over the new set of instructions to find the new call + // instruction. + for (Instruction &I : *RewrittenBB) + if (CallInst *CI = dyn_cast(&I)) { + if (Region.ExtractedFunction == CI->getCalledFunction()) + Region.Call = CI; + } else if (LoadInst *LI = dyn_cast(&I)) + updateOutputMapping(Region, Outputs.getArrayRef(), LI); + Region.reattachCandidate(); + return true; +} + +unsigned IROutliner::doOutline(Module &M) { + // Find the possible similarity sections. + IRSimilarityIdentifier &Identifier = getIRSI(M); + SimilarityGroupList &SimilarityCandidates = *Identifier.getSimilarity(); + + // Sort them by size of extracted sections + unsigned OutlinedFunctionNum = 0; + // If we only have one SimilarityGroup in SimilarityCandidates, we do not have + // to sort them by the potential number of instructions to be outlined + if (SimilarityCandidates.size() > 1) + llvm::stable_sort(SimilarityCandidates, + [](const std::vector &LHS, + const std::vector &RHS) { + return LHS[0].getLength() * LHS.size() > + RHS[0].getLength() * RHS.size(); + }); + + DenseSet NotSame; + std::vector FuncsToRemove; + // Iterate over the possible sets of similarity. + for (SimilarityGroup &CandidateVec : SimilarityCandidates) { + OutlinableGroup CurrentGroup; + + // Remove entries that were previously outlined + pruneIncompatibleRegions(CandidateVec, CurrentGroup); + + // We pruned the number of regions to 0 to 1, meaning that it's not worth + // trying to outlined since there is no compatible similar instance of this + // code. + if (CurrentGroup.Regions.size() < 2) + continue; + + // Determine if there are any values that are the same constant throughout + // each section in the set. + NotSame.clear(); + CurrentGroup.findSameConstants(NotSame); + + if (CurrentGroup.IgnoreGroup) + continue; + + // Create a CodeExtractor for each outlinable region. Identify inputs and + // outputs for each section using the code extractor and create the argument + // types for the Aggregate Outlining Function. + std::vector OutlinedRegions; + for (OutlinableRegion *OS : CurrentGroup.Regions) { + // Break the outlinable region out of its parent BasicBlock into its own + // BasicBlocks (see function implementation). + OS->splitCandidate(); + std::vector BE = {OS->StartBB}; + OS->CE = new (ExtractorAllocator.Allocate()) + CodeExtractor(BE, nullptr, false, nullptr, nullptr, nullptr, false, + false, "outlined"); + findAddInputsOutputs(M, *OS, NotSame); + if (!OS->IgnoreRegion) + OutlinedRegions.push_back(OS); + else + OS->reattachCandidate(); + } + + CurrentGroup.Regions = std::move(OutlinedRegions); + + if (CurrentGroup.Regions.empty()) + continue; + + CurrentGroup.collectGVNStoreSets(M); + + if (CostModel) + findCostBenefit(M, CurrentGroup); + + // If we are adhering to the cost model, reattach all the candidates + if (CurrentGroup.Cost >= CurrentGroup.Benefit && CostModel) { + for (OutlinableRegion *OS : CurrentGroup.Regions) + OS->reattachCandidate(); + OptimizationRemarkEmitter &ORE = getORE( + *CurrentGroup.Regions[0]->Candidate->getFunction()); + ORE.emit([&]() { + IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate; + OptimizationRemarkMissed R(DEBUG_TYPE, "WouldNotDecreaseSize", + C->frontInstruction()); + R << "did not outline " + << ore::NV(std::to_string(CurrentGroup.Regions.size())) + << " regions due to estimated increase of " + << ore::NV("InstructionIncrease", + CurrentGroup.Cost - CurrentGroup.Benefit) + << " instructions at locations "; + interleave( + CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(), + [&R](OutlinableRegion *Region) { + R << ore::NV( + "DebugLoc", + Region->Candidate->frontInstruction()->getDebugLoc()); + }, + [&R]() { R << " "; }); + return R; + }); + continue; + } + + LLVM_DEBUG(dbgs() << "Outlining regions with cost " << CurrentGroup.Cost + << " and benefit " << CurrentGroup.Benefit << "\n"); + + // Create functions out of all the sections, and mark them as outlined. + OutlinedRegions.clear(); + for (OutlinableRegion *OS : CurrentGroup.Regions) { + bool FunctionOutlined = extractSection(*OS); + if (FunctionOutlined) { + unsigned StartIdx = OS->Candidate->getStartIdx(); + unsigned EndIdx = OS->Candidate->getEndIdx(); + for (unsigned Idx = StartIdx; Idx <= EndIdx; Idx++) + Outlined.insert(Idx); + + OutlinedRegions.push_back(OS); + } + } + + LLVM_DEBUG(dbgs() << "Outlined " << OutlinedRegions.size() + << " with benefit " << CurrentGroup.Benefit + << " and cost " << CurrentGroup.Cost << "\n"); + + CurrentGroup.Regions = std::move(OutlinedRegions); + + if (CurrentGroup.Regions.empty()) + continue; + + OptimizationRemarkEmitter &ORE = + getORE(*CurrentGroup.Regions[0]->Call->getFunction()); + ORE.emit([&]() { + IRSimilarityCandidate *C = CurrentGroup.Regions[0]->Candidate; + OptimizationRemark R(DEBUG_TYPE, "Outlined", C->front()->Inst); + R << "outlined " << ore::NV(std::to_string(CurrentGroup.Regions.size())) + << " regions with decrease of " + << ore::NV("Benefit", CurrentGroup.Benefit - CurrentGroup.Cost) + << " instructions at locations "; + interleave( + CurrentGroup.Regions.begin(), CurrentGroup.Regions.end(), + [&R](OutlinableRegion *Region) { + R << ore::NV("DebugLoc", + Region->Candidate->frontInstruction()->getDebugLoc()); + }, + [&R]() { R << " "; }); + return R; + }); + + deduplicateExtractedSections(M, CurrentGroup, FuncsToRemove, + OutlinedFunctionNum); + } + + for (Function *F : FuncsToRemove) + F->eraseFromParent(); + + return OutlinedFunctionNum; +} + +bool IROutliner::run(Module &M) { + CostModel = !NoCostModel; + OutlineFromLinkODRs = EnableLinkOnceODRIROutlining; + + return doOutline(M) > 0; +} + +// Pass Manager Boilerplate +class IROutlinerLegacyPass : public ModulePass { +public: + static char ID; + IROutlinerLegacyPass() : ModulePass(ID) { + initializeIROutlinerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + } + + bool runOnModule(Module &M) override; +}; + +bool IROutlinerLegacyPass::runOnModule(Module &M) { + if (skipModule(M)) + return false; + + std::unique_ptr ORE; + auto GORE = [&ORE](Function &F) -> OptimizationRemarkEmitter & { + ORE.reset(new OptimizationRemarkEmitter(&F)); + return *ORE.get(); + }; + + auto GTTI = [this](Function &F) -> TargetTransformInfo & { + return this->getAnalysis().getTTI(F); + }; + + auto GIRSI = [this](Module &) -> IRSimilarityIdentifier & { + return this->getAnalysis().getIRSI(); + }; + + return IROutliner(GTTI, GIRSI, GORE).run(M); +} + +PreservedAnalyses IROutlinerPass::run(Module &M, ModuleAnalysisManager &AM) { + auto &FAM = AM.getResult(M).getManager(); + + std::function GTTI = + [&FAM](Function &F) -> TargetTransformInfo & { + return FAM.getResult(F); + }; + + std::function GIRSI = + [&AM](Module &M) -> IRSimilarityIdentifier & { + return AM.getResult(M); + }; + + std::unique_ptr ORE; + std::function GORE = + [&ORE](Function &F) -> OptimizationRemarkEmitter & { + ORE.reset(new OptimizationRemarkEmitter(&F)); + return *ORE.get(); + }; + + if (IROutliner(GTTI, GIRSI, GORE).run(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +char IROutlinerLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(IROutlinerLegacyPass, "iroutliner", "IR Outliner", false, + false) +INITIALIZE_PASS_DEPENDENCY(IRSimilarityIdentifierWrapperPass) +INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_END(IROutlinerLegacyPass, "iroutliner", "IR Outliner", false, + false) + +ModulePass *llvm::createIROutlinerPass() { return new IROutlinerLegacyPass(); } diff --git a/llvm/lib/Transforms/IPO/Inliner.cpp b/llvm/lib/Transforms/IPO/Inliner.cpp index 7d2260f4c169..e91b6c9b1d26 100644 --- a/llvm/lib/Transforms/IPO/Inliner.cpp +++ b/llvm/lib/Transforms/IPO/Inliner.cpp @@ -23,7 +23,6 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/BlockFrequencyInfo.h" @@ -37,6 +36,7 @@ #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/Utils/ImportedFunctionsInliningStatistics.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DataLayout.h" @@ -60,7 +60,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/CallPromotionUtils.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include @@ -91,24 +90,14 @@ static cl::opt DisableInlinedAllocaMerging("disable-inlined-alloca-merging", cl::init(false), cl::Hidden); -namespace { +extern cl::opt InlinerFunctionImportStats; -enum class InlinerFunctionImportStatsOpts { - No = 0, - Basic = 1, - Verbose = 2, -}; - -} // end anonymous namespace - -static cl::opt InlinerFunctionImportStats( - "inliner-function-import-stats", - cl::init(InlinerFunctionImportStatsOpts::No), - cl::values(clEnumValN(InlinerFunctionImportStatsOpts::Basic, "basic", - "basic statistics"), - clEnumValN(InlinerFunctionImportStatsOpts::Verbose, "verbose", - "printing of statistics for each inlined function")), - cl::Hidden, cl::desc("Enable inliner stats for imported functions")); +static cl::opt CGSCCInlineReplayFile( + "cgscc-inline-replay", cl::init(""), cl::value_desc("filename"), + cl::desc( + "Optimization remarks file containing inline remarks to be replayed " + "by inlining from cgscc inline remarks."), + cl::Hidden); LegacyInlinerBase::LegacyInlinerBase(char &ID) : CallGraphSCCPass(ID) {} @@ -648,17 +637,12 @@ bool LegacyInlinerBase::removeDeadFunctions(CallGraph &CG, return true; } -InlinerPass::~InlinerPass() { - if (ImportedFunctionsStats) { - assert(InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No); - ImportedFunctionsStats->dump(InlinerFunctionImportStats == - InlinerFunctionImportStatsOpts::Verbose); - } -} - InlineAdvisor & InlinerPass::getAdvisor(const ModuleAnalysisManagerCGSCCProxy::Result &MAM, FunctionAnalysisManager &FAM, Module &M) { + if (OwnedAdvisor) + return *OwnedAdvisor; + auto *IAA = MAM.getCachedResult(M); if (!IAA) { // It should still be possible to run the inliner as a stand-alone SCC pass, @@ -669,8 +653,16 @@ InlinerPass::getAdvisor(const ModuleAnalysisManagerCGSCCProxy::Result &MAM, // duration of the inliner pass, and thus the lifetime of the owned advisor. // The one we would get from the MAM can be invalidated as a result of the // inliner's activity. - OwnedDefaultAdvisor.emplace(FAM, getInlineParams()); - return *OwnedDefaultAdvisor; + OwnedAdvisor = + std::make_unique(M, FAM, getInlineParams()); + + if (!CGSCCInlineReplayFile.empty()) + OwnedAdvisor = std::make_unique( + M, FAM, M.getContext(), std::move(OwnedAdvisor), + CGSCCInlineReplayFile, + /*EmitRemarks=*/true); + + return *OwnedAdvisor; } assert(IAA->getAdvisor() && "Expected a present InlineAdvisorAnalysis also have an " @@ -698,20 +690,13 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, auto AdvisorOnExit = make_scope_exit([&] { Advisor.onPassExit(); }); - if (!ImportedFunctionsStats && - InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) { - ImportedFunctionsStats = - std::make_unique(); - ImportedFunctionsStats->setModuleInfo(M); - } - // We use a single common worklist for calls across the entire SCC. We // process these in-order and append new calls introduced during inlining to // the end. // // Note that this particular order of processing is actually critical to // avoid very bad behaviors. Consider *highly connected* call graphs where - // each function contains a small amonut of code and a couple of calls to + // each function contains a small amount of code and a couple of calls to // other functions. Because the LLVM inliner is fundamentally a bottom-up // inliner, it can handle gracefully the fact that these all appear to be // reasonable inlining candidates as it will flatten things until they become @@ -761,9 +746,8 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, if (Calls.empty()) return PreservedAnalyses::all(); - // Capture updatable variables for the current SCC and RefSCC. + // Capture updatable variable for the current SCC. auto *C = &InitialC; - auto *RC = &C->getOuterRefSCC(); // When inlining a callee produces new call sites, we want to keep track of // the fact that they were inlined from the callee. This allows us to avoid @@ -791,12 +775,6 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, LazyCallGraph::Node &N = *CG.lookup(F); if (CG.lookupSCC(N) != C) continue; - if (!Calls[I].first->getCalledFunction()->hasFnAttribute( - Attribute::AlwaysInline) && - F.hasOptNone()) { - setInlineRemark(*Calls[I].first, "optnone attribute"); - continue; - } LLVM_DEBUG(dbgs() << "Inlining calls in: " << F.getName() << "\n"); @@ -834,7 +812,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, continue; } - auto Advice = Advisor.getAdvice(*CB); + auto Advice = Advisor.getAdvice(*CB, OnlyMandatory); // Check whether we want to inline this callsite. if (!Advice->isInliningRecommended()) { Advice->recordUnattemptedInlining(); @@ -848,7 +826,8 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, &FAM.getResult(*(CB->getCaller())), &FAM.getResult(Callee)); - InlineResult IR = InlineFunction(*CB, IFI); + InlineResult IR = + InlineFunction(*CB, IFI, &FAM.getResult(*CB->getCaller())); if (!IR.isSuccess()) { Advice->recordUnsuccessfulInlining(IR); continue; @@ -879,9 +858,6 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, } } - if (InlinerFunctionImportStats != InlinerFunctionImportStatsOpts::No) - ImportedFunctionsStats->recordInline(F, Callee); - // Merge the attributes based on the inlining. AttributeFuncs::mergeAttributesForInlining(F, Callee); @@ -906,7 +882,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, // Note that after this point, it is an error to do anything other // than use the callee's address or delete it. Callee.dropAllReferences(); - assert(find(DeadFunctions, &Callee) == DeadFunctions.end() && + assert(!is_contained(DeadFunctions, &Callee) && "Cannot put cause a function to become dead twice!"); DeadFunctions.push_back(&Callee); CalleeWasDeleted = true; @@ -926,20 +902,6 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, continue; Changed = true; - // Add all the inlined callees' edges as ref edges to the caller. These are - // by definition trivial edges as we always have *some* transitive ref edge - // chain. While in some cases these edges are direct calls inside the - // callee, they have to be modeled in the inliner as reference edges as - // there may be a reference edge anywhere along the chain from the current - // caller to the callee that causes the whole thing to appear like - // a (transitive) reference edge that will require promotion to a call edge - // below. - for (Function *InlinedCallee : InlinedCallees) { - LazyCallGraph::Node &CalleeN = *CG.lookup(*InlinedCallee); - for (LazyCallGraph::Edge &E : *CalleeN) - RC->insertTrivialRefEdge(N, E.getNode()); - } - // At this point, since we have made changes we have at least removed // a call instruction. However, in the process we do some incremental // simplification of the surrounding code. This simplification can @@ -952,9 +914,8 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, // as we're going to mutate this particular function we want to make sure // the proxy is in place to forward any invalidation events. LazyCallGraph::SCC *OldC = C; - C = &updateCGAndAnalysisManagerForFunctionPass(CG, *C, N, AM, UR, FAM); + C = &updateCGAndAnalysisManagerForCGSCCPass(CG, *C, N, AM, UR, FAM); LLVM_DEBUG(dbgs() << "Updated inlining SCC: " << *C << "\n"); - RC = &C->getOuterRefSCC(); // If this causes an SCC to split apart into multiple smaller SCCs, there // is a subtle risk we need to prepare for. Other transformations may @@ -1033,6 +994,7 @@ PreservedAnalyses InlinerPass::run(LazyCallGraph::SCC &InitialC, ModuleInlinerWrapperPass::ModuleInlinerWrapperPass(InlineParams Params, bool Debugging, + bool MandatoryFirst, InliningAdvisorMode Mode, unsigned MaxDevirtIterations) : Params(Params), Mode(Mode), MaxDevirtIterations(MaxDevirtIterations), @@ -1042,13 +1004,15 @@ ModuleInlinerWrapperPass::ModuleInlinerWrapperPass(InlineParams Params, // into the callers so that our optimizations can reflect that. // For PreLinkThinLTO pass, we disable hot-caller heuristic for sample PGO // because it makes profile annotation in the backend inaccurate. + if (MandatoryFirst) + PM.addPass(InlinerPass(/*OnlyMandatory*/ true)); PM.addPass(InlinerPass()); } PreservedAnalyses ModuleInlinerWrapperPass::run(Module &M, ModuleAnalysisManager &MAM) { auto &IAA = MAM.getResult(M); - if (!IAA.tryCreate(Params, Mode)) { + if (!IAA.tryCreate(Params, Mode, CGSCCInlineReplayFile)) { M.getContext().emitError( "Could not setup Inlining Advisor for the requested " "mode and/or options"); diff --git a/llvm/lib/Transforms/IPO/LoopExtractor.cpp b/llvm/lib/Transforms/IPO/LoopExtractor.cpp index f7f5b4cf6704..a497c0390bce 100644 --- a/llvm/lib/Transforms/IPO/LoopExtractor.cpp +++ b/llvm/lib/Transforms/IPO/LoopExtractor.cpp @@ -13,12 +13,14 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/LoopExtractor.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" @@ -36,51 +38,71 @@ using namespace llvm; STATISTIC(NumExtracted, "Number of loops extracted"); namespace { - struct LoopExtractor : public ModulePass { - static char ID; // Pass identification, replacement for typeid +struct LoopExtractorLegacyPass : public ModulePass { + static char ID; // Pass identification, replacement for typeid - // The number of natural loops to extract from the program into functions. - unsigned NumLoops; + unsigned NumLoops; - explicit LoopExtractor(unsigned numLoops = ~0) - : ModulePass(ID), NumLoops(numLoops) { - initializeLoopExtractorPass(*PassRegistry::getPassRegistry()); - } - - bool runOnModule(Module &M) override; - bool runOnFunction(Function &F); + explicit LoopExtractorLegacyPass(unsigned NumLoops = ~0) + : ModulePass(ID), NumLoops(NumLoops) { + initializeLoopExtractorLegacyPassPass(*PassRegistry::getPassRegistry()); + } - bool extractLoops(Loop::iterator From, Loop::iterator To, LoopInfo &LI, - DominatorTree &DT); - bool extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT); + bool runOnModule(Module &M) override; - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequiredID(BreakCriticalEdgesID); - AU.addRequired(); - AU.addRequired(); - AU.addPreserved(); - AU.addRequiredID(LoopSimplifyID); - AU.addUsedIfAvailable(); - } - }; -} - -char LoopExtractor::ID = 0; -INITIALIZE_PASS_BEGIN(LoopExtractor, "loop-extract", + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(BreakCriticalEdgesID); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addRequiredID(LoopSimplifyID); + AU.addUsedIfAvailable(); + } +}; + +struct LoopExtractor { + explicit LoopExtractor( + unsigned NumLoops, + function_ref LookupDomTree, + function_ref LookupLoopInfo, + function_ref LookupAssumptionCache) + : NumLoops(NumLoops), LookupDomTree(LookupDomTree), + LookupLoopInfo(LookupLoopInfo), + LookupAssumptionCache(LookupAssumptionCache) {} + bool runOnModule(Module &M); + +private: + // The number of natural loops to extract from the program into functions. + unsigned NumLoops; + + function_ref LookupDomTree; + function_ref LookupLoopInfo; + function_ref LookupAssumptionCache; + + bool runOnFunction(Function &F); + + bool extractLoops(Loop::iterator From, Loop::iterator To, LoopInfo &LI, + DominatorTree &DT); + bool extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT); +}; +} // namespace + +char LoopExtractorLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(LoopExtractorLegacyPass, "loop-extract", "Extract loops into new functions", false, false) INITIALIZE_PASS_DEPENDENCY(BreakCriticalEdges) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopSimplify) -INITIALIZE_PASS_END(LoopExtractor, "loop-extract", +INITIALIZE_PASS_END(LoopExtractorLegacyPass, "loop-extract", "Extract loops into new functions", false, false) namespace { /// SingleLoopExtractor - For bugpoint. - struct SingleLoopExtractor : public LoopExtractor { - static char ID; // Pass identification, replacement for typeid - SingleLoopExtractor() : LoopExtractor(1) {} - }; +struct SingleLoopExtractor : public LoopExtractorLegacyPass { + static char ID; // Pass identification, replacement for typeid + SingleLoopExtractor() : LoopExtractorLegacyPass(1) {} +}; } // End anonymous namespace char SingleLoopExtractor::ID = 0; @@ -90,12 +112,30 @@ INITIALIZE_PASS(SingleLoopExtractor, "loop-extract-single", // createLoopExtractorPass - This pass extracts all natural loops from the // program into a function if it can. // -Pass *llvm::createLoopExtractorPass() { return new LoopExtractor(); } +Pass *llvm::createLoopExtractorPass() { return new LoopExtractorLegacyPass(); } -bool LoopExtractor::runOnModule(Module &M) { +bool LoopExtractorLegacyPass::runOnModule(Module &M) { if (skipModule(M)) return false; + bool Changed = false; + auto LookupDomTree = [this](Function &F) -> DominatorTree & { + return this->getAnalysis(F).getDomTree(); + }; + auto LookupLoopInfo = [this, &Changed](Function &F) -> LoopInfo & { + return this->getAnalysis(F, &Changed).getLoopInfo(); + }; + auto LookupACT = [this](Function &F) -> AssumptionCache * { + if (auto *ACT = this->getAnalysisIfAvailable()) + return ACT->lookupAssumptionCache(F); + return nullptr; + }; + return LoopExtractor(NumLoops, LookupDomTree, LookupLoopInfo, LookupACT) + .runOnModule(M) || + Changed; +} + +bool LoopExtractor::runOnModule(Module &M) { if (M.empty()) return false; @@ -132,13 +172,13 @@ bool LoopExtractor::runOnFunction(Function &F) { return false; bool Changed = false; - LoopInfo &LI = getAnalysis(F, &Changed).getLoopInfo(); + LoopInfo &LI = LookupLoopInfo(F); // If there are no loops in the function. if (LI.empty()) return Changed; - DominatorTree &DT = getAnalysis(F).getDomTree(); + DominatorTree &DT = LookupDomTree(F); // If there is more than one top-level loop in this function, extract all of // the loops. @@ -203,10 +243,8 @@ bool LoopExtractor::extractLoops(Loop::iterator From, Loop::iterator To, bool LoopExtractor::extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT) { assert(NumLoops != 0); - AssumptionCache *AC = nullptr; Function &Func = *L->getHeader()->getParent(); - if (auto *ACT = getAnalysisIfAvailable()) - AC = ACT->lookupAssumptionCache(Func); + AssumptionCache *AC = LookupAssumptionCache(Func); CodeExtractorAnalysisCache CEAC(Func); CodeExtractor Extractor(DT, *L, false, nullptr, nullptr, AC); if (Extractor.extractCodeRegion(CEAC)) { @@ -224,3 +262,24 @@ bool LoopExtractor::extractLoop(Loop *L, LoopInfo &LI, DominatorTree &DT) { Pass *llvm::createSingleLoopExtractorPass() { return new SingleLoopExtractor(); } + +PreservedAnalyses LoopExtractorPass::run(Module &M, ModuleAnalysisManager &AM) { + auto &FAM = AM.getResult(M).getManager(); + auto LookupDomTree = [&FAM](Function &F) -> DominatorTree & { + return FAM.getResult(F); + }; + auto LookupLoopInfo = [&FAM](Function &F) -> LoopInfo & { + return FAM.getResult(F); + }; + auto LookupAssumptionCache = [&FAM](Function &F) -> AssumptionCache * { + return FAM.getCachedResult(F); + }; + if (!LoopExtractor(NumLoops, LookupDomTree, LookupLoopInfo, + LookupAssumptionCache) + .runOnModule(M)) + return PreservedAnalyses::all(); + + PreservedAnalyses PA; + PA.preserve(); + return PA; +} diff --git a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp index 8eef7e3e7e99..8bd3036f1fc3 100644 --- a/llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ b/llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -198,7 +198,7 @@ void GlobalLayoutBuilder::addFragment(const std::set &F) { // indices from the old fragment in this fragment do not insert any more // indices. std::vector &OldFragment = Fragments[OldFragmentIndex]; - Fragment.insert(Fragment.end(), OldFragment.begin(), OldFragment.end()); + llvm::append_range(Fragment, OldFragment); OldFragment.clear(); } } @@ -1205,6 +1205,7 @@ void LowerTypeTestsModule::verifyTypeMDNode(GlobalObject *GO, MDNode *Type) { static const unsigned kX86JumpTableEntrySize = 8; static const unsigned kARMJumpTableEntrySize = 4; +static const unsigned kARMBTIJumpTableEntrySize = 8; unsigned LowerTypeTestsModule::getJumpTableEntrySize() { switch (Arch) { @@ -1213,7 +1214,12 @@ unsigned LowerTypeTestsModule::getJumpTableEntrySize() { return kX86JumpTableEntrySize; case Triple::arm: case Triple::thumb: + return kARMJumpTableEntrySize; case Triple::aarch64: + if (const auto *BTE = mdconst::extract_or_null( + M.getModuleFlag("branch-target-enforcement"))) + if (BTE->getZExtValue()) + return kARMBTIJumpTableEntrySize; return kARMJumpTableEntrySize; default: report_fatal_error("Unsupported architecture for jump tables"); @@ -1232,7 +1238,13 @@ void LowerTypeTestsModule::createJumpTableEntry( if (JumpTableArch == Triple::x86 || JumpTableArch == Triple::x86_64) { AsmOS << "jmp ${" << ArgIndex << ":c}@plt\n"; AsmOS << "int3\nint3\nint3\n"; - } else if (JumpTableArch == Triple::arm || JumpTableArch == Triple::aarch64) { + } else if (JumpTableArch == Triple::arm) { + AsmOS << "b $" << ArgIndex << "\n"; + } else if (JumpTableArch == Triple::aarch64) { + if (const auto *BTE = mdconst::extract_or_null( + Dest->getParent()->getModuleFlag("branch-target-enforcement"))) + if (BTE->getZExtValue()) + AsmOS << "bti c\n"; AsmOS << "b $" << ArgIndex << "\n"; } else if (JumpTableArch == Triple::thumb) { AsmOS << "b.w $" << ArgIndex << "\n"; @@ -1326,7 +1338,7 @@ void LowerTypeTestsModule::replaceWeakDeclarationWithJumpTablePtr( static bool isThumbFunction(Function *F, Triple::ArchType ModuleArch) { Attribute TFAttr = F->getFnAttribute("target-features"); - if (!TFAttr.hasAttribute(Attribute::None)) { + if (TFAttr.isValid()) { SmallVector Features; TFAttr.getValueAsString().split(Features, ','); for (StringRef Feature : Features) { @@ -1394,6 +1406,10 @@ void LowerTypeTestsModule::createJumpTable( // by Clang for -march=armv7. F->addFnAttr("target-cpu", "cortex-a8"); } + if (JumpTableArch == Triple::aarch64) { + F->addFnAttr("branch-target-enforcement", "false"); + F->addFnAttr("sign-return-address", "none"); + } // Make sure we don't emit .eh_frame for this function. F->addFnAttr(Attribute::NoUnwind); @@ -2239,9 +2255,13 @@ bool LowerTypeTestsModule::lower() { PreservedAnalyses LowerTypeTestsPass::run(Module &M, ModuleAnalysisManager &AM) { - bool Changed = - LowerTypeTestsModule(M, ExportSummary, ImportSummary, DropTypeTests) - .lower(); + bool Changed; + if (UseCommandLine) + Changed = LowerTypeTestsModule::runForTesting(M); + else + Changed = + LowerTypeTestsModule(M, ExportSummary, ImportSummary, DropTypeTests) + .lower(); if (!Changed) return PreservedAnalyses::all(); return PreservedAnalyses::none(); diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp index 8cc19515f3db..ec5d86b72a1f 100644 --- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp +++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp @@ -725,8 +725,10 @@ void MergeFunctions::writeThunk(Function *F, Function *G) { if (MergeFunctionsPDI) { DISubprogram *DIS = G->getSubprogram(); if (DIS) { - DebugLoc CIDbgLoc = DebugLoc::get(DIS->getScopeLine(), 0, DIS); - DebugLoc RIDbgLoc = DebugLoc::get(DIS->getScopeLine(), 0, DIS); + DebugLoc CIDbgLoc = + DILocation::get(DIS->getContext(), DIS->getScopeLine(), 0, DIS); + DebugLoc RIDbgLoc = + DILocation::get(DIS->getContext(), DIS->getScopeLine(), 0, DIS); CI->setDebugLoc(CIDbgLoc); RI->setDebugLoc(RIDbgLoc); } else { diff --git a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp index f664a2417374..a5ba6edb9a00 100644 --- a/llvm/lib/Transforms/IPO/OpenMPOpt.cpp +++ b/llvm/lib/Transforms/IPO/OpenMPOpt.cpp @@ -19,13 +19,16 @@ #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CallGraphSCCPass.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/Attributor.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/CallGraphUpdater.h" +#include "llvm/Transforms/Utils/CodeExtractor.h" using namespace llvm; using namespace omp; @@ -37,11 +40,22 @@ static cl::opt DisableOpenMPOptimizations( cl::desc("Disable OpenMP specific optimizations."), cl::Hidden, cl::init(false)); +static cl::opt EnableParallelRegionMerging( + "openmp-opt-enable-merging", cl::ZeroOrMore, + cl::desc("Enable the OpenMP region merging optimization."), cl::Hidden, + cl::init(false)); + static cl::opt PrintICVValues("openmp-print-icv-values", cl::init(false), cl::Hidden); static cl::opt PrintOpenMPKernels("openmp-print-gpu-kernels", cl::init(false), cl::Hidden); +static cl::opt HideMemoryTransferLatency( + "openmp-hide-memory-transfer-latency", + cl::desc("[WIP] Tries to hide the latency of host to device memory" + " transfers"), + cl::Hidden, cl::init(false)); + STATISTIC(NumOpenMPRuntimeCallsDeduplicated, "Number of OpenMP runtime calls deduplicated"); STATISTIC(NumOpenMPParallelRegionsDeleted, @@ -55,70 +69,13 @@ STATISTIC(NumOpenMPTargetRegionKernels, STATISTIC( NumOpenMPParallelRegionsReplacedInGPUStateMachine, "Number of OpenMP parallel regions replaced with ID in GPU state machines"); +STATISTIC(NumOpenMPParallelRegionsMerged, + "Number of OpenMP parallel regions merged"); #if !defined(NDEBUG) static constexpr auto TAG = "[" DEBUG_TYPE "]"; #endif -/// Apply \p CB to all uses of \p F. If \p LookThroughConstantExprUses is -/// true, constant expression users are not given to \p CB but their uses are -/// traversed transitively. -template -static void foreachUse(Function &F, CBTy CB, - bool LookThroughConstantExprUses = true) { - SmallVector Worklist(make_pointer_range(F.uses())); - - for (unsigned idx = 0; idx < Worklist.size(); ++idx) { - Use &U = *Worklist[idx]; - - // Allow use in constant bitcasts and simply look through them. - if (LookThroughConstantExprUses && isa(U.getUser())) { - for (Use &CEU : cast(U.getUser())->uses()) - Worklist.push_back(&CEU); - continue; - } - - CB(U); - } -} - -/// Helper struct to store tracked ICV values at specif instructions. -struct ICVValue { - Instruction *Inst; - Value *TrackedValue; - - ICVValue(Instruction *I, Value *Val) : Inst(I), TrackedValue(Val) {} -}; - -namespace llvm { - -// Provide DenseMapInfo for ICVValue -template <> struct DenseMapInfo { - using InstInfo = DenseMapInfo; - using ValueInfo = DenseMapInfo; - - static inline ICVValue getEmptyKey() { - return ICVValue(InstInfo::getEmptyKey(), ValueInfo::getEmptyKey()); - }; - - static inline ICVValue getTombstoneKey() { - return ICVValue(InstInfo::getTombstoneKey(), ValueInfo::getTombstoneKey()); - }; - - static unsigned getHashValue(const ICVValue &ICVVal) { - return detail::combineHashValue( - InstInfo::getHashValue(ICVVal.Inst), - ValueInfo::getHashValue(ICVVal.TrackedValue)); - } - - static bool isEqual(const ICVValue &LHS, const ICVValue &RHS) { - return InstInfo::isEqual(LHS.Inst, RHS.Inst) && - ValueInfo::isEqual(LHS.TrackedValue, RHS.TrackedValue); - } -}; - -} // end namespace llvm - namespace { struct AAICVTracker; @@ -131,7 +88,6 @@ struct OMPInformationCache : public InformationCache { SmallPtrSetImpl &Kernels) : InformationCache(M, AG, Allocator, &CGSCC), OMPBuilder(M), Kernels(Kernels) { - initializeModuleSlice(CGSCC); OMPBuilder.initialize(); initializeRuntimeFunctions(); @@ -258,46 +214,6 @@ struct OMPInformationCache : public InformationCache { DenseMap> UsesMap; }; - /// Initialize the ModuleSlice member based on \p SCC. ModuleSlices contains - /// (a subset of) all functions that we can look at during this SCC traversal. - /// This includes functions (transitively) called from the SCC and the - /// (transitive) callers of SCC functions. We also can look at a function if - /// there is a "reference edge", i.a., if the function somehow uses (!=calls) - /// a function in the SCC or a caller of a function in the SCC. - void initializeModuleSlice(SetVector &SCC) { - ModuleSlice.insert(SCC.begin(), SCC.end()); - - SmallPtrSet Seen; - SmallVector Worklist(SCC.begin(), SCC.end()); - while (!Worklist.empty()) { - Function *F = Worklist.pop_back_val(); - ModuleSlice.insert(F); - - for (Instruction &I : instructions(*F)) - if (auto *CB = dyn_cast(&I)) - if (Function *Callee = CB->getCalledFunction()) - if (Seen.insert(Callee).second) - Worklist.push_back(Callee); - } - - Seen.clear(); - Worklist.append(SCC.begin(), SCC.end()); - while (!Worklist.empty()) { - Function *F = Worklist.pop_back_val(); - ModuleSlice.insert(F); - - // Traverse all transitive uses. - foreachUse(*F, [&](Use &U) { - if (auto *UsrI = dyn_cast(U.getUser())) - if (Seen.insert(UsrI->getFunction()).second) - Worklist.push_back(UsrI->getFunction()); - }); - } - } - - /// The slice of the module we are allowed to look at. - SmallPtrSet ModuleSlice; - /// An OpenMP-IR-Builder instance OpenMPIRBuilder OMPBuilder; @@ -402,13 +318,17 @@ struct OMPInformationCache : public InformationCache { return NumUses; } + // Helper function to recollect uses of a runtime function. + void recollectUsesForFunction(RuntimeFunction RTF) { + auto &RFI = RFIs[RTF]; + RFI.clearUsesMap(); + collectUses(RFI, /*CollectStats*/ false); + } + // Helper function to recollect uses of all runtime functions. void recollectUses() { - for (int Idx = 0; Idx < RFIs.size(); ++Idx) { - auto &RFI = RFIs[static_cast(Idx)]; - RFI.clearUsesMap(); - collectUses(RFI, /*CollectStats*/ false); - } + for (int Idx = 0; Idx < RFIs.size(); ++Idx) + recollectUsesForFunction(static_cast(Idx)); } /// Helper to initialize all runtime function information for those defined @@ -472,6 +392,91 @@ struct OMPInformationCache : public InformationCache { SmallPtrSetImpl &Kernels; }; +/// Used to map the values physically (in the IR) stored in an offload +/// array, to a vector in memory. +struct OffloadArray { + /// Physical array (in the IR). + AllocaInst *Array = nullptr; + /// Mapped values. + SmallVector StoredValues; + /// Last stores made in the offload array. + SmallVector LastAccesses; + + OffloadArray() = default; + + /// Initializes the OffloadArray with the values stored in \p Array before + /// instruction \p Before is reached. Returns false if the initialization + /// fails. + /// This MUST be used immediately after the construction of the object. + bool initialize(AllocaInst &Array, Instruction &Before) { + if (!Array.getAllocatedType()->isArrayTy()) + return false; + + if (!getValues(Array, Before)) + return false; + + this->Array = &Array; + return true; + } + + static const unsigned DeviceIDArgNum = 1; + static const unsigned BasePtrsArgNum = 3; + static const unsigned PtrsArgNum = 4; + static const unsigned SizesArgNum = 5; + +private: + /// Traverses the BasicBlock where \p Array is, collecting the stores made to + /// \p Array, leaving StoredValues with the values stored before the + /// instruction \p Before is reached. + bool getValues(AllocaInst &Array, Instruction &Before) { + // Initialize container. + const uint64_t NumValues = Array.getAllocatedType()->getArrayNumElements(); + StoredValues.assign(NumValues, nullptr); + LastAccesses.assign(NumValues, nullptr); + + // TODO: This assumes the instruction \p Before is in the same + // BasicBlock as Array. Make it general, for any control flow graph. + BasicBlock *BB = Array.getParent(); + if (BB != Before.getParent()) + return false; + + const DataLayout &DL = Array.getModule()->getDataLayout(); + const unsigned int PointerSize = DL.getPointerSize(); + + for (Instruction &I : *BB) { + if (&I == &Before) + break; + + if (!isa(&I)) + continue; + + auto *S = cast(&I); + int64_t Offset = -1; + auto *Dst = + GetPointerBaseWithConstantOffset(S->getPointerOperand(), Offset, DL); + if (Dst == &Array) { + int64_t Idx = Offset / PointerSize; + StoredValues[Idx] = getUnderlyingObject(S->getValueOperand()); + LastAccesses[Idx] = S; + } + } + + return isFilled(); + } + + /// Returns true if all values in StoredValues and + /// LastAccesses are not nullptrs. + bool isFilled() { + const unsigned NumValues = StoredValues.size(); + for (unsigned I = 0; I < NumValues; ++I) { + if (!StoredValues[I] || !LastAccesses[I]) + return false; + } + + return true; + } +}; + struct OpenMPOpt { using OptimizationRemarkGetter = @@ -483,6 +488,12 @@ struct OpenMPOpt { : M(*(*SCC.begin())->getParent()), SCC(SCC), CGUpdater(CGUpdater), OREGetter(OREGetter), OMPInfoCache(OMPInfoCache), A(A) {} + /// Check if any remarks are enabled for openmp-opt + bool remarksEnabled() { + auto &Ctx = M.getContext(); + return Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(DEBUG_TYPE); + } + /// Run all OpenMP optimizations on the underlying SCC/ModuleSlice. bool run() { if (SCC.empty()) @@ -506,8 +517,18 @@ struct OpenMPOpt { // Recollect uses, in case Attributor deleted any. OMPInfoCache.recollectUses(); - Changed |= deduplicateRuntimeCalls(); Changed |= deleteParallelRegions(); + if (HideMemoryTransferLatency) + Changed |= hideMemTransfersLatency(); + if (remarksEnabled()) + analysisGlobalization(); + Changed |= deduplicateRuntimeCalls(); + if (EnableParallelRegionMerging) { + if (mergeParallelRegions()) { + deduplicateRuntimeCalls(); + Changed = true; + } + } return Changed; } @@ -515,7 +536,8 @@ struct OpenMPOpt { /// Print initial ICV values for testing. /// FIXME: This should be done from the Attributor once it is added. void printICVs() const { - InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel}; + InternalControlVar ICVs[] = {ICV_nthreads, ICV_active_levels, ICV_cancel, + ICV_proc_bind}; for (Function *F : OMPInfoCache.ModuleSlice) { for (auto ICV : ICVs) { @@ -571,6 +593,394 @@ struct OpenMPOpt { } private: + /// Merge parallel regions when it is safe. + bool mergeParallelRegions() { + const unsigned CallbackCalleeOperand = 2; + const unsigned CallbackFirstArgOperand = 3; + using InsertPointTy = OpenMPIRBuilder::InsertPointTy; + + // Check if there are any __kmpc_fork_call calls to merge. + OMPInformationCache::RuntimeFunctionInfo &RFI = + OMPInfoCache.RFIs[OMPRTL___kmpc_fork_call]; + + if (!RFI.Declaration) + return false; + + // Unmergable calls that prevent merging a parallel region. + OMPInformationCache::RuntimeFunctionInfo UnmergableCallsInfo[] = { + OMPInfoCache.RFIs[OMPRTL___kmpc_push_proc_bind], + OMPInfoCache.RFIs[OMPRTL___kmpc_push_num_threads], + }; + + bool Changed = false; + LoopInfo *LI = nullptr; + DominatorTree *DT = nullptr; + + SmallDenseMap> BB2PRMap; + + BasicBlock *StartBB = nullptr, *EndBB = nullptr; + auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, + BasicBlock &ContinuationIP) { + BasicBlock *CGStartBB = CodeGenIP.getBlock(); + BasicBlock *CGEndBB = + SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI); + assert(StartBB != nullptr && "StartBB should not be null"); + CGStartBB->getTerminator()->setSuccessor(0, StartBB); + assert(EndBB != nullptr && "EndBB should not be null"); + EndBB->getTerminator()->setSuccessor(0, CGEndBB); + }; + + auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &, + Value &Inner, Value *&ReplacementValue) -> InsertPointTy { + ReplacementValue = &Inner; + return CodeGenIP; + }; + + auto FiniCB = [&](InsertPointTy CodeGenIP) {}; + + /// Create a sequential execution region within a merged parallel region, + /// encapsulated in a master construct with a barrier for synchronization. + auto CreateSequentialRegion = [&](Function *OuterFn, + BasicBlock *OuterPredBB, + Instruction *SeqStartI, + Instruction *SeqEndI) { + // Isolate the instructions of the sequential region to a separate + // block. + BasicBlock *ParentBB = SeqStartI->getParent(); + BasicBlock *SeqEndBB = + SplitBlock(ParentBB, SeqEndI->getNextNode(), DT, LI); + BasicBlock *SeqAfterBB = + SplitBlock(SeqEndBB, &*SeqEndBB->getFirstInsertionPt(), DT, LI); + BasicBlock *SeqStartBB = + SplitBlock(ParentBB, SeqStartI, DT, LI, nullptr, "seq.par.merged"); + + assert(ParentBB->getUniqueSuccessor() == SeqStartBB && + "Expected a different CFG"); + const DebugLoc DL = ParentBB->getTerminator()->getDebugLoc(); + ParentBB->getTerminator()->eraseFromParent(); + + auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, + BasicBlock &ContinuationIP) { + BasicBlock *CGStartBB = CodeGenIP.getBlock(); + BasicBlock *CGEndBB = + SplitBlock(CGStartBB, &*CodeGenIP.getPoint(), DT, LI); + assert(SeqStartBB != nullptr && "SeqStartBB should not be null"); + CGStartBB->getTerminator()->setSuccessor(0, SeqStartBB); + assert(SeqEndBB != nullptr && "SeqEndBB should not be null"); + SeqEndBB->getTerminator()->setSuccessor(0, CGEndBB); + }; + auto FiniCB = [&](InsertPointTy CodeGenIP) {}; + + // Find outputs from the sequential region to outside users and + // broadcast their values to them. + for (Instruction &I : *SeqStartBB) { + SmallPtrSet OutsideUsers; + for (User *Usr : I.users()) { + Instruction &UsrI = *cast(Usr); + // Ignore outputs to LT intrinsics, code extraction for the merged + // parallel region will fix them. + if (UsrI.isLifetimeStartOrEnd()) + continue; + + if (UsrI.getParent() != SeqStartBB) + OutsideUsers.insert(&UsrI); + } + + if (OutsideUsers.empty()) + continue; + + // Emit an alloca in the outer region to store the broadcasted + // value. + const DataLayout &DL = M.getDataLayout(); + AllocaInst *AllocaI = new AllocaInst( + I.getType(), DL.getAllocaAddrSpace(), nullptr, + I.getName() + ".seq.output.alloc", &OuterFn->front().front()); + + // Emit a store instruction in the sequential BB to update the + // value. + new StoreInst(&I, AllocaI, SeqStartBB->getTerminator()); + + // Emit a load instruction and replace the use of the output value + // with it. + for (Instruction *UsrI : OutsideUsers) { + LoadInst *LoadI = new LoadInst(I.getType(), AllocaI, + I.getName() + ".seq.output.load", UsrI); + UsrI->replaceUsesOfWith(&I, LoadI); + } + } + + OpenMPIRBuilder::LocationDescription Loc( + InsertPointTy(ParentBB, ParentBB->end()), DL); + InsertPointTy SeqAfterIP = + OMPInfoCache.OMPBuilder.createMaster(Loc, BodyGenCB, FiniCB); + + OMPInfoCache.OMPBuilder.createBarrier(SeqAfterIP, OMPD_parallel); + + BranchInst::Create(SeqAfterBB, SeqAfterIP.getBlock()); + + LLVM_DEBUG(dbgs() << TAG << "After sequential inlining " << *OuterFn + << "\n"); + }; + + // Helper to merge the __kmpc_fork_call calls in MergableCIs. They are all + // contained in BB and only separated by instructions that can be + // redundantly executed in parallel. The block BB is split before the first + // call (in MergableCIs) and after the last so the entire region we merge + // into a single parallel region is contained in a single basic block + // without any other instructions. We use the OpenMPIRBuilder to outline + // that block and call the resulting function via __kmpc_fork_call. + auto Merge = [&](SmallVectorImpl &MergableCIs, BasicBlock *BB) { + // TODO: Change the interface to allow single CIs expanded, e.g, to + // include an outer loop. + assert(MergableCIs.size() > 1 && "Assumed multiple mergable CIs"); + + auto Remark = [&](OptimizationRemark OR) { + OR << "Parallel region at " + << ore::NV("OpenMPParallelMergeFront", + MergableCIs.front()->getDebugLoc()) + << " merged with parallel regions at "; + for (auto *CI : llvm::drop_begin(MergableCIs)) { + OR << ore::NV("OpenMPParallelMerge", CI->getDebugLoc()); + if (CI != MergableCIs.back()) + OR << ", "; + } + return OR; + }; + + emitRemark(MergableCIs.front(), + "OpenMPParallelRegionMerging", Remark); + + Function *OriginalFn = BB->getParent(); + LLVM_DEBUG(dbgs() << TAG << "Merge " << MergableCIs.size() + << " parallel regions in " << OriginalFn->getName() + << "\n"); + + // Isolate the calls to merge in a separate block. + EndBB = SplitBlock(BB, MergableCIs.back()->getNextNode(), DT, LI); + BasicBlock *AfterBB = + SplitBlock(EndBB, &*EndBB->getFirstInsertionPt(), DT, LI); + StartBB = SplitBlock(BB, MergableCIs.front(), DT, LI, nullptr, + "omp.par.merged"); + + assert(BB->getUniqueSuccessor() == StartBB && "Expected a different CFG"); + const DebugLoc DL = BB->getTerminator()->getDebugLoc(); + BB->getTerminator()->eraseFromParent(); + + // Create sequential regions for sequential instructions that are + // in-between mergable parallel regions. + for (auto *It = MergableCIs.begin(), *End = MergableCIs.end() - 1; + It != End; ++It) { + Instruction *ForkCI = *It; + Instruction *NextForkCI = *(It + 1); + + // Continue if there are not in-between instructions. + if (ForkCI->getNextNode() == NextForkCI) + continue; + + CreateSequentialRegion(OriginalFn, BB, ForkCI->getNextNode(), + NextForkCI->getPrevNode()); + } + + OpenMPIRBuilder::LocationDescription Loc(InsertPointTy(BB, BB->end()), + DL); + IRBuilder<>::InsertPoint AllocaIP( + &OriginalFn->getEntryBlock(), + OriginalFn->getEntryBlock().getFirstInsertionPt()); + // Create the merged parallel region with default proc binding, to + // avoid overriding binding settings, and without explicit cancellation. + InsertPointTy AfterIP = OMPInfoCache.OMPBuilder.createParallel( + Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, nullptr, nullptr, + OMP_PROC_BIND_default, /* IsCancellable */ false); + BranchInst::Create(AfterBB, AfterIP.getBlock()); + + // Perform the actual outlining. + OMPInfoCache.OMPBuilder.finalize(/* AllowExtractorSinking */ true); + + Function *OutlinedFn = MergableCIs.front()->getCaller(); + + // Replace the __kmpc_fork_call calls with direct calls to the outlined + // callbacks. + SmallVector Args; + for (auto *CI : MergableCIs) { + Value *Callee = + CI->getArgOperand(CallbackCalleeOperand)->stripPointerCasts(); + FunctionType *FT = + cast(Callee->getType()->getPointerElementType()); + Args.clear(); + Args.push_back(OutlinedFn->getArg(0)); + Args.push_back(OutlinedFn->getArg(1)); + for (unsigned U = CallbackFirstArgOperand, E = CI->getNumArgOperands(); + U < E; ++U) + Args.push_back(CI->getArgOperand(U)); + + CallInst *NewCI = CallInst::Create(FT, Callee, Args, "", CI); + if (CI->getDebugLoc()) + NewCI->setDebugLoc(CI->getDebugLoc()); + + // Forward parameter attributes from the callback to the callee. + for (unsigned U = CallbackFirstArgOperand, E = CI->getNumArgOperands(); + U < E; ++U) + for (const Attribute &A : CI->getAttributes().getParamAttributes(U)) + NewCI->addParamAttr( + U - (CallbackFirstArgOperand - CallbackCalleeOperand), A); + + // Emit an explicit barrier to replace the implicit fork-join barrier. + if (CI != MergableCIs.back()) { + // TODO: Remove barrier if the merged parallel region includes the + // 'nowait' clause. + OMPInfoCache.OMPBuilder.createBarrier( + InsertPointTy(NewCI->getParent(), + NewCI->getNextNode()->getIterator()), + OMPD_parallel); + } + + auto Remark = [&](OptimizationRemark OR) { + return OR << "Parallel region at " + << ore::NV("OpenMPParallelMerge", CI->getDebugLoc()) + << " merged with " + << ore::NV("OpenMPParallelMergeFront", + MergableCIs.front()->getDebugLoc()); + }; + if (CI != MergableCIs.front()) + emitRemark(CI, "OpenMPParallelRegionMerging", + Remark); + + CI->eraseFromParent(); + } + + assert(OutlinedFn != OriginalFn && "Outlining failed"); + CGUpdater.registerOutlinedFunction(*OriginalFn, *OutlinedFn); + CGUpdater.reanalyzeFunction(*OriginalFn); + + NumOpenMPParallelRegionsMerged += MergableCIs.size(); + + return true; + }; + + // Helper function that identifes sequences of + // __kmpc_fork_call uses in a basic block. + auto DetectPRsCB = [&](Use &U, Function &F) { + CallInst *CI = getCallIfRegularCall(U, &RFI); + BB2PRMap[CI->getParent()].insert(CI); + + return false; + }; + + BB2PRMap.clear(); + RFI.foreachUse(SCC, DetectPRsCB); + SmallVector, 4> MergableCIsVector; + // Find mergable parallel regions within a basic block that are + // safe to merge, that is any in-between instructions can safely + // execute in parallel after merging. + // TODO: support merging across basic-blocks. + for (auto &It : BB2PRMap) { + auto &CIs = It.getSecond(); + if (CIs.size() < 2) + continue; + + BasicBlock *BB = It.getFirst(); + SmallVector MergableCIs; + + /// Returns true if the instruction is mergable, false otherwise. + /// A terminator instruction is unmergable by definition since merging + /// works within a BB. Instructions before the mergable region are + /// mergable if they are not calls to OpenMP runtime functions that may + /// set different execution parameters for subsequent parallel regions. + /// Instructions in-between parallel regions are mergable if they are not + /// calls to any non-intrinsic function since that may call a non-mergable + /// OpenMP runtime function. + auto IsMergable = [&](Instruction &I, bool IsBeforeMergableRegion) { + // We do not merge across BBs, hence return false (unmergable) if the + // instruction is a terminator. + if (I.isTerminator()) + return false; + + if (!isa(&I)) + return true; + + CallInst *CI = cast(&I); + if (IsBeforeMergableRegion) { + Function *CalledFunction = CI->getCalledFunction(); + if (!CalledFunction) + return false; + // Return false (unmergable) if the call before the parallel + // region calls an explicit affinity (proc_bind) or number of + // threads (num_threads) compiler-generated function. Those settings + // may be incompatible with following parallel regions. + // TODO: ICV tracking to detect compatibility. + for (const auto &RFI : UnmergableCallsInfo) { + if (CalledFunction == RFI.Declaration) + return false; + } + } else { + // Return false (unmergable) if there is a call instruction + // in-between parallel regions when it is not an intrinsic. It + // may call an unmergable OpenMP runtime function in its callpath. + // TODO: Keep track of possible OpenMP calls in the callpath. + if (!isa(CI)) + return false; + } + + return true; + }; + // Find maximal number of parallel region CIs that are safe to merge. + for (auto It = BB->begin(), End = BB->end(); It != End;) { + Instruction &I = *It; + ++It; + + if (CIs.count(&I)) { + MergableCIs.push_back(cast(&I)); + continue; + } + + // Continue expanding if the instruction is mergable. + if (IsMergable(I, MergableCIs.empty())) + continue; + + // Forward the instruction iterator to skip the next parallel region + // since there is an unmergable instruction which can affect it. + for (; It != End; ++It) { + Instruction &SkipI = *It; + if (CIs.count(&SkipI)) { + LLVM_DEBUG(dbgs() << TAG << "Skip parallel region " << SkipI + << " due to " << I << "\n"); + ++It; + break; + } + } + + // Store mergable regions found. + if (MergableCIs.size() > 1) { + MergableCIsVector.push_back(MergableCIs); + LLVM_DEBUG(dbgs() << TAG << "Found " << MergableCIs.size() + << " parallel regions in block " << BB->getName() + << " of function " << BB->getParent()->getName() + << "\n";); + } + + MergableCIs.clear(); + } + + if (!MergableCIsVector.empty()) { + Changed = true; + + for (auto &MergableCIs : MergableCIsVector) + Merge(MergableCIs, BB); + } + } + + if (Changed) { + /// Re-collect use for fork calls, emitted barrier calls, and + /// any emitted master/end_master calls. + OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_fork_call); + OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_barrier); + OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_master); + OMPInfoCache.recollectUsesForFunction(OMPRTL___kmpc_end_master); + } + + return Changed; + } + /// Try to delete parallel regions if possible. bool deleteParallelRegions() { const unsigned CallbackCalleeOperand = 2; @@ -648,8 +1058,8 @@ private: for (Function *F : SCC) { for (auto DeduplicableRuntimeCallID : DeduplicableRuntimeCallIDs) - deduplicateRuntimeCalls(*F, - OMPInfoCache.RFIs[DeduplicableRuntimeCallID]); + Changed |= deduplicateRuntimeCalls( + *F, OMPInfoCache.RFIs[DeduplicableRuntimeCallID]); // __kmpc_global_thread_num is special as we can replace it with an // argument in enough cases to make it worth trying. @@ -666,6 +1076,223 @@ private: return Changed; } + /// Tries to hide the latency of runtime calls that involve host to + /// device memory transfers by splitting them into their "issue" and "wait" + /// versions. The "issue" is moved upwards as much as possible. The "wait" is + /// moved downards as much as possible. The "issue" issues the memory transfer + /// asynchronously, returning a handle. The "wait" waits in the returned + /// handle for the memory transfer to finish. + bool hideMemTransfersLatency() { + auto &RFI = OMPInfoCache.RFIs[OMPRTL___tgt_target_data_begin_mapper]; + bool Changed = false; + auto SplitMemTransfers = [&](Use &U, Function &Decl) { + auto *RTCall = getCallIfRegularCall(U, &RFI); + if (!RTCall) + return false; + + OffloadArray OffloadArrays[3]; + if (!getValuesInOffloadArrays(*RTCall, OffloadArrays)) + return false; + + LLVM_DEBUG(dumpValuesInOffloadArrays(OffloadArrays)); + + // TODO: Check if can be moved upwards. + bool WasSplit = false; + Instruction *WaitMovementPoint = canBeMovedDownwards(*RTCall); + if (WaitMovementPoint) + WasSplit = splitTargetDataBeginRTC(*RTCall, *WaitMovementPoint); + + Changed |= WasSplit; + return WasSplit; + }; + RFI.foreachUse(SCC, SplitMemTransfers); + + return Changed; + } + + void analysisGlobalization() { + RuntimeFunction GlobalizationRuntimeIDs[] = { + OMPRTL___kmpc_data_sharing_coalesced_push_stack, + OMPRTL___kmpc_data_sharing_push_stack}; + + for (const auto GlobalizationCallID : GlobalizationRuntimeIDs) { + auto &RFI = OMPInfoCache.RFIs[GlobalizationCallID]; + + auto CheckGlobalization = [&](Use &U, Function &Decl) { + if (CallInst *CI = getCallIfRegularCall(U, &RFI)) { + auto Remark = [&](OptimizationRemarkAnalysis ORA) { + return ORA + << "Found thread data sharing on the GPU. " + << "Expect degraded performance due to data globalization."; + }; + emitRemark(CI, "OpenMPGlobalization", + Remark); + } + + return false; + }; + + RFI.foreachUse(SCC, CheckGlobalization); + } + } + + /// Maps the values stored in the offload arrays passed as arguments to + /// \p RuntimeCall into the offload arrays in \p OAs. + bool getValuesInOffloadArrays(CallInst &RuntimeCall, + MutableArrayRef OAs) { + assert(OAs.size() == 3 && "Need space for three offload arrays!"); + + // A runtime call that involves memory offloading looks something like: + // call void @__tgt_target_data_begin_mapper(arg0, arg1, + // i8** %offload_baseptrs, i8** %offload_ptrs, i64* %offload_sizes, + // ...) + // So, the idea is to access the allocas that allocate space for these + // offload arrays, offload_baseptrs, offload_ptrs, offload_sizes. + // Therefore: + // i8** %offload_baseptrs. + Value *BasePtrsArg = + RuntimeCall.getArgOperand(OffloadArray::BasePtrsArgNum); + // i8** %offload_ptrs. + Value *PtrsArg = RuntimeCall.getArgOperand(OffloadArray::PtrsArgNum); + // i8** %offload_sizes. + Value *SizesArg = RuntimeCall.getArgOperand(OffloadArray::SizesArgNum); + + // Get values stored in **offload_baseptrs. + auto *V = getUnderlyingObject(BasePtrsArg); + if (!isa(V)) + return false; + auto *BasePtrsArray = cast(V); + if (!OAs[0].initialize(*BasePtrsArray, RuntimeCall)) + return false; + + // Get values stored in **offload_baseptrs. + V = getUnderlyingObject(PtrsArg); + if (!isa(V)) + return false; + auto *PtrsArray = cast(V); + if (!OAs[1].initialize(*PtrsArray, RuntimeCall)) + return false; + + // Get values stored in **offload_sizes. + V = getUnderlyingObject(SizesArg); + // If it's a [constant] global array don't analyze it. + if (isa(V)) + return isa(V); + if (!isa(V)) + return false; + + auto *SizesArray = cast(V); + if (!OAs[2].initialize(*SizesArray, RuntimeCall)) + return false; + + return true; + } + + /// Prints the values in the OffloadArrays \p OAs using LLVM_DEBUG. + /// For now this is a way to test that the function getValuesInOffloadArrays + /// is working properly. + /// TODO: Move this to a unittest when unittests are available for OpenMPOpt. + void dumpValuesInOffloadArrays(ArrayRef OAs) { + assert(OAs.size() == 3 && "There are three offload arrays to debug!"); + + LLVM_DEBUG(dbgs() << TAG << " Successfully got offload values:\n"); + std::string ValuesStr; + raw_string_ostream Printer(ValuesStr); + std::string Separator = " --- "; + + for (auto *BP : OAs[0].StoredValues) { + BP->print(Printer); + Printer << Separator; + } + LLVM_DEBUG(dbgs() << "\t\toffload_baseptrs: " << Printer.str() << "\n"); + ValuesStr.clear(); + + for (auto *P : OAs[1].StoredValues) { + P->print(Printer); + Printer << Separator; + } + LLVM_DEBUG(dbgs() << "\t\toffload_ptrs: " << Printer.str() << "\n"); + ValuesStr.clear(); + + for (auto *S : OAs[2].StoredValues) { + S->print(Printer); + Printer << Separator; + } + LLVM_DEBUG(dbgs() << "\t\toffload_sizes: " << Printer.str() << "\n"); + } + + /// Returns the instruction where the "wait" counterpart \p RuntimeCall can be + /// moved. Returns nullptr if the movement is not possible, or not worth it. + Instruction *canBeMovedDownwards(CallInst &RuntimeCall) { + // FIXME: This traverses only the BasicBlock where RuntimeCall is. + // Make it traverse the CFG. + + Instruction *CurrentI = &RuntimeCall; + bool IsWorthIt = false; + while ((CurrentI = CurrentI->getNextNode())) { + + // TODO: Once we detect the regions to be offloaded we should use the + // alias analysis manager to check if CurrentI may modify one of + // the offloaded regions. + if (CurrentI->mayHaveSideEffects() || CurrentI->mayReadFromMemory()) { + if (IsWorthIt) + return CurrentI; + + return nullptr; + } + + // FIXME: For now if we move it over anything without side effect + // is worth it. + IsWorthIt = true; + } + + // Return end of BasicBlock. + return RuntimeCall.getParent()->getTerminator(); + } + + /// Splits \p RuntimeCall into its "issue" and "wait" counterparts. + bool splitTargetDataBeginRTC(CallInst &RuntimeCall, + Instruction &WaitMovementPoint) { + // Create stack allocated handle (__tgt_async_info) at the beginning of the + // function. Used for storing information of the async transfer, allowing to + // wait on it later. + auto &IRBuilder = OMPInfoCache.OMPBuilder; + auto *F = RuntimeCall.getCaller(); + Instruction *FirstInst = &(F->getEntryBlock().front()); + AllocaInst *Handle = new AllocaInst( + IRBuilder.AsyncInfo, F->getAddressSpace(), "handle", FirstInst); + + // Add "issue" runtime call declaration: + // declare %struct.tgt_async_info @__tgt_target_data_begin_issue(i64, i32, + // i8**, i8**, i64*, i64*) + FunctionCallee IssueDecl = IRBuilder.getOrCreateRuntimeFunction( + M, OMPRTL___tgt_target_data_begin_mapper_issue); + + // Change RuntimeCall call site for its asynchronous version. + SmallVector Args; + for (auto &Arg : RuntimeCall.args()) + Args.push_back(Arg.get()); + Args.push_back(Handle); + + CallInst *IssueCallsite = + CallInst::Create(IssueDecl, Args, /*NameStr=*/"", &RuntimeCall); + RuntimeCall.eraseFromParent(); + + // Add "wait" runtime call declaration: + // declare void @__tgt_target_data_begin_wait(i64, %struct.__tgt_async_info) + FunctionCallee WaitDecl = IRBuilder.getOrCreateRuntimeFunction( + M, OMPRTL___tgt_target_data_begin_mapper_wait); + + Value *WaitParams[2] = { + IssueCallsite->getArgOperand( + OffloadArray::DeviceIDArgNum), // device_id. + Handle // handle to wait on. + }; + CallInst::Create(WaitDecl, WaitParams, /*NameStr=*/"", &WaitMovementPoint); + + return true; + } + static Value *combinedIdentStruct(Value *CurrentIdent, Value *NextIdent, bool GlobalOnly, bool &SingleChoice) { if (CurrentIdent == NextIdent) @@ -951,11 +1578,28 @@ private: /// Populate the Attributor with abstract attribute opportunities in the /// function. void registerAAs() { - for (Function *F : SCC) { - if (F->isDeclaration()) - continue; + if (SCC.empty()) + return; + + // Create CallSite AA for all Getters. + for (int Idx = 0; Idx < OMPInfoCache.ICVs.size() - 1; ++Idx) { + auto ICVInfo = OMPInfoCache.ICVs[static_cast(Idx)]; + + auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter]; + + auto CreateAA = [&](Use &U, Function &Caller) { + CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI); + if (!CI) + return false; + + auto &CB = cast(*CI); + + IRPosition CBPos = IRPosition::callsite_function(CB); + A.getOrCreateAAFor(CBPos); + return false; + }; - A.getOrCreateAAFor(IRPosition::function(*F)); + GetterRFI.foreachUse(SCC, CreateAA); } } }; @@ -979,8 +1623,16 @@ Kernel OpenMPOpt::getUniqueKernelFor(Function &F) { } CachedKernel = nullptr; - if (!F.hasLocalLinkage()) + if (!F.hasLocalLinkage()) { + + // See https://openmp.llvm.org/remarks/OptimizationRemarks.html + auto Remark = [&](OptimizationRemark OR) { + return OR << "[OMP100] Potentially unknown OpenMP target region caller"; + }; + emitRemarkOnFunction(&F, "OMP100", Remark); + return nullptr; + } } auto GetUniqueKernelForUse = [&](const Use &U) -> Kernel { @@ -1006,7 +1658,7 @@ Kernel OpenMPOpt::getUniqueKernelFor(Function &F) { // TODO: In the future we want to track more than just a unique kernel. SmallPtrSet PotentialKernels; - foreachUse(F, [&](const Use &U) { + OMPInformationCache::foreachUse(F, [&](const Use &U) { PotentialKernels.insert(GetUniqueKernelForUse(U)); }); @@ -1037,7 +1689,7 @@ bool OpenMPOpt::rewriteDeviceCodeStateMachine() { unsigned NumDirectCalls = 0; SmallVector ToBeReplacedStateMachineUses; - foreachUse(*F, [&](Use &U) { + OMPInformationCache::foreachUse(*F, [&](Use &U) { if (auto *CB = dyn_cast(U.getUser())) if (CB->isCallee(&U)) { ++NumDirectCalls; @@ -1157,6 +1809,12 @@ struct AAICVTracker : public StateWrapper { using Base = StateWrapper; AAICVTracker(const IRPosition &IRP, Attributor &A) : Base(IRP) {} + void initialize(Attributor &A) override { + Function *F = getAnchorScope(); + if (!F || !A.isFunctionIPOAmendable(*F)) + indicatePessimisticFixpoint(); + } + /// Returns true if value is assumed to be tracked. bool isAssumedTracked() const { return getAssumed(); } @@ -1167,8 +1825,21 @@ struct AAICVTracker : public StateWrapper { static AAICVTracker &createForPosition(const IRPosition &IRP, Attributor &A); /// Return the value with which \p I can be replaced for specific \p ICV. - virtual Value *getReplacementValue(InternalControlVar ICV, - const Instruction *I, Attributor &A) = 0; + virtual Optional getReplacementValue(InternalControlVar ICV, + const Instruction *I, + Attributor &A) const { + return None; + } + + /// Return an assumed unique ICV value if a single candidate is found. If + /// there cannot be one, return a nullptr. If it is not clear yet, return the + /// Optional::NoneType. + virtual Optional + getUniqueReplacementValue(InternalControlVar ICV) const = 0; + + // Currently only nthreads is being tracked. + // this array will only grow with time. + InternalControlVar TrackableICVs[1] = {ICV_nthreads}; /// See AbstractAttribute::getName() const std::string getName() const override { return "AAICVTracker"; } @@ -1189,57 +1860,20 @@ struct AAICVTrackerFunction : public AAICVTracker { : AAICVTracker(IRP, A) {} // FIXME: come up with better string. - const std::string getAsStr() const override { return "ICVTracker"; } + const std::string getAsStr() const override { return "ICVTrackerFunction"; } // FIXME: come up with some stats. void trackStatistics() const override {} - /// TODO: decide whether to deduplicate here, or use current - /// deduplicateRuntimeCalls function. + /// We don't manifest anything for this AA. ChangeStatus manifest(Attributor &A) override { - ChangeStatus Changed = ChangeStatus::UNCHANGED; - - for (InternalControlVar &ICV : TrackableICVs) - if (deduplicateICVGetters(ICV, A)) - Changed = ChangeStatus::CHANGED; - - return Changed; - } - - bool deduplicateICVGetters(InternalControlVar &ICV, Attributor &A) { - auto &OMPInfoCache = static_cast(A.getInfoCache()); - auto &ICVInfo = OMPInfoCache.ICVs[ICV]; - auto &GetterRFI = OMPInfoCache.RFIs[ICVInfo.Getter]; - - bool Changed = false; - - auto ReplaceAndDeleteCB = [&](Use &U, Function &Caller) { - CallInst *CI = OpenMPOpt::getCallIfRegularCall(U, &GetterRFI); - Instruction *UserI = cast(U.getUser()); - Value *ReplVal = getReplacementValue(ICV, UserI, A); - - if (!ReplVal || !CI) - return false; - - A.removeCallSite(CI); - CI->replaceAllUsesWith(ReplVal); - CI->eraseFromParent(); - Changed = true; - return true; - }; - - GetterRFI.foreachUse(ReplaceAndDeleteCB, getAnchorScope()); - return Changed; + return ChangeStatus::UNCHANGED; } // Map of ICV to their values at specific program point. - EnumeratedArray, InternalControlVar, + EnumeratedArray, InternalControlVar, InternalControlVar::ICV___last> - ICVValuesMap; - - // Currently only nthreads is being tracked. - // this array will only grow with time. - InternalControlVar TrackableICVs[1] = {ICV_nthreads}; + ICVReplacementValuesMap; ChangeStatus updateImpl(Attributor &A) override { ChangeStatus HasChanged = ChangeStatus::UNCHANGED; @@ -1251,6 +1885,7 @@ struct AAICVTrackerFunction : public AAICVTracker { for (InternalControlVar ICV : TrackableICVs) { auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter]; + auto &ValuesMap = ICVReplacementValuesMap[ICV]; auto TrackValues = [&](Use &U, Function &) { CallInst *CI = OpenMPOpt::getCallIfRegularCall(U); if (!CI) @@ -1258,51 +1893,342 @@ struct AAICVTrackerFunction : public AAICVTracker { // FIXME: handle setters with more that 1 arguments. /// Track new value. - if (ICVValuesMap[ICV].insert(ICVValue(CI, CI->getArgOperand(0)))) + if (ValuesMap.insert(std::make_pair(CI, CI->getArgOperand(0))).second) HasChanged = ChangeStatus::CHANGED; return false; }; + auto CallCheck = [&](Instruction &I) { + Optional ReplVal = getValueForCall(A, &I, ICV); + if (ReplVal.hasValue() && + ValuesMap.insert(std::make_pair(&I, *ReplVal)).second) + HasChanged = ChangeStatus::CHANGED; + + return true; + }; + + // Track all changes of an ICV. SetterRFI.foreachUse(TrackValues, F); + + A.checkForAllInstructions(CallCheck, *this, {Instruction::Call}, + /* CheckBBLivenessOnly */ true); + + /// TODO: Figure out a way to avoid adding entry in + /// ICVReplacementValuesMap + Instruction *Entry = &F->getEntryBlock().front(); + if (HasChanged == ChangeStatus::CHANGED && !ValuesMap.count(Entry)) + ValuesMap.insert(std::make_pair(Entry, nullptr)); } return HasChanged; } - /// Return the value with which \p I can be replaced for specific \p ICV. - Value *getReplacementValue(InternalControlVar ICV, const Instruction *I, - Attributor &A) override { - const BasicBlock *CurrBB = I->getParent(); + /// Hepler to check if \p I is a call and get the value for it if it is + /// unique. + Optional getValueForCall(Attributor &A, const Instruction *I, + InternalControlVar &ICV) const { + + const auto *CB = dyn_cast(I); + if (!CB || CB->hasFnAttr("no_openmp") || + CB->hasFnAttr("no_openmp_routines")) + return None; - auto &ValuesSet = ICVValuesMap[ICV]; auto &OMPInfoCache = static_cast(A.getInfoCache()); auto &GetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Getter]; + auto &SetterRFI = OMPInfoCache.RFIs[OMPInfoCache.ICVs[ICV].Setter]; + Function *CalledFunction = CB->getCalledFunction(); - for (const auto &ICVVal : ValuesSet) { - if (CurrBB == ICVVal.Inst->getParent()) { - if (!ICVVal.Inst->comesBefore(I)) - continue; + // Indirect call, assume ICV changes. + if (CalledFunction == nullptr) + return nullptr; + if (CalledFunction == GetterRFI.Declaration) + return None; + if (CalledFunction == SetterRFI.Declaration) { + if (ICVReplacementValuesMap[ICV].count(I)) + return ICVReplacementValuesMap[ICV].lookup(I); - // both instructions are in the same BB and at \p I we know the ICV - // value. - while (I != ICVVal.Inst) { - // we don't yet know if a call might update an ICV. - // TODO: check callsite AA for value. - if (const auto *CB = dyn_cast(I)) - if (CB->getCalledFunction() != GetterRFI.Declaration) + return nullptr; + } + + // Since we don't know, assume it changes the ICV. + if (CalledFunction->isDeclaration()) + return nullptr; + + const auto &ICVTrackingAA = + A.getAAFor(*this, IRPosition::callsite_returned(*CB)); + + if (ICVTrackingAA.isAssumedTracked()) + return ICVTrackingAA.getUniqueReplacementValue(ICV); + + // If we don't know, assume it changes. + return nullptr; + } + + // We don't check unique value for a function, so return None. + Optional + getUniqueReplacementValue(InternalControlVar ICV) const override { + return None; + } + + /// Return the value with which \p I can be replaced for specific \p ICV. + Optional getReplacementValue(InternalControlVar ICV, + const Instruction *I, + Attributor &A) const override { + const auto &ValuesMap = ICVReplacementValuesMap[ICV]; + if (ValuesMap.count(I)) + return ValuesMap.lookup(I); + + SmallVector Worklist; + SmallPtrSet Visited; + Worklist.push_back(I); + + Optional ReplVal; + + while (!Worklist.empty()) { + const Instruction *CurrInst = Worklist.pop_back_val(); + if (!Visited.insert(CurrInst).second) + continue; + + const BasicBlock *CurrBB = CurrInst->getParent(); + + // Go up and look for all potential setters/calls that might change the + // ICV. + while ((CurrInst = CurrInst->getPrevNode())) { + if (ValuesMap.count(CurrInst)) { + Optional NewReplVal = ValuesMap.lookup(CurrInst); + // Unknown value, track new. + if (!ReplVal.hasValue()) { + ReplVal = NewReplVal; + break; + } + + // If we found a new value, we can't know the icv value anymore. + if (NewReplVal.hasValue()) + if (ReplVal != NewReplVal) return nullptr; - I = I->getPrevNode(); + break; } - // No call in between, return the value. - return ICVVal.TrackedValue; + Optional NewReplVal = getValueForCall(A, CurrInst, ICV); + if (!NewReplVal.hasValue()) + continue; + + // Unknown value, track new. + if (!ReplVal.hasValue()) { + ReplVal = NewReplVal; + break; + } + + // if (NewReplVal.hasValue()) + // We found a new value, we can't know the icv value anymore. + if (ReplVal != NewReplVal) + return nullptr; } + + // If we are in the same BB and we have a value, we are done. + if (CurrBB == I->getParent() && ReplVal.hasValue()) + return ReplVal; + + // Go through all predecessors and add terminators for analysis. + for (const BasicBlock *Pred : predecessors(CurrBB)) + if (const Instruction *Terminator = Pred->getTerminator()) + Worklist.push_back(Terminator); } - // No value was tracked. - return nullptr; + return ReplVal; + } +}; + +struct AAICVTrackerFunctionReturned : AAICVTracker { + AAICVTrackerFunctionReturned(const IRPosition &IRP, Attributor &A) + : AAICVTracker(IRP, A) {} + + // FIXME: come up with better string. + const std::string getAsStr() const override { + return "ICVTrackerFunctionReturned"; + } + + // FIXME: come up with some stats. + void trackStatistics() const override {} + + /// We don't manifest anything for this AA. + ChangeStatus manifest(Attributor &A) override { + return ChangeStatus::UNCHANGED; + } + + // Map of ICV to their values at specific program point. + EnumeratedArray, InternalControlVar, + InternalControlVar::ICV___last> + ICVReplacementValuesMap; + + /// Return the value with which \p I can be replaced for specific \p ICV. + Optional + getUniqueReplacementValue(InternalControlVar ICV) const override { + return ICVReplacementValuesMap[ICV]; + } + + ChangeStatus updateImpl(Attributor &A) override { + ChangeStatus Changed = ChangeStatus::UNCHANGED; + const auto &ICVTrackingAA = A.getAAFor( + *this, IRPosition::function(*getAnchorScope())); + + if (!ICVTrackingAA.isAssumedTracked()) + return indicatePessimisticFixpoint(); + + for (InternalControlVar ICV : TrackableICVs) { + Optional &ReplVal = ICVReplacementValuesMap[ICV]; + Optional UniqueICVValue; + + auto CheckReturnInst = [&](Instruction &I) { + Optional NewReplVal = + ICVTrackingAA.getReplacementValue(ICV, &I, A); + + // If we found a second ICV value there is no unique returned value. + if (UniqueICVValue.hasValue() && UniqueICVValue != NewReplVal) + return false; + + UniqueICVValue = NewReplVal; + + return true; + }; + + if (!A.checkForAllInstructions(CheckReturnInst, *this, {Instruction::Ret}, + /* CheckBBLivenessOnly */ true)) + UniqueICVValue = nullptr; + + if (UniqueICVValue == ReplVal) + continue; + + ReplVal = UniqueICVValue; + Changed = ChangeStatus::CHANGED; + } + + return Changed; + } +}; + +struct AAICVTrackerCallSite : AAICVTracker { + AAICVTrackerCallSite(const IRPosition &IRP, Attributor &A) + : AAICVTracker(IRP, A) {} + + void initialize(Attributor &A) override { + Function *F = getAnchorScope(); + if (!F || !A.isFunctionIPOAmendable(*F)) + indicatePessimisticFixpoint(); + + // We only initialize this AA for getters, so we need to know which ICV it + // gets. + auto &OMPInfoCache = static_cast(A.getInfoCache()); + for (InternalControlVar ICV : TrackableICVs) { + auto ICVInfo = OMPInfoCache.ICVs[ICV]; + auto &Getter = OMPInfoCache.RFIs[ICVInfo.Getter]; + if (Getter.Declaration == getAssociatedFunction()) { + AssociatedICV = ICVInfo.Kind; + return; + } + } + + /// Unknown ICV. + indicatePessimisticFixpoint(); + } + + ChangeStatus manifest(Attributor &A) override { + if (!ReplVal.hasValue() || !ReplVal.getValue()) + return ChangeStatus::UNCHANGED; + + A.changeValueAfterManifest(*getCtxI(), **ReplVal); + A.deleteAfterManifest(*getCtxI()); + + return ChangeStatus::CHANGED; + } + + // FIXME: come up with better string. + const std::string getAsStr() const override { return "ICVTrackerCallSite"; } + + // FIXME: come up with some stats. + void trackStatistics() const override {} + + InternalControlVar AssociatedICV; + Optional ReplVal; + + ChangeStatus updateImpl(Attributor &A) override { + const auto &ICVTrackingAA = A.getAAFor( + *this, IRPosition::function(*getAnchorScope())); + + // We don't have any information, so we assume it changes the ICV. + if (!ICVTrackingAA.isAssumedTracked()) + return indicatePessimisticFixpoint(); + + Optional NewReplVal = + ICVTrackingAA.getReplacementValue(AssociatedICV, getCtxI(), A); + + if (ReplVal == NewReplVal) + return ChangeStatus::UNCHANGED; + + ReplVal = NewReplVal; + return ChangeStatus::CHANGED; + } + + // Return the value with which associated value can be replaced for specific + // \p ICV. + Optional + getUniqueReplacementValue(InternalControlVar ICV) const override { + return ReplVal; + } +}; + +struct AAICVTrackerCallSiteReturned : AAICVTracker { + AAICVTrackerCallSiteReturned(const IRPosition &IRP, Attributor &A) + : AAICVTracker(IRP, A) {} + + // FIXME: come up with better string. + const std::string getAsStr() const override { + return "ICVTrackerCallSiteReturned"; + } + + // FIXME: come up with some stats. + void trackStatistics() const override {} + + /// We don't manifest anything for this AA. + ChangeStatus manifest(Attributor &A) override { + return ChangeStatus::UNCHANGED; + } + + // Map of ICV to their values at specific program point. + EnumeratedArray, InternalControlVar, + InternalControlVar::ICV___last> + ICVReplacementValuesMap; + + /// Return the value with which associated value can be replaced for specific + /// \p ICV. + Optional + getUniqueReplacementValue(InternalControlVar ICV) const override { + return ICVReplacementValuesMap[ICV]; + } + + ChangeStatus updateImpl(Attributor &A) override { + ChangeStatus Changed = ChangeStatus::UNCHANGED; + const auto &ICVTrackingAA = A.getAAFor( + *this, IRPosition::returned(*getAssociatedFunction())); + + // We don't have any information, so we assume it changes the ICV. + if (!ICVTrackingAA.isAssumedTracked()) + return indicatePessimisticFixpoint(); + + for (InternalControlVar ICV : TrackableICVs) { + Optional &ReplVal = ICVReplacementValuesMap[ICV]; + Optional NewReplVal = + ICVTrackingAA.getUniqueReplacementValue(ICV); + + if (ReplVal == NewReplVal) + continue; + + ReplVal = NewReplVal; + Changed = ChangeStatus::CHANGED; + } + return Changed; } }; } // namespace @@ -1316,11 +2242,17 @@ AAICVTracker &AAICVTracker::createForPosition(const IRPosition &IRP, case IRPosition::IRP_INVALID: case IRPosition::IRP_FLOAT: case IRPosition::IRP_ARGUMENT: + case IRPosition::IRP_CALL_SITE_ARGUMENT: + llvm_unreachable("ICVTracker can only be created for function position!"); case IRPosition::IRP_RETURNED: + AA = new (A.Allocator) AAICVTrackerFunctionReturned(IRP, A); + break; case IRPosition::IRP_CALL_SITE_RETURNED: - case IRPosition::IRP_CALL_SITE_ARGUMENT: + AA = new (A.Allocator) AAICVTrackerCallSiteReturned(IRP, A); + break; case IRPosition::IRP_CALL_SITE: - llvm_unreachable("ICVTracker can only be created for function position!"); + AA = new (A.Allocator) AAICVTrackerCallSite(IRP, A); + break; case IRPosition::IRP_FUNCTION: AA = new (A.Allocator) AAICVTrackerFunction(IRP, A); break; @@ -1339,10 +2271,21 @@ PreservedAnalyses OpenMPOptPass::run(LazyCallGraph::SCC &C, return PreservedAnalyses::all(); SmallVector SCC; - for (LazyCallGraph::Node &N : C) - SCC.push_back(&N.getFunction()); + // If there are kernels in the module, we have to run on all SCC's. + bool SCCIsInteresting = !OMPInModule.getKernels().empty(); + for (LazyCallGraph::Node &N : C) { + Function *Fn = &N.getFunction(); + SCC.push_back(Fn); + + // Do we already know that the SCC contains kernels, + // or that OpenMP functions are called from this SCC? + if (SCCIsInteresting) + continue; + // If not, let's check that. + SCCIsInteresting |= OMPInModule.containsOMPRuntimeCalls(Fn); + } - if (SCC.empty()) + if (!SCCIsInteresting || SCC.empty()) return PreservedAnalyses::all(); FunctionAnalysisManager &FAM = @@ -1364,7 +2307,6 @@ PreservedAnalyses OpenMPOptPass::run(LazyCallGraph::SCC &C, Attributor A(Functions, InfoCache, CGUpdater); - // TODO: Compute the module slice we are allowed to look at. OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A); bool Changed = OMPOpt.run(); if (Changed) @@ -1401,12 +2343,23 @@ struct OpenMPOptLegacyPass : public CallGraphSCCPass { return false; SmallVector SCC; - for (CallGraphNode *CGN : CGSCC) - if (Function *Fn = CGN->getFunction()) - if (!Fn->isDeclaration()) - SCC.push_back(Fn); + // If there are kernels in the module, we have to run on all SCC's. + bool SCCIsInteresting = !OMPInModule.getKernels().empty(); + for (CallGraphNode *CGN : CGSCC) { + Function *Fn = CGN->getFunction(); + if (!Fn || Fn->isDeclaration()) + continue; + SCC.push_back(Fn); - if (SCC.empty()) + // Do we already know that the SCC contains kernels, + // or that OpenMP functions are called from this SCC? + if (SCCIsInteresting) + continue; + // If not, let's check that. + SCCIsInteresting |= OMPInModule.containsOMPRuntimeCalls(Fn); + } + + if (!SCCIsInteresting || SCC.empty()) return false; CallGraph &CG = getAnalysis().getCallGraph(); @@ -1430,7 +2383,6 @@ struct OpenMPOptLegacyPass : public CallGraphSCCPass { Attributor A(Functions, InfoCache, CGUpdater); - // TODO: Compute the module slice we are allowed to look at. OpenMPOpt OMPOpt(SCC, CGUpdater, OREGetter, InfoCache, A); return OMPOpt.run(); } @@ -1468,13 +2420,19 @@ bool llvm::omp::containsOpenMP(Module &M, OpenMPInModule &OMPInModule) { if (OMPInModule.isKnown()) return OMPInModule; + auto RecordFunctionsContainingUsesOf = [&](Function *F) { + for (User *U : F->users()) + if (auto *I = dyn_cast(U)) + OMPInModule.FuncsWithOMPRuntimeCalls.insert(I->getFunction()); + }; + // MSVC doesn't like long if-else chains for some reason and instead just // issues an error. Work around it.. do { #define OMP_RTL(_Enum, _Name, ...) \ - if (M.getFunction(_Name)) { \ + if (Function *F = M.getFunction(_Name)) { \ + RecordFunctionsContainingUsesOf(F); \ OMPInModule = true; \ - break; \ } #include "llvm/Frontend/OpenMP/OMPKinds.def" } while (false); diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp index 5d863f1330a4..2bbf4bf110ae 100644 --- a/llvm/lib/Transforms/IPO/PartialInlining.cpp +++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp @@ -97,13 +97,6 @@ static cl::opt MarkOutlinedColdCC("pi-mark-coldcc", cl::init(false), cl::Hidden, cl::desc("Mark outline function calls with ColdCC")); -#ifndef NDEBUG -// Command line option to debug partial-inlining. The default is none: -static cl::opt TracePartialInlining("trace-partial-inlining", - cl::init(false), cl::Hidden, - cl::desc("Trace partial inlining.")); -#endif - // This is an option used by testing: static cl::opt SkipCostAnalysis("skip-partial-inlining-cost-analysis", cl::init(false), cl::ZeroOrMore, @@ -159,7 +152,7 @@ struct FunctionOutliningInfo { // Returns the number of blocks to be inlined including all blocks // in Entries and one return block. - unsigned GetNumInlinedBlocks() const { return Entries.size() + 1; } + unsigned getNumInlinedBlocks() const { return Entries.size() + 1; } // A set of blocks including the function entry that guard // the region to be outlined. @@ -215,7 +208,7 @@ struct PartialInlinerImpl { // function (only if we partially inlined early returns) as there is a // possibility to further "peel" early return statements that were left in the // outline function due to code size. - std::pair unswitchFunction(Function *F); + std::pair unswitchFunction(Function &F); // This class speculatively clones the function to be partial inlined. // At the end of partial inlining, the remaining callsites to the cloned @@ -226,16 +219,19 @@ struct PartialInlinerImpl { // multi-region outlining. FunctionCloner(Function *F, FunctionOutliningInfo *OI, OptimizationRemarkEmitter &ORE, - function_ref LookupAC); + function_ref LookupAC, + function_ref GetTTI); FunctionCloner(Function *F, FunctionOutliningMultiRegionInfo *OMRI, OptimizationRemarkEmitter &ORE, - function_ref LookupAC); + function_ref LookupAC, + function_ref GetTTI); + ~FunctionCloner(); // Prepare for function outlining: making sure there is only // one incoming edge from the extracted/outlined region to // the return block. - void NormalizeReturnBlock(); + void normalizeReturnBlock() const; // Do function outlining for cold regions. bool doMultiRegionFunctionOutlining(); @@ -266,6 +262,7 @@ struct PartialInlinerImpl { std::unique_ptr ClonedFuncBFI = nullptr; OptimizationRemarkEmitter &ORE; function_ref LookupAC; + function_ref GetTTI; }; private: @@ -281,13 +278,14 @@ private: // The result is no larger than 1 and is represented using BP. // (Note that the outlined region's 'head' block can only have incoming // edges from the guarding entry blocks). - BranchProbability getOutliningCallBBRelativeFreq(FunctionCloner &Cloner); + BranchProbability + getOutliningCallBBRelativeFreq(FunctionCloner &Cloner) const; // Return true if the callee of CB should be partially inlined with // profit. bool shouldPartialInline(CallBase &CB, FunctionCloner &Cloner, BlockFrequency WeightedOutliningRcost, - OptimizationRemarkEmitter &ORE); + OptimizationRemarkEmitter &ORE) const; // Try to inline DuplicateFunction (cloned from F with call to // the OutlinedFunction into its callers. Return true @@ -296,10 +294,11 @@ private: // Compute the mapping from use site of DuplicationFunction to the enclosing // BB's profile count. - void computeCallsiteToProfCountMap(Function *DuplicateFunction, - DenseMap &SiteCountMap); + void + computeCallsiteToProfCountMap(Function *DuplicateFunction, + DenseMap &SiteCountMap) const; - bool IsLimitReached() { + bool isLimitReached() const { return (MaxNumPartialInlining != -1 && NumPartialInlining >= MaxNumPartialInlining); } @@ -311,12 +310,12 @@ private: return nullptr; } - static CallBase *getOneCallSiteTo(Function *F) { - User *User = *F->user_begin(); + static CallBase *getOneCallSiteTo(Function &F) { + User *User = *F.user_begin(); return getSupportedCallBase(User); } - std::tuple getOneDebugLoc(Function *F) { + std::tuple getOneDebugLoc(Function &F) const { CallBase *CB = getOneCallSiteTo(F); DebugLoc DLoc = CB->getDebugLoc(); BasicBlock *Block = CB->getParent(); @@ -329,16 +328,19 @@ private: // outlined function itself; // - The second value is the estimated size of the new call sequence in // basic block Cloner.OutliningCallBB; - std::tuple computeOutliningCosts(FunctionCloner &Cloner); + std::tuple computeOutliningCosts(FunctionCloner &Cloner) const; // Compute the 'InlineCost' of block BB. InlineCost is a proxy used to // approximate both the size and runtime cost (Note that in the current // inline cost analysis, there is no clear distinction there either). - static int computeBBInlineCost(BasicBlock *BB); + static int computeBBInlineCost(BasicBlock *BB, TargetTransformInfo *TTI); + + std::unique_ptr + computeOutliningInfo(Function &F) const; - std::unique_ptr computeOutliningInfo(Function *F); std::unique_ptr - computeOutliningColdRegionsInfo(Function *F, OptimizationRemarkEmitter &ORE); + computeOutliningColdRegionsInfo(Function &F, + OptimizationRemarkEmitter &ORE) const; }; struct PartialInlinerLegacyPass : public ModulePass { @@ -390,20 +392,20 @@ struct PartialInlinerLegacyPass : public ModulePass { } // end anonymous namespace std::unique_ptr -PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, - OptimizationRemarkEmitter &ORE) { - BasicBlock *EntryBlock = &F->front(); +PartialInlinerImpl::computeOutliningColdRegionsInfo( + Function &F, OptimizationRemarkEmitter &ORE) const { + BasicBlock *EntryBlock = &F.front(); - DominatorTree DT(*F); + DominatorTree DT(F); LoopInfo LI(DT); - BranchProbabilityInfo BPI(*F, LI); + BranchProbabilityInfo BPI(F, LI); std::unique_ptr ScopedBFI; BlockFrequencyInfo *BFI; if (!GetBFI) { - ScopedBFI.reset(new BlockFrequencyInfo(*F, BPI, LI)); + ScopedBFI.reset(new BlockFrequencyInfo(F, BPI, LI)); BFI = ScopedBFI.get(); } else - BFI = &(GetBFI(*F)); + BFI = &(GetBFI(F)); // Return if we don't have profiling information. if (!PSI.hasInstrumentationProfile()) @@ -412,11 +414,6 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, std::unique_ptr OutliningInfo = std::make_unique(); - auto IsSingleEntry = [](SmallVectorImpl &BlockList) { - BasicBlock *Dom = BlockList.front(); - return BlockList.size() > 1 && Dom->hasNPredecessors(1); - }; - auto IsSingleExit = [&ORE](SmallVectorImpl &BlockList) -> BasicBlock * { BasicBlock *ExitBlock = nullptr; @@ -432,8 +429,9 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, << " has more than one region exit edge."; }); return nullptr; - } else - ExitBlock = Block; + } + + ExitBlock = Block; } } } @@ -448,14 +446,14 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, // Use the same computeBBInlineCost function to compute the cost savings of // the outlining the candidate region. + TargetTransformInfo *FTTI = &GetTTI(F); int OverallFunctionCost = 0; - for (auto &BB : *F) - OverallFunctionCost += computeBBInlineCost(&BB); + for (auto &BB : F) + OverallFunctionCost += computeBBInlineCost(&BB, FTTI); + + LLVM_DEBUG(dbgs() << "OverallFunctionCost = " << OverallFunctionCost + << "\n";); -#ifndef NDEBUG - if (TracePartialInlining) - dbgs() << "OverallFunctionCost = " << OverallFunctionCost << "\n"; -#endif int MinOutlineRegionCost = static_cast(OverallFunctionCost * MinRegionSizeRatio); BranchProbability MinBranchProbability( @@ -467,6 +465,7 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, DenseMap VisitedMap; DFS.push_back(CurrEntry); VisitedMap[CurrEntry] = true; + // Use Depth First Search on the basic blocks to find CFG edges that are // considered cold. // Cold regions considered must also have its inline cost compared to the @@ -474,88 +473,98 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, // if it reduced the inline cost of the function by 'MinOutlineRegionCost' or // more. while (!DFS.empty()) { - auto *thisBB = DFS.back(); + auto *ThisBB = DFS.back(); DFS.pop_back(); // Only consider regions with predecessor blocks that are considered // not-cold (default: part of the top 99.99% of all block counters) // AND greater than our minimum block execution count (default: 100). - if (PSI.isColdBlock(thisBB, BFI) || - BBProfileCount(thisBB) < MinBlockCounterExecution) + if (PSI.isColdBlock(ThisBB, BFI) || + BBProfileCount(ThisBB) < MinBlockCounterExecution) continue; - for (auto SI = succ_begin(thisBB); SI != succ_end(thisBB); ++SI) { + for (auto SI = succ_begin(ThisBB); SI != succ_end(ThisBB); ++SI) { if (VisitedMap[*SI]) continue; VisitedMap[*SI] = true; DFS.push_back(*SI); // If branch isn't cold, we skip to the next one. - BranchProbability SuccProb = BPI.getEdgeProbability(thisBB, *SI); + BranchProbability SuccProb = BPI.getEdgeProbability(ThisBB, *SI); if (SuccProb > MinBranchProbability) continue; -#ifndef NDEBUG - if (TracePartialInlining) { - dbgs() << "Found cold edge: " << thisBB->getName() << "->" - << (*SI)->getName() << "\nBranch Probability = " << SuccProb - << "\n"; - } -#endif + + LLVM_DEBUG(dbgs() << "Found cold edge: " << ThisBB->getName() << "->" + << SI->getName() + << "\nBranch Probability = " << SuccProb << "\n";); + SmallVector DominateVector; DT.getDescendants(*SI, DominateVector); + assert(!DominateVector.empty() && + "SI should be reachable and have at least itself as descendant"); + // We can only outline single entry regions (for now). - if (!IsSingleEntry(DominateVector)) + if (!DominateVector.front()->hasNPredecessors(1)) { + LLVM_DEBUG(dbgs() << "ABORT: Block " << SI->getName() + << " doesn't have a single predecessor in the " + "dominator tree\n";); continue; + } + BasicBlock *ExitBlock = nullptr; // We can only outline single exit regions (for now). - if (!(ExitBlock = IsSingleExit(DominateVector))) + if (!(ExitBlock = IsSingleExit(DominateVector))) { + LLVM_DEBUG(dbgs() << "ABORT: Block " << SI->getName() + << " doesn't have a unique successor\n";); continue; + } + int OutlineRegionCost = 0; for (auto *BB : DominateVector) - OutlineRegionCost += computeBBInlineCost(BB); + OutlineRegionCost += computeBBInlineCost(BB, &GetTTI(*BB->getParent())); -#ifndef NDEBUG - if (TracePartialInlining) - dbgs() << "OutlineRegionCost = " << OutlineRegionCost << "\n"; -#endif + LLVM_DEBUG(dbgs() << "OutlineRegionCost = " << OutlineRegionCost + << "\n";); - if (OutlineRegionCost < MinOutlineRegionCost) { + if (!SkipCostAnalysis && OutlineRegionCost < MinOutlineRegionCost) { ORE.emit([&]() { return OptimizationRemarkAnalysis(DEBUG_TYPE, "TooCostly", &SI->front()) - << ore::NV("Callee", F) << " inline cost-savings smaller than " + << ore::NV("Callee", &F) + << " inline cost-savings smaller than " << ore::NV("Cost", MinOutlineRegionCost); }); + + LLVM_DEBUG(dbgs() << "ABORT: Outline region cost is smaller than " + << MinOutlineRegionCost << "\n";); continue; } + // For now, ignore blocks that belong to a SISE region that is a // candidate for outlining. In the future, we may want to look // at inner regions because the outer region may have live-exit // variables. for (auto *BB : DominateVector) VisitedMap[BB] = true; + // ReturnBlock here means the block after the outline call BasicBlock *ReturnBlock = ExitBlock->getSingleSuccessor(); - // assert(ReturnBlock && "ReturnBlock is NULL somehow!"); FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegInfo( DominateVector, DominateVector.front(), ExitBlock, ReturnBlock); OutliningInfo->ORI.push_back(RegInfo); -#ifndef NDEBUG - if (TracePartialInlining) { - dbgs() << "Found Cold Candidate starting at block: " - << DominateVector.front()->getName() << "\n"; - } -#endif + LLVM_DEBUG(dbgs() << "Found Cold Candidate starting at block: " + << DominateVector.front()->getName() << "\n";); ColdCandidateFound = true; NumColdRegionsFound++; } } + if (ColdCandidateFound) return OutliningInfo; - else - return std::unique_ptr(); + + return std::unique_ptr(); } std::unique_ptr -PartialInlinerImpl::computeOutliningInfo(Function *F) { - BasicBlock *EntryBlock = &F->front(); +PartialInlinerImpl::computeOutliningInfo(Function &F) const { + BasicBlock *EntryBlock = &F.front(); BranchInst *BR = dyn_cast(EntryBlock->getTerminator()); if (!BR || BR->isUnconditional()) return std::unique_ptr(); @@ -598,7 +607,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { // The number of blocks to be inlined has already reached // the limit. When MaxNumInlineBlocks is set to 0 or 1, this // disables partial inlining for the function. - if (OutliningInfo->GetNumInlinedBlocks() >= MaxNumInlineBlocks) + if (OutliningInfo->getNumInlinedBlocks() >= MaxNumInlineBlocks) break; if (succ_size(CurrEntry) != 2) @@ -618,8 +627,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { break; } - BasicBlock *CommSucc; - BasicBlock *OtherSucc; + BasicBlock *CommSucc, *OtherSucc; std::tie(CommSucc, OtherSucc) = GetCommonSucc(Succ1, Succ2); if (!CommSucc) @@ -635,7 +643,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { // Do sanity check of the entries: threre should not // be any successors (not in the entry set) other than // {ReturnBlock, NonReturnBlock} - assert(OutliningInfo->Entries[0] == &F->front() && + assert(OutliningInfo->Entries[0] == &F.front() && "Function Entry must be the first in Entries vector"); DenseSet Entries; for (BasicBlock *E : OutliningInfo->Entries) @@ -644,7 +652,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { // Returns true of BB has Predecessor which is not // in Entries set. auto HasNonEntryPred = [Entries](BasicBlock *BB) { - for (auto Pred : predecessors(BB)) { + for (auto *Pred : predecessors(BB)) { if (!Entries.count(Pred)) return true; } @@ -653,7 +661,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { auto CheckAndNormalizeCandidate = [Entries, HasNonEntryPred](FunctionOutliningInfo *OutliningInfo) { for (BasicBlock *E : OutliningInfo->Entries) { - for (auto Succ : successors(E)) { + for (auto *Succ : successors(E)) { if (Entries.count(Succ)) continue; if (Succ == OutliningInfo->ReturnBlock) @@ -673,7 +681,7 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { // Now further growing the candidate's inlining region by // peeling off dominating blocks from the outlining region: - while (OutliningInfo->GetNumInlinedBlocks() < MaxNumInlineBlocks) { + while (OutliningInfo->getNumInlinedBlocks() < MaxNumInlineBlocks) { BasicBlock *Cand = OutliningInfo->NonReturnBlock; if (succ_size(Cand) != 2) break; @@ -703,11 +711,11 @@ PartialInlinerImpl::computeOutliningInfo(Function *F) { } // Check if there is PGO data or user annotated branch data: -static bool hasProfileData(Function *F, FunctionOutliningInfo *OI) { - if (F->hasProfileData()) +static bool hasProfileData(const Function &F, const FunctionOutliningInfo &OI) { + if (F.hasProfileData()) return true; // Now check if any of the entry block has MD_prof data: - for (auto *E : OI->Entries) { + for (auto *E : OI.Entries) { BranchInst *BR = dyn_cast(E->getTerminator()); if (!BR || BR->isUnconditional()) continue; @@ -718,8 +726,8 @@ static bool hasProfileData(Function *F, FunctionOutliningInfo *OI) { return false; } -BranchProbability -PartialInlinerImpl::getOutliningCallBBRelativeFreq(FunctionCloner &Cloner) { +BranchProbability PartialInlinerImpl::getOutliningCallBBRelativeFreq( + FunctionCloner &Cloner) const { BasicBlock *OutliningCallBB = Cloner.OutlinedFunctions.back().second; auto EntryFreq = Cloner.ClonedFuncBFI->getBlockFreq(&Cloner.ClonedFunc->getEntryBlock()); @@ -728,13 +736,13 @@ PartialInlinerImpl::getOutliningCallBBRelativeFreq(FunctionCloner &Cloner) { // FIXME Hackery needed because ClonedFuncBFI is based on the function BEFORE // we outlined any regions, so we may encounter situations where the // OutliningCallFreq is *slightly* bigger than the EntryFreq. - if (OutliningCallFreq.getFrequency() > EntryFreq.getFrequency()) { + if (OutliningCallFreq.getFrequency() > EntryFreq.getFrequency()) OutliningCallFreq = EntryFreq; - } + auto OutlineRegionRelFreq = BranchProbability::getBranchProbability( OutliningCallFreq.getFrequency(), EntryFreq.getFrequency()); - if (hasProfileData(Cloner.OrigFunc, Cloner.ClonedOI.get())) + if (hasProfileData(*Cloner.OrigFunc, *Cloner.ClonedOI.get())) return OutlineRegionRelFreq; // When profile data is not available, we need to be conservative in @@ -760,7 +768,7 @@ PartialInlinerImpl::getOutliningCallBBRelativeFreq(FunctionCloner &Cloner) { bool PartialInlinerImpl::shouldPartialInline( CallBase &CB, FunctionCloner &Cloner, BlockFrequency WeightedOutliningRcost, - OptimizationRemarkEmitter &ORE) { + OptimizationRemarkEmitter &ORE) const { using namespace ore; Function *Callee = CB.getCalledFunction(); @@ -843,7 +851,8 @@ bool PartialInlinerImpl::shouldPartialInline( // TODO: Ideally we should share Inliner's InlineCost Analysis code. // For now use a simplified version. The returned 'InlineCost' will be used // to esimate the size cost as well as runtime cost of the BB. -int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB) { +int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB, + TargetTransformInfo *TTI) { int InlineCost = 0; const DataLayout &DL = BB->getParent()->getParent()->getDataLayout(); for (Instruction &I : BB->instructionsWithoutDebug()) { @@ -866,6 +875,21 @@ int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB) { if (I.isLifetimeStartOrEnd()) continue; + if (auto *II = dyn_cast(&I)) { + Intrinsic::ID IID = II->getIntrinsicID(); + SmallVector Tys; + FastMathFlags FMF; + for (Value *Val : II->args()) + Tys.push_back(Val->getType()); + + if (auto *FPMO = dyn_cast(II)) + FMF = FPMO->getFastMathFlags(); + + IntrinsicCostAttributes ICA(IID, II->getType(), Tys, FMF); + InlineCost += TTI->getIntrinsicInstrCost(ICA, TTI::TCK_SizeAndLatency); + continue; + } + if (CallInst *CI = dyn_cast(&I)) { InlineCost += getCallsiteCost(*CI, DL); continue; @@ -886,18 +910,20 @@ int PartialInlinerImpl::computeBBInlineCost(BasicBlock *BB) { } std::tuple -PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner) { +PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner) const { int OutliningFuncCallCost = 0, OutlinedFunctionCost = 0; for (auto FuncBBPair : Cloner.OutlinedFunctions) { Function *OutlinedFunc = FuncBBPair.first; BasicBlock* OutliningCallBB = FuncBBPair.second; // Now compute the cost of the call sequence to the outlined function // 'OutlinedFunction' in BB 'OutliningCallBB': - OutliningFuncCallCost += computeBBInlineCost(OutliningCallBB); + auto *OutlinedFuncTTI = &GetTTI(*OutlinedFunc); + OutliningFuncCallCost += + computeBBInlineCost(OutliningCallBB, OutlinedFuncTTI); // Now compute the cost of the extracted/outlined function itself: for (BasicBlock &BB : *OutlinedFunc) - OutlinedFunctionCost += computeBBInlineCost(&BB); + OutlinedFunctionCost += computeBBInlineCost(&BB, OutlinedFuncTTI); } assert(OutlinedFunctionCost >= Cloner.OutlinedRegionCost && "Outlined function cost should be no less than the outlined region"); @@ -921,7 +947,7 @@ PartialInlinerImpl::computeOutliningCosts(FunctionCloner &Cloner) { // after the function is partially inlined into the callsite. void PartialInlinerImpl::computeCallsiteToProfCountMap( Function *DuplicateFunction, - DenseMap &CallSiteToProfCountMap) { + DenseMap &CallSiteToProfCountMap) const { std::vector Users(DuplicateFunction->user_begin(), DuplicateFunction->user_end()); Function *CurrentCaller = nullptr; @@ -962,8 +988,9 @@ void PartialInlinerImpl::computeCallsiteToProfCountMap( PartialInlinerImpl::FunctionCloner::FunctionCloner( Function *F, FunctionOutliningInfo *OI, OptimizationRemarkEmitter &ORE, - function_ref LookupAC) - : OrigFunc(F), ORE(ORE), LookupAC(LookupAC) { + function_ref LookupAC, + function_ref GetTTI) + : OrigFunc(F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) { ClonedOI = std::make_unique(); // Clone the function, so that we can hack away on it. @@ -972,9 +999,9 @@ PartialInlinerImpl::FunctionCloner::FunctionCloner( ClonedOI->ReturnBlock = cast(VMap[OI->ReturnBlock]); ClonedOI->NonReturnBlock = cast(VMap[OI->NonReturnBlock]); - for (BasicBlock *BB : OI->Entries) { + for (BasicBlock *BB : OI->Entries) ClonedOI->Entries.push_back(cast(VMap[BB])); - } + for (BasicBlock *E : OI->ReturnBlockPreds) { BasicBlock *NewE = cast(VMap[E]); ClonedOI->ReturnBlockPreds.push_back(NewE); @@ -987,8 +1014,9 @@ PartialInlinerImpl::FunctionCloner::FunctionCloner( PartialInlinerImpl::FunctionCloner::FunctionCloner( Function *F, FunctionOutliningMultiRegionInfo *OI, OptimizationRemarkEmitter &ORE, - function_ref LookupAC) - : OrigFunc(F), ORE(ORE), LookupAC(LookupAC) { + function_ref LookupAC, + function_ref GetTTI) + : OrigFunc(F), ORE(ORE), LookupAC(LookupAC), GetTTI(GetTTI) { ClonedOMRI = std::make_unique(); // Clone the function, so that we can hack away on it. @@ -1000,9 +1028,9 @@ PartialInlinerImpl::FunctionCloner::FunctionCloner( for (FunctionOutliningMultiRegionInfo::OutlineRegionInfo RegionInfo : OI->ORI) { SmallVector Region; - for (BasicBlock *BB : RegionInfo.Region) { + for (BasicBlock *BB : RegionInfo.Region) Region.push_back(cast(VMap[BB])); - } + BasicBlock *NewEntryBlock = cast(VMap[RegionInfo.EntryBlock]); BasicBlock *NewExitBlock = cast(VMap[RegionInfo.ExitBlock]); BasicBlock *NewReturnBlock = nullptr; @@ -1017,8 +1045,8 @@ PartialInlinerImpl::FunctionCloner::FunctionCloner( F->replaceAllUsesWith(ClonedFunc); } -void PartialInlinerImpl::FunctionCloner::NormalizeReturnBlock() { - auto getFirstPHI = [](BasicBlock *BB) { +void PartialInlinerImpl::FunctionCloner::normalizeReturnBlock() const { + auto GetFirstPHI = [](BasicBlock *BB) { BasicBlock::iterator I = BB->begin(); PHINode *FirstPhi = nullptr; while (I != BB->end()) { @@ -1044,7 +1072,7 @@ void PartialInlinerImpl::FunctionCloner::NormalizeReturnBlock() { // of which will go outside. BasicBlock *PreReturn = ClonedOI->ReturnBlock; // only split block when necessary: - PHINode *FirstPhi = getFirstPHI(PreReturn); + PHINode *FirstPhi = GetFirstPHI(PreReturn); unsigned NumPredsFromEntries = ClonedOI->ReturnBlockPreds.size(); if (!FirstPhi || FirstPhi->getNumIncomingValues() <= NumPredsFromEntries + 1) @@ -1092,17 +1120,16 @@ void PartialInlinerImpl::FunctionCloner::NormalizeReturnBlock() { for (auto *DP : DeadPhis) DP->eraseFromParent(); - for (auto E : ClonedOI->ReturnBlockPreds) { + for (auto *E : ClonedOI->ReturnBlockPreds) E->getTerminator()->replaceUsesOfWith(PreReturn, ClonedOI->ReturnBlock); - } } bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() { - auto ComputeRegionCost = [](SmallVectorImpl &Region) { + auto ComputeRegionCost = [&](SmallVectorImpl &Region) { int Cost = 0; for (BasicBlock* BB : Region) - Cost += computeBBInlineCost(BB); + Cost += computeBBInlineCost(BB, &GetTTI(*BB->getParent())); return Cost; }; @@ -1135,24 +1162,21 @@ bool PartialInlinerImpl::FunctionCloner::doMultiRegionFunctionOutlining() { CE.findInputsOutputs(Inputs, Outputs, Sinks); -#ifndef NDEBUG - if (TracePartialInlining) { + LLVM_DEBUG({ dbgs() << "inputs: " << Inputs.size() << "\n"; dbgs() << "outputs: " << Outputs.size() << "\n"; for (Value *value : Inputs) dbgs() << "value used in func: " << *value << "\n"; for (Value *output : Outputs) dbgs() << "instr used in func: " << *output << "\n"; - } -#endif + }); + // Do not extract regions that have live exit variables. if (Outputs.size() > 0 && !ForceLiveExit) continue; - Function *OutlinedFunc = CE.extractCodeRegion(CEAC); - - if (OutlinedFunc) { - CallBase *OCS = PartialInlinerImpl::getOneCallSiteTo(OutlinedFunc); + if (Function *OutlinedFunc = CE.extractCodeRegion(CEAC)) { + CallBase *OCS = PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc); BasicBlock *OutliningCallBB = OCS->getParent(); assert(OutliningCallBB->getParent() == ClonedFunc); OutlinedFunctions.push_back(std::make_pair(OutlinedFunc,OutliningCallBB)); @@ -1181,8 +1205,7 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() { // (i.e. not to be extracted to the out of line function) auto ToBeInlined = [&, this](BasicBlock *BB) { return BB == ClonedOI->ReturnBlock || - (std::find(ClonedOI->Entries.begin(), ClonedOI->Entries.end(), BB) != - ClonedOI->Entries.end()); + llvm::is_contained(ClonedOI->Entries, BB); }; assert(ClonedOI && "Expecting OutlineInfo for single region outline"); @@ -1197,9 +1220,10 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() { // Gather up the blocks that we're going to extract. std::vector ToExtract; + auto *ClonedFuncTTI = &GetTTI(*ClonedFunc); ToExtract.push_back(ClonedOI->NonReturnBlock); - OutlinedRegionCost += - PartialInlinerImpl::computeBBInlineCost(ClonedOI->NonReturnBlock); + OutlinedRegionCost += PartialInlinerImpl::computeBBInlineCost( + ClonedOI->NonReturnBlock, ClonedFuncTTI); for (BasicBlock &BB : *ClonedFunc) if (!ToBeInlined(&BB) && &BB != ClonedOI->NonReturnBlock) { ToExtract.push_back(&BB); @@ -1207,7 +1231,7 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() { // into the outlined function which may make the outlining // overhead (the difference of the outlined function cost // and OutliningRegionCost) look larger. - OutlinedRegionCost += computeBBInlineCost(&BB); + OutlinedRegionCost += computeBBInlineCost(&BB, ClonedFuncTTI); } // Extract the body of the if. @@ -1220,8 +1244,7 @@ PartialInlinerImpl::FunctionCloner::doSingleRegionFunctionOutlining() { if (OutlinedFunc) { BasicBlock *OutliningCallBB = - PartialInlinerImpl::getOneCallSiteTo(OutlinedFunc) - ->getParent(); + PartialInlinerImpl::getOneCallSiteTo(*OutlinedFunc)->getParent(); assert(OutliningCallBB->getParent() == ClonedFunc); OutlinedFunctions.push_back(std::make_pair(OutlinedFunc, OutliningCallBB)); } else @@ -1250,52 +1273,48 @@ PartialInlinerImpl::FunctionCloner::~FunctionCloner() { } } -std::pair PartialInlinerImpl::unswitchFunction(Function *F) { - - if (F->hasAddressTaken()) +std::pair PartialInlinerImpl::unswitchFunction(Function &F) { + if (F.hasAddressTaken()) return {false, nullptr}; // Let inliner handle it - if (F->hasFnAttribute(Attribute::AlwaysInline)) + if (F.hasFnAttribute(Attribute::AlwaysInline)) return {false, nullptr}; - if (F->hasFnAttribute(Attribute::NoInline)) + if (F.hasFnAttribute(Attribute::NoInline)) return {false, nullptr}; - if (PSI.isFunctionEntryCold(F)) + if (PSI.isFunctionEntryCold(&F)) return {false, nullptr}; - if (F->users().empty()) + if (F.users().empty()) return {false, nullptr}; - OptimizationRemarkEmitter ORE(F); + OptimizationRemarkEmitter ORE(&F); // Only try to outline cold regions if we have a profile summary, which // implies we have profiling information. - if (PSI.hasProfileSummary() && F->hasProfileData() && + if (PSI.hasProfileSummary() && F.hasProfileData() && !DisableMultiRegionPartialInline) { std::unique_ptr OMRI = computeOutliningColdRegionsInfo(F, ORE); if (OMRI) { - FunctionCloner Cloner(F, OMRI.get(), ORE, LookupAssumptionCache); + FunctionCloner Cloner(&F, OMRI.get(), ORE, LookupAssumptionCache, GetTTI); -#ifndef NDEBUG - if (TracePartialInlining) { + LLVM_DEBUG({ dbgs() << "HotCountThreshold = " << PSI.getHotCountThreshold() << "\n"; dbgs() << "ColdCountThreshold = " << PSI.getColdCountThreshold() << "\n"; - } -#endif + }); + bool DidOutline = Cloner.doMultiRegionFunctionOutlining(); if (DidOutline) { -#ifndef NDEBUG - if (TracePartialInlining) { + LLVM_DEBUG({ dbgs() << ">>>>>> Outlined (Cloned) Function >>>>>>\n"; Cloner.ClonedFunc->print(dbgs()); dbgs() << "<<<<<< Outlined (Cloned) Function <<<<<<\n"; - } -#endif + }); if (tryPartialInline(Cloner)) return {true, nullptr}; @@ -1310,17 +1329,15 @@ std::pair PartialInlinerImpl::unswitchFunction(Function *F) { if (!OI) return {false, nullptr}; - FunctionCloner Cloner(F, OI.get(), ORE, LookupAssumptionCache); - Cloner.NormalizeReturnBlock(); + FunctionCloner Cloner(&F, OI.get(), ORE, LookupAssumptionCache, GetTTI); + Cloner.normalizeReturnBlock(); Function *OutlinedFunction = Cloner.doSingleRegionFunctionOutlining(); if (!OutlinedFunction) return {false, nullptr}; - bool AnyInline = tryPartialInline(Cloner); - - if (AnyInline) + if (tryPartialInline(Cloner)) return {true, OutlinedFunction}; return {false, nullptr}; @@ -1338,9 +1355,9 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { // Only calculate RelativeToEntryFreq when we are doing single region // outlining. BranchProbability RelativeToEntryFreq; - if (Cloner.ClonedOI) { + if (Cloner.ClonedOI) RelativeToEntryFreq = getOutliningCallBBRelativeFreq(Cloner); - } else + else // RelativeToEntryFreq doesn't make sense when we have more than one // outlined call because each call will have a different relative frequency // to the entry block. We can consider using the average, but the @@ -1358,7 +1375,7 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { OptimizationRemarkEmitter OrigFuncORE(Cloner.OrigFunc); DebugLoc DLoc; BasicBlock *Block; - std::tie(DLoc, Block) = getOneDebugLoc(Cloner.ClonedFunc); + std::tie(DLoc, Block) = getOneDebugLoc(*Cloner.ClonedFunc); OrigFuncORE.emit([&]() { return OptimizationRemarkAnalysis(DEBUG_TYPE, "OutlineRegionTooSmall", DLoc, Block) @@ -1389,7 +1406,7 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { for (User *User : Users) { CallBase *CB = getSupportedCallBase(User); - if (IsLimitReached()) + if (isLimitReached()) continue; OptimizationRemarkEmitter CallerORE(CB->getCaller()); @@ -1426,7 +1443,6 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { NumPartialInlined++; else NumColdOutlinePartialInlined++; - } if (AnyInline) { @@ -1439,7 +1455,6 @@ bool PartialInlinerImpl::tryPartialInline(FunctionCloner &Cloner) { return OptimizationRemark(DEBUG_TYPE, "PartiallyInlined", Cloner.OrigFunc) << "Partially inlined into at least one caller"; }); - } return AnyInline; @@ -1473,7 +1488,7 @@ bool PartialInlinerImpl::run(Module &M) { if (Recursive) continue; - std::pair Result = unswitchFunction(CurrFunc); + std::pair Result = unswitchFunction(*CurrFunc); if (Result.second) Worklist.push_back(Result.second); Changed |= Result.first; diff --git a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp index d73d42c52074..068328391dff 100644 --- a/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ b/llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -51,16 +51,16 @@ using namespace llvm; -static cl::opt - RunPartialInlining("enable-partial-inlining", cl::init(false), cl::Hidden, - cl::ZeroOrMore, cl::desc("Run Partial inlinining pass")); +cl::opt RunPartialInlining("enable-partial-inlining", cl::init(false), + cl::Hidden, cl::ZeroOrMore, + cl::desc("Run Partial inlinining pass")); static cl::opt UseGVNAfterVectorization("use-gvn-after-vectorization", cl::init(false), cl::Hidden, cl::desc("Run GVN instead of Early CSE after vectorization passes")); -static cl::opt ExtraVectorizerPasses( +cl::opt ExtraVectorizerPasses( "extra-vectorizer-passes", cl::init(false), cl::Hidden, cl::desc("Run cleanup optimization passes after vectorization.")); @@ -68,29 +68,33 @@ static cl::opt RunLoopRerolling("reroll-loops", cl::Hidden, cl::desc("Run the loop rerolling pass")); -static cl::opt RunNewGVN("enable-newgvn", cl::init(false), cl::Hidden, - cl::desc("Run the NewGVN pass")); +cl::opt RunNewGVN("enable-newgvn", cl::init(false), cl::Hidden, + cl::desc("Run the NewGVN pass")); // Experimental option to use CFL-AA enum class CFLAAType { None, Steensgaard, Andersen, Both }; -static cl::opt - UseCFLAA("use-cfl-aa", cl::init(CFLAAType::None), cl::Hidden, +static cl::opt<::CFLAAType> + UseCFLAA("use-cfl-aa", cl::init(::CFLAAType::None), cl::Hidden, cl::desc("Enable the new, experimental CFL alias analysis"), - cl::values(clEnumValN(CFLAAType::None, "none", "Disable CFL-AA"), - clEnumValN(CFLAAType::Steensgaard, "steens", + cl::values(clEnumValN(::CFLAAType::None, "none", "Disable CFL-AA"), + clEnumValN(::CFLAAType::Steensgaard, "steens", "Enable unification-based CFL-AA"), - clEnumValN(CFLAAType::Andersen, "anders", + clEnumValN(::CFLAAType::Andersen, "anders", "Enable inclusion-based CFL-AA"), - clEnumValN(CFLAAType::Both, "both", + clEnumValN(::CFLAAType::Both, "both", "Enable both variants of CFL-AA"))); static cl::opt EnableLoopInterchange( "enable-loopinterchange", cl::init(false), cl::Hidden, cl::desc("Enable the new, experimental LoopInterchange Pass")); -static cl::opt EnableUnrollAndJam("enable-unroll-and-jam", - cl::init(false), cl::Hidden, - cl::desc("Enable Unroll And Jam Pass")); +cl::opt EnableUnrollAndJam("enable-unroll-and-jam", cl::init(false), + cl::Hidden, + cl::desc("Enable Unroll And Jam Pass")); + +cl::opt EnableLoopFlatten("enable-loop-flatten", cl::init(false), + cl::Hidden, + cl::desc("Enable the LoopFlatten Pass")); static cl::opt EnablePrepareForThinLTO("prepare-for-thinlto", cl::init(false), cl::Hidden, @@ -103,22 +107,25 @@ static cl::opt cl::opt EnableHotColdSplit("hot-cold-split", cl::init(false), cl::ZeroOrMore, cl::desc("Enable hot-cold splitting pass")); +cl::opt EnableIROutliner("ir-outliner", cl::init(false), cl::Hidden, + cl::desc("Enable ir outliner pass")); + static cl::opt UseLoopVersioningLICM( "enable-loop-versioning-licm", cl::init(false), cl::Hidden, cl::desc("Enable the experimental Loop Versioning LICM pass")); -static cl::opt +cl::opt DisablePreInliner("disable-preinline", cl::init(false), cl::Hidden, cl::desc("Disable pre-instrumentation inliner")); -static cl::opt PreInlineThreshold( +cl::opt PreInlineThreshold( "preinline-threshold", cl::Hidden, cl::init(75), cl::ZeroOrMore, cl::desc("Control the amount of inlining in pre-instrumentation inliner " "(default = 75)")); -static cl::opt EnableGVNHoist( - "enable-gvn-hoist", cl::init(false), cl::ZeroOrMore, - cl::desc("Enable the GVN hoisting pass (default = off)")); +cl::opt + EnableGVNHoist("enable-gvn-hoist", cl::init(false), cl::ZeroOrMore, + cl::desc("Enable the GVN hoisting pass (default = off)")); static cl::opt DisableLibCallsShrinkWrap("disable-libcalls-shrinkwrap", cl::init(false), @@ -130,13 +137,13 @@ static cl::opt EnableSimpleLoopUnswitch( cl::desc("Enable the simple loop unswitch pass. Also enables independent " "cleanup passes integrated into the loop pass manager pipeline.")); -static cl::opt EnableGVNSink( - "enable-gvn-sink", cl::init(false), cl::ZeroOrMore, - cl::desc("Enable the GVN sinking pass (default = off)")); +cl::opt + EnableGVNSink("enable-gvn-sink", cl::init(false), cl::ZeroOrMore, + cl::desc("Enable the GVN sinking pass (default = off)")); // This option is used in simplifying testing SampleFDO optimizations for // profile loading. -static cl::opt +cl::opt EnableCHR("enable-chr", cl::init(true), cl::Hidden, cl::desc("Enable control height reduction optimization (CHR)")); @@ -149,9 +156,14 @@ cl::opt EnableOrderFileInstrumentation( "enable-order-file-instrumentation", cl::init(false), cl::Hidden, cl::desc("Enable order file instrumentation (default = off)")); -static cl::opt - EnableMatrix("enable-matrix", cl::init(false), cl::Hidden, - cl::desc("Enable lowering of the matrix intrinsics")); +cl::opt EnableMatrix( + "enable-matrix", cl::init(false), cl::Hidden, + cl::desc("Enable lowering of the matrix intrinsics")); + +cl::opt EnableConstraintElimination( + "enable-constraint-elimination", cl::init(false), cl::Hidden, + cl::desc( + "Enable pass to eliminate conditions based on linear constraints.")); cl::opt AttributorRun( "attributor-enable", cl::Hidden, cl::init(AttributorRunOption::NONE), @@ -264,13 +276,13 @@ void PassManagerBuilder::addExtensionsToPM(ExtensionPointTy ETy, void PassManagerBuilder::addInitialAliasAnalysisPasses( legacy::PassManagerBase &PM) const { switch (UseCFLAA) { - case CFLAAType::Steensgaard: + case ::CFLAAType::Steensgaard: PM.add(createCFLSteensAAWrapperPass()); break; - case CFLAAType::Andersen: + case ::CFLAAType::Andersen: PM.add(createCFLAndersAAWrapperPass()); break; - case CFLAAType::Both: + case ::CFLAAType::Both: PM.add(createCFLSteensAAWrapperPass()); PM.add(createCFLAndersAAWrapperPass()); break; @@ -294,6 +306,13 @@ void PassManagerBuilder::populateFunctionPassManager( if (LibraryInfo) FPM.add(new TargetLibraryInfoWrapperPass(*LibraryInfo)); + // The backends do not handle matrix intrinsics currently. + // Make sure they are also lowered in O0. + // FIXME: A lightweight version of the pass should run in the backend + // pipeline on demand. + if (EnableMatrix && OptLevel == 0) + FPM.add(createLowerMatrixIntrinsicsMinimalPass()); + if (OptLevel == 0) return; addInitialAliasAnalysisPasses(FPM); @@ -314,19 +333,21 @@ void PassManagerBuilder::addPGOInstrPasses(legacy::PassManagerBase &MPM, return; // Perform the preinline and cleanup passes for O1 and above. - // And avoid doing them if optimizing for size. // We will not do this inline for context sensitive PGO (when IsCS is true). - if (OptLevel > 0 && SizeLevel == 0 && !DisablePreInliner && - PGOSampleUse.empty() && !IsCS) { + if (OptLevel > 0 && !DisablePreInliner && PGOSampleUse.empty() && !IsCS) { // Create preinline pass. We construct an InlineParams object and specify // the threshold here to avoid the command line options of the regular // inliner to influence pre-inlining. The only fields of InlineParams we // care about are DefaultThreshold and HintThreshold. InlineParams IP; IP.DefaultThreshold = PreInlineThreshold; - // FIXME: The hint threshold has the same value used by the regular inliner. - // This should probably be lowered after performance testing. - IP.HintThreshold = 325; + // FIXME: The hint threshold has the same value used by the regular inliner + // when not optimzing for size. This should probably be lowered after + // performance testing. + // Use PreInlineThreshold for both -Os and -Oz. Not running preinliner makes + // the instrumented binary unusably large. Even if PreInlineThreshold is not + // correct thresold for -Oz, it is better than not running preinliner. + IP.HintThreshold = SizeLevel > 0 ? PreInlineThreshold : 325; MPM.add(createFunctionInliningPass(IP)); MPM.add(createSROAPass()); @@ -374,6 +395,9 @@ void PassManagerBuilder::addFunctionSimplificationPasses( } } + if (EnableConstraintElimination) + MPM.add(createConstraintEliminationPass()); + if (OptLevel > 1) { // Speculative execution if the target has divergent branches; otherwise nop. MPM.add(createSpeculativeExecutionIfHasBranchDivergencePass()); @@ -409,7 +433,7 @@ void PassManagerBuilder::addFunctionSimplificationPasses( MPM.add(createLoopSimplifyCFGPass()); } // Rotate Loop - disable header duplication at -Oz - MPM.add(createLoopRotatePass(SizeLevel == 2 ? 0 : -1)); + MPM.add(createLoopRotatePass(SizeLevel == 2 ? 0 : -1, PrepareForLTO)); // TODO: Investigate promotion cap for O1. MPM.add(createLICMPass(LicmMssaOptCap, LicmMssaNoAccForPromotionCap)); if (EnableSimpleLoopUnswitch) @@ -422,20 +446,27 @@ void PassManagerBuilder::addFunctionSimplificationPasses( MPM.add(createCFGSimplificationPass()); MPM.add(createInstructionCombiningPass()); // We resume loop passes creating a second loop pipeline here. - MPM.add(createIndVarSimplifyPass()); // Canonicalize indvars + if (EnableLoopFlatten) { + MPM.add(createLoopFlattenPass()); // Flatten loops + MPM.add(createLoopSimplifyCFGPass()); + } MPM.add(createLoopIdiomPass()); // Recognize idioms like memset. + MPM.add(createIndVarSimplifyPass()); // Canonicalize indvars addExtensionsToPM(EP_LateLoopOptimizations, MPM); MPM.add(createLoopDeletionPass()); // Delete dead loops if (EnableLoopInterchange) MPM.add(createLoopInterchangePass()); // Interchange loops - // Unroll small loops + // Unroll small loops and perform peeling. MPM.add(createSimpleLoopUnrollPass(OptLevel, DisableUnrollLoops, ForgetAllSCEVInLoopUnroll)); addExtensionsToPM(EP_LoopOptimizerEnd, MPM); // This ends the loop pass pipelines. + // Break up allocas that may now be splittable after loop unrolling. + MPM.add(createSROAPass()); + if (OptLevel > 1) { MPM.add(createMergedLoadStoreMotionPass()); // Merge ld/st in diamonds MPM.add(NewGVN ? createNewGVNPass() @@ -444,6 +475,9 @@ void PassManagerBuilder::addFunctionSimplificationPasses( MPM.add(createMemCpyOptPass()); // Remove memcpy / form memset MPM.add(createSCCPPass()); // Constant prop with SCCP + if (EnableConstraintElimination) + MPM.add(createConstraintEliminationPass()); + // Delete dead bit computations (instcombine runs after to fold away the dead // computations, and then ADCE will run later to exploit any new DCE // opportunities that creates). @@ -456,6 +490,11 @@ void PassManagerBuilder::addFunctionSimplificationPasses( if (OptLevel > 1) { MPM.add(createJumpThreadingPass()); // Thread jumps MPM.add(createCorrelatedValuePropagationPass()); + } + MPM.add(createAggressiveDCEPass()); // Delete dead instructions + + // TODO: Investigate if this is too expensive at O1. + if (OptLevel > 1) { MPM.add(createDeadStoreEliminationPass()); // Delete dead stores MPM.add(createLICMPass(LicmMssaOptCap, LicmMssaNoAccForPromotionCap)); } @@ -465,8 +504,6 @@ void PassManagerBuilder::addFunctionSimplificationPasses( if (RerollLoops) MPM.add(createLoopRerollPass()); - // TODO: Investigate if this is too expensive at O1. - MPM.add(createAggressiveDCEPass()); // Delete dead instructions MPM.add(createCFGSimplificationPass()); // Merge & remove BBs // Clean up after everything. MPM.add(createInstructionCombiningPass()); @@ -483,6 +520,8 @@ void PassManagerBuilder::populateModulePassManager( // is handled separately, so just check this is not the ThinLTO post-link. bool DefaultOrPreLinkPipeline = !PerformThinLTO; + MPM.add(createAnnotation2MetadataLegacyPass()); + if (!PGOSampleUse.empty()) { MPM.add(createPruneEHPass()); // In ThinLTO mode, when flattened profile is used, all the available @@ -533,6 +572,8 @@ void PassManagerBuilder::populateModulePassManager( // new unnamed globals. MPM.add(createNameAnonGlobalPass()); } + + MPM.add(createAnnotationRemarksLegacyPass()); return; } @@ -736,7 +777,7 @@ void PassManagerBuilder::populateModulePassManager( // Re-rotate loops in all our loop nests. These may have fallout out of // rotated form due to GVN or other transformations, and the vectorizer relies // on the rotated form. Disable header duplication at -Oz. - MPM.add(createLoopRotatePass(SizeLevel == 2 ? 0 : -1)); + MPM.add(createLoopRotatePass(SizeLevel == 2 ? 0 : -1, PrepareForLTO)); // Distribute loops to allow partial vectorization. I.e. isolate dependences // into separate loop that would otherwise inhibit vectorization. This is @@ -777,7 +818,14 @@ void PassManagerBuilder::populateModulePassManager( // convert to more optimized IR using more aggressive simplify CFG options. // The extra sinking transform can create larger basic blocks, so do this // before SLP vectorization. - MPM.add(createCFGSimplificationPass(1, true, true, false, true)); + // FIXME: study whether hoisting and/or sinking of common instructions should + // be delayed until after SLP vectorizer. + MPM.add(createCFGSimplificationPass(SimplifyCFGOptions() + .forwardSwitchCondToPhi(true) + .convertSwitchToLookupTable(true) + .needCanonicalLoops(false) + .hoistCommonInsts(true) + .sinkCommonInsts(true))); if (SLPVectorize) { MPM.add(createSLPVectorizerPass()); // Vectorize parallel scalar chains. @@ -835,6 +883,9 @@ void PassManagerBuilder::populateModulePassManager( if (EnableHotColdSplit && !(PrepareForLTO || PrepareForThinLTO)) MPM.add(createHotColdSplittingPass()); + if (EnableIROutliner) + MPM.add(createIROutlinerPass()); + if (MergeFunctions) MPM.add(createMergeFunctionsPass()); @@ -866,6 +917,8 @@ void PassManagerBuilder::populateModulePassManager( // Rename anon globals to be able to handle them in the summary MPM.add(createNameAnonGlobalPass()); } + + MPM.add(createAnnotationRemarksLegacyPass()); } void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { @@ -984,7 +1037,7 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { // The IPO passes may leave cruft around. Clean up after them. PM.add(createInstructionCombiningPass()); addExtensionsToPM(EP_Peephole, PM); - PM.add(createJumpThreadingPass()); + PM.add(createJumpThreadingPass(/*FreezeSelectCond*/ true)); // Break up allocas PM.add(createSROAPass()); @@ -1000,23 +1053,29 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { PM.add(createGlobalsAAWrapperPass()); // IP alias analysis. PM.add(createLICMPass(LicmMssaOptCap, LicmMssaNoAccForPromotionCap)); - PM.add(createMergedLoadStoreMotionPass()); // Merge ld/st in diamonds. PM.add(NewGVN ? createNewGVNPass() : createGVNPass(DisableGVNLoadPRE)); // Remove redundancies. PM.add(createMemCpyOptPass()); // Remove dead memcpys. // Nuke dead stores. PM.add(createDeadStoreEliminationPass()); + PM.add(createMergedLoadStoreMotionPass()); // Merge ld/st in diamonds. // More loops are countable; try to optimize them. + if (EnableLoopFlatten) + PM.add(createLoopFlattenPass()); PM.add(createIndVarSimplifyPass()); PM.add(createLoopDeletionPass()); if (EnableLoopInterchange) PM.add(createLoopInterchangePass()); - // Unroll small loops + if (EnableConstraintElimination) + PM.add(createConstraintEliminationPass()); + + // Unroll small loops and perform peeling. PM.add(createSimpleLoopUnrollPass(OptLevel, DisableUnrollLoops, ForgetAllSCEVInLoopUnroll)); + PM.add(createLoopDistributePass()); PM.add(createLoopVectorizePass(true, !LoopVectorize)); // The vectorizer may have significantly shortened a loop body; unroll again. PM.add(createLoopUnrollPass(OptLevel, DisableUnrollLoops, @@ -1028,7 +1087,8 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { // we may have exposed more scalar opportunities. Run parts of the scalar // optimizer again at this point. PM.add(createInstructionCombiningPass()); // Initial cleanup - PM.add(createCFGSimplificationPass()); // if-convert + PM.add(createCFGSimplificationPass(SimplifyCFGOptions() // if-convert + .hoistCommonInsts(true))); PM.add(createSCCPPass()); // Propagate exposed constants PM.add(createInstructionCombiningPass()); // Clean up again PM.add(createBitTrackingDCEPass()); @@ -1047,7 +1107,7 @@ void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) { PM.add(createInstructionCombiningPass()); addExtensionsToPM(EP_Peephole, PM); - PM.add(createJumpThreadingPass()); + PM.add(createJumpThreadingPass(/*FreezeSelectCond*/ true)); } void PassManagerBuilder::addLateLTOOptimizationPasses( @@ -1058,7 +1118,8 @@ void PassManagerBuilder::addLateLTOOptimizationPasses( PM.add(createHotColdSplittingPass()); // Delete basic blocks, which optimization passes may have killed. - PM.add(createCFGSimplificationPass()); + PM.add( + createCFGSimplificationPass(SimplifyCFGOptions().hoistCommonInsts(true))); // Drop bodies of available externally objects to improve GlobalDCE. PM.add(createEliminateAvailableExternallyPass()); @@ -1140,6 +1201,8 @@ void PassManagerBuilder::populateLTOPassManager(legacy::PassManagerBase &PM) { addExtensionsToPM(EP_FullLinkTimeOptimizationLast, PM); + PM.add(createAnnotationRemarksLegacyPass()); + if (VerifyOutput) PM.add(createVerifierPass()); } diff --git a/llvm/lib/Transforms/IPO/PruneEH.cpp b/llvm/lib/Transforms/IPO/PruneEH.cpp index a16dc664db64..3f3b18771cd5 100644 --- a/llvm/lib/Transforms/IPO/PruneEH.cpp +++ b/llvm/lib/Transforms/IPO/PruneEH.cpp @@ -13,6 +13,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/CallGraph.h" @@ -27,8 +28,10 @@ #include "llvm/InitializePasses.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/Utils/CallGraphUpdater.h" #include "llvm/Transforms/Utils/Local.h" #include + using namespace llvm; #define DEBUG_TYPE "prune-eh" @@ -45,11 +48,10 @@ namespace { // runOnSCC - Analyze the SCC, performing the transformation if possible. bool runOnSCC(CallGraphSCC &SCC) override; - }; } -static bool SimplifyFunction(Function *F, CallGraph &CG); -static void DeleteBasicBlock(BasicBlock *BB, CallGraph &CG); +static bool SimplifyFunction(Function *F, CallGraphUpdater &CGU); +static void DeleteBasicBlock(BasicBlock *BB, CallGraphUpdater &CGU); char PruneEH::ID = 0; INITIALIZE_PASS_BEGIN(PruneEH, "prune-eh", @@ -60,20 +62,17 @@ INITIALIZE_PASS_END(PruneEH, "prune-eh", Pass *llvm::createPruneEHPass() { return new PruneEH(); } -static bool runImpl(CallGraphSCC &SCC, CallGraph &CG) { - SmallPtrSet SCCNodes; +static bool runImpl(CallGraphUpdater &CGU, SetVector &Functions) { +#ifndef NDEBUG + for (auto *F : Functions) + assert(F && "null Function"); +#endif bool MadeChange = false; - // Fill SCCNodes with the elements of the SCC. Used for quickly - // looking up whether a given CallGraphNode is in this SCC. - for (CallGraphNode *I : SCC) - SCCNodes.insert(I); - // First pass, scan all of the functions in the SCC, simplifying them // according to what we know. - for (CallGraphNode *I : SCC) - if (Function *F = I->getFunction()) - MadeChange |= SimplifyFunction(F, CG); + for (Function *F : Functions) + MadeChange |= SimplifyFunction(F, CGU); // Next, check to see if any callees might throw or if there are any external // functions in this SCC: if so, we cannot prune any functions in this SCC. @@ -83,13 +82,8 @@ static bool runImpl(CallGraphSCC &SCC, CallGraph &CG) { // obviously the SCC might throw. // bool SCCMightUnwind = false, SCCMightReturn = false; - for (CallGraphSCC::iterator I = SCC.begin(), E = SCC.end(); - (!SCCMightUnwind || !SCCMightReturn) && I != E; ++I) { - Function *F = (*I)->getFunction(); - if (!F) { - SCCMightUnwind = true; - SCCMightReturn = true; - } else if (!F->hasExactDefinition()) { + for (Function *F : Functions) { + if (!F->hasExactDefinition()) { SCCMightUnwind |= !F->doesNotThrow(); SCCMightReturn |= !F->doesNotReturn(); } else { @@ -125,10 +119,9 @@ static bool runImpl(CallGraphSCC &SCC, CallGraph &CG) { bool InstMightUnwind = true; if (const auto *CI = dyn_cast(&I)) { if (Function *Callee = CI->getCalledFunction()) { - CallGraphNode *CalleeNode = CG[Callee]; // If the callee is outside our current SCC then we may throw // because it might. If it is inside, do nothing. - if (SCCNodes.count(CalleeNode) > 0) + if (Functions.contains(Callee)) InstMightUnwind = false; } } @@ -140,18 +133,15 @@ static bool runImpl(CallGraphSCC &SCC, CallGraph &CG) { if (IA->hasSideEffects()) SCCMightReturn = true; } - + } if (SCCMightUnwind && SCCMightReturn) break; - } } } // If the SCC doesn't unwind or doesn't throw, note this fact. if (!SCCMightUnwind || !SCCMightReturn) - for (CallGraphNode *I : SCC) { - Function *F = I->getFunction(); - + for (Function *F : Functions) { if (!SCCMightUnwind && !F->hasFnAttribute(Attribute::NoUnwind)) { F->addFnAttr(Attribute::NoUnwind); MadeChange = true; @@ -163,30 +153,35 @@ static bool runImpl(CallGraphSCC &SCC, CallGraph &CG) { } } - for (CallGraphNode *I : SCC) { + for (Function *F : Functions) { // Convert any invoke instructions to non-throwing functions in this node // into call instructions with a branch. This makes the exception blocks // dead. - if (Function *F = I->getFunction()) - MadeChange |= SimplifyFunction(F, CG); + MadeChange |= SimplifyFunction(F, CGU); } return MadeChange; } - bool PruneEH::runOnSCC(CallGraphSCC &SCC) { if (skipSCC(SCC)) return false; + SetVector Functions; + for (auto &N : SCC) { + if (auto *F = N->getFunction()) + Functions.insert(F); + } CallGraph &CG = getAnalysis().getCallGraph(); - return runImpl(SCC, CG); + CallGraphUpdater CGU; + CGU.initialize(CG, SCC); + return runImpl(CGU, Functions); } // SimplifyFunction - Given information about callees, simplify the specified // function if we have invokes to non-unwinding functions or code after calls to // no-return functions. -static bool SimplifyFunction(Function *F, CallGraph &CG) { +static bool SimplifyFunction(Function *F, CallGraphUpdater &CGU) { bool MadeChange = false; for (Function::iterator BB = F->begin(), E = F->end(); BB != E; ++BB) { if (InvokeInst *II = dyn_cast(BB->getTerminator())) @@ -196,7 +191,7 @@ static bool SimplifyFunction(Function *F, CallGraph &CG) { // If the unwind block is now dead, nuke it. if (pred_empty(UnwindBlock)) - DeleteBasicBlock(UnwindBlock, CG); // Delete the new BB. + DeleteBasicBlock(UnwindBlock, CGU); // Delete the new BB. ++NumRemoved; MadeChange = true; @@ -216,7 +211,7 @@ static bool SimplifyFunction(Function *F, CallGraph &CG) { BB->getInstList().pop_back(); new UnreachableInst(BB->getContext(), &*BB); - DeleteBasicBlock(New, CG); // Delete the new BB. + DeleteBasicBlock(New, CGU); // Delete the new BB. MadeChange = true; ++NumUnreach; break; @@ -229,12 +224,11 @@ static bool SimplifyFunction(Function *F, CallGraph &CG) { /// DeleteBasicBlock - remove the specified basic block from the program, /// updating the callgraph to reflect any now-obsolete edges due to calls that /// exist in the BB. -static void DeleteBasicBlock(BasicBlock *BB, CallGraph &CG) { +static void DeleteBasicBlock(BasicBlock *BB, CallGraphUpdater &CGU) { assert(pred_empty(BB) && "BB is not dead!"); Instruction *TokenInst = nullptr; - CallGraphNode *CGN = CG[BB->getParent()]; for (BasicBlock::iterator I = BB->end(), E = BB->begin(); I != E; ) { --I; @@ -246,9 +240,9 @@ static void DeleteBasicBlock(BasicBlock *BB, CallGraph &CG) { if (auto *Call = dyn_cast(&*I)) { const Function *Callee = Call->getCalledFunction(); if (!Callee || !Intrinsic::isLeaf(Callee->getIntrinsicID())) - CGN->removeCallEdgeFor(*Call); + CGU.removeCallSite(*Call); else if (!Callee->isIntrinsic()) - CGN->removeCallEdgeFor(*Call); + CGU.removeCallSite(*Call); } if (!I->use_empty()) diff --git a/llvm/lib/Transforms/IPO/SampleContextTracker.cpp b/llvm/lib/Transforms/IPO/SampleContextTracker.cpp new file mode 100644 index 000000000000..37fc27e91100 --- /dev/null +++ b/llvm/lib/Transforms/IPO/SampleContextTracker.cpp @@ -0,0 +1,521 @@ +//===- SampleContextTracker.cpp - Context-sensitive Profile Tracker -------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SampleContextTracker used by CSSPGO. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/SampleContextTracker.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/Instructions.h" +#include "llvm/ProfileData/SampleProf.h" +#include +#include +#include + +using namespace llvm; +using namespace sampleprof; + +#define DEBUG_TYPE "sample-context-tracker" + +namespace llvm { + +ContextTrieNode *ContextTrieNode::getChildContext(const LineLocation &CallSite, + StringRef CalleeName) { + if (CalleeName.empty()) + return getChildContext(CallSite); + + uint32_t Hash = nodeHash(CalleeName, CallSite); + auto It = AllChildContext.find(Hash); + if (It != AllChildContext.end()) + return &It->second; + return nullptr; +} + +ContextTrieNode * +ContextTrieNode::getChildContext(const LineLocation &CallSite) { + // CSFDO-TODO: This could be slow, change AllChildContext so we can + // do point look up for child node by call site alone. + // CSFDO-TODO: Return the child with max count for indirect call + ContextTrieNode *ChildNodeRet = nullptr; + for (auto &It : AllChildContext) { + ContextTrieNode &ChildNode = It.second; + if (ChildNode.CallSiteLoc == CallSite) { + if (ChildNodeRet) + return nullptr; + else + ChildNodeRet = &ChildNode; + } + } + + return ChildNodeRet; +} + +ContextTrieNode &ContextTrieNode::moveToChildContext( + const LineLocation &CallSite, ContextTrieNode &&NodeToMove, + StringRef ContextStrToRemove, bool DeleteNode) { + uint32_t Hash = nodeHash(NodeToMove.getFuncName(), CallSite); + assert(!AllChildContext.count(Hash) && "Node to remove must exist"); + LineLocation OldCallSite = NodeToMove.CallSiteLoc; + ContextTrieNode &OldParentContext = *NodeToMove.getParentContext(); + AllChildContext[Hash] = NodeToMove; + ContextTrieNode &NewNode = AllChildContext[Hash]; + NewNode.CallSiteLoc = CallSite; + + // Walk through nodes in the moved the subtree, and update + // FunctionSamples' context as for the context promotion. + // We also need to set new parant link for all children. + std::queue NodeToUpdate; + NewNode.setParentContext(this); + NodeToUpdate.push(&NewNode); + + while (!NodeToUpdate.empty()) { + ContextTrieNode *Node = NodeToUpdate.front(); + NodeToUpdate.pop(); + FunctionSamples *FSamples = Node->getFunctionSamples(); + + if (FSamples) { + FSamples->getContext().promoteOnPath(ContextStrToRemove); + FSamples->getContext().setState(SyntheticContext); + LLVM_DEBUG(dbgs() << " Context promoted to: " << FSamples->getContext() + << "\n"); + } + + for (auto &It : Node->getAllChildContext()) { + ContextTrieNode *ChildNode = &It.second; + ChildNode->setParentContext(Node); + NodeToUpdate.push(ChildNode); + } + } + + // Original context no longer needed, destroy if requested. + if (DeleteNode) + OldParentContext.removeChildContext(OldCallSite, NewNode.getFuncName()); + + return NewNode; +} + +void ContextTrieNode::removeChildContext(const LineLocation &CallSite, + StringRef CalleeName) { + uint32_t Hash = nodeHash(CalleeName, CallSite); + // Note this essentially calls dtor and destroys that child context + AllChildContext.erase(Hash); +} + +std::map &ContextTrieNode::getAllChildContext() { + return AllChildContext; +} + +const StringRef ContextTrieNode::getFuncName() const { return FuncName; } + +FunctionSamples *ContextTrieNode::getFunctionSamples() const { + return FuncSamples; +} + +void ContextTrieNode::setFunctionSamples(FunctionSamples *FSamples) { + FuncSamples = FSamples; +} + +LineLocation ContextTrieNode::getCallSiteLoc() const { return CallSiteLoc; } + +ContextTrieNode *ContextTrieNode::getParentContext() const { + return ParentContext; +} + +void ContextTrieNode::setParentContext(ContextTrieNode *Parent) { + ParentContext = Parent; +} + +void ContextTrieNode::dump() { + dbgs() << "Node: " << FuncName << "\n" + << " Callsite: " << CallSiteLoc << "\n" + << " Children:\n"; + + for (auto &It : AllChildContext) { + dbgs() << " Node: " << It.second.getFuncName() << "\n"; + } +} + +uint32_t ContextTrieNode::nodeHash(StringRef ChildName, + const LineLocation &Callsite) { + // We still use child's name for child hash, this is + // because for children of root node, we don't have + // different line/discriminator, and we'll rely on name + // to differentiate children. + uint32_t NameHash = std::hash{}(ChildName.str()); + uint32_t LocId = (Callsite.LineOffset << 16) | Callsite.Discriminator; + return NameHash + (LocId << 5) + LocId; +} + +ContextTrieNode *ContextTrieNode::getOrCreateChildContext( + const LineLocation &CallSite, StringRef CalleeName, bool AllowCreate) { + uint32_t Hash = nodeHash(CalleeName, CallSite); + auto It = AllChildContext.find(Hash); + if (It != AllChildContext.end()) { + assert(It->second.getFuncName() == CalleeName && + "Hash collision for child context node"); + return &It->second; + } + + if (!AllowCreate) + return nullptr; + + AllChildContext[Hash] = ContextTrieNode(this, CalleeName, nullptr, CallSite); + return &AllChildContext[Hash]; +} + +// Profiler tracker than manages profiles and its associated context +SampleContextTracker::SampleContextTracker( + StringMap &Profiles) { + for (auto &FuncSample : Profiles) { + FunctionSamples *FSamples = &FuncSample.second; + SampleContext Context(FuncSample.first(), RawContext); + LLVM_DEBUG(dbgs() << "Tracking Context for function: " << Context << "\n"); + if (!Context.isBaseContext()) + FuncToCtxtProfileSet[Context.getName()].insert(FSamples); + ContextTrieNode *NewNode = getOrCreateContextPath(Context, true); + assert(!NewNode->getFunctionSamples() && + "New node can't have sample profile"); + NewNode->setFunctionSamples(FSamples); + } +} + +FunctionSamples * +SampleContextTracker::getCalleeContextSamplesFor(const CallBase &Inst, + StringRef CalleeName) { + LLVM_DEBUG(dbgs() << "Getting callee context for instr: " << Inst << "\n"); + // CSFDO-TODO: We use CalleeName to differentiate indirect call + // We need to get sample for indirect callee too. + DILocation *DIL = Inst.getDebugLoc(); + if (!DIL) + return nullptr; + + ContextTrieNode *CalleeContext = getCalleeContextFor(DIL, CalleeName); + if (CalleeContext) { + FunctionSamples *FSamples = CalleeContext->getFunctionSamples(); + LLVM_DEBUG(if (FSamples) { + dbgs() << " Callee context found: " << FSamples->getContext() << "\n"; + }); + return FSamples; + } + + return nullptr; +} + +FunctionSamples * +SampleContextTracker::getContextSamplesFor(const DILocation *DIL) { + assert(DIL && "Expect non-null location"); + + ContextTrieNode *ContextNode = getContextFor(DIL); + if (!ContextNode) + return nullptr; + + // We may have inlined callees during pre-LTO compilation, in which case + // we need to rely on the inline stack from !dbg to mark context profile + // as inlined, instead of `MarkContextSamplesInlined` during inlining. + // Sample profile loader walks through all instructions to get profile, + // which calls this function. So once that is done, all previously inlined + // context profile should be marked properly. + FunctionSamples *Samples = ContextNode->getFunctionSamples(); + if (Samples && ContextNode->getParentContext() != &RootContext) + Samples->getContext().setState(InlinedContext); + + return Samples; +} + +FunctionSamples * +SampleContextTracker::getContextSamplesFor(const SampleContext &Context) { + ContextTrieNode *Node = getContextFor(Context); + if (!Node) + return nullptr; + + return Node->getFunctionSamples(); +} + +FunctionSamples *SampleContextTracker::getBaseSamplesFor(const Function &Func, + bool MergeContext) { + StringRef CanonName = FunctionSamples::getCanonicalFnName(Func); + return getBaseSamplesFor(CanonName, MergeContext); +} + +FunctionSamples *SampleContextTracker::getBaseSamplesFor(StringRef Name, + bool MergeContext) { + LLVM_DEBUG(dbgs() << "Getting base profile for function: " << Name << "\n"); + // Base profile is top-level node (child of root node), so try to retrieve + // existing top-level node for given function first. If it exists, it could be + // that we've merged base profile before, or there's actually context-less + // profile from the input (e.g. due to unreliable stack walking). + ContextTrieNode *Node = getTopLevelContextNode(Name); + if (MergeContext) { + LLVM_DEBUG(dbgs() << " Merging context profile into base profile: " << Name + << "\n"); + + // We have profile for function under different contexts, + // create synthetic base profile and merge context profiles + // into base profile. + for (auto *CSamples : FuncToCtxtProfileSet[Name]) { + SampleContext &Context = CSamples->getContext(); + ContextTrieNode *FromNode = getContextFor(Context); + if (FromNode == Node) + continue; + + // Skip inlined context profile and also don't re-merge any context + if (Context.hasState(InlinedContext) || Context.hasState(MergedContext)) + continue; + + ContextTrieNode &ToNode = promoteMergeContextSamplesTree(*FromNode); + assert((!Node || Node == &ToNode) && "Expect only one base profile"); + Node = &ToNode; + } + } + + // Still no profile even after merge/promotion (if allowed) + if (!Node) + return nullptr; + + return Node->getFunctionSamples(); +} + +void SampleContextTracker::markContextSamplesInlined( + const FunctionSamples *InlinedSamples) { + assert(InlinedSamples && "Expect non-null inlined samples"); + LLVM_DEBUG(dbgs() << "Marking context profile as inlined: " + << InlinedSamples->getContext() << "\n"); + InlinedSamples->getContext().setState(InlinedContext); +} + +void SampleContextTracker::promoteMergeContextSamplesTree( + const Instruction &Inst, StringRef CalleeName) { + LLVM_DEBUG(dbgs() << "Promoting and merging context tree for instr: \n" + << Inst << "\n"); + // CSFDO-TODO: We also need to promote context profile from indirect + // calls. We won't have callee names from those from call instr. + if (CalleeName.empty()) + return; + + // Get the caller context for the call instruction, we don't use callee + // name from call because there can be context from indirect calls too. + DILocation *DIL = Inst.getDebugLoc(); + ContextTrieNode *CallerNode = getContextFor(DIL); + if (!CallerNode) + return; + + // Get the context that needs to be promoted + LineLocation CallSite(FunctionSamples::getOffset(DIL), + DIL->getBaseDiscriminator()); + ContextTrieNode *NodeToPromo = + CallerNode->getChildContext(CallSite, CalleeName); + if (!NodeToPromo) + return; + + promoteMergeContextSamplesTree(*NodeToPromo); +} + +ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree( + ContextTrieNode &NodeToPromo) { + // Promote the input node to be directly under root. This can happen + // when we decided to not inline a function under context represented + // by the input node. The promote and merge is then needed to reflect + // the context profile in the base (context-less) profile. + FunctionSamples *FromSamples = NodeToPromo.getFunctionSamples(); + assert(FromSamples && "Shouldn't promote a context without profile"); + LLVM_DEBUG(dbgs() << " Found context tree root to promote: " + << FromSamples->getContext() << "\n"); + + StringRef ContextStrToRemove = FromSamples->getContext().getCallingContext(); + return promoteMergeContextSamplesTree(NodeToPromo, RootContext, + ContextStrToRemove); +} + +void SampleContextTracker::dump() { + dbgs() << "Context Profile Tree:\n"; + std::queue NodeQueue; + NodeQueue.push(&RootContext); + + while (!NodeQueue.empty()) { + ContextTrieNode *Node = NodeQueue.front(); + NodeQueue.pop(); + Node->dump(); + + for (auto &It : Node->getAllChildContext()) { + ContextTrieNode *ChildNode = &It.second; + NodeQueue.push(ChildNode); + } + } +} + +ContextTrieNode * +SampleContextTracker::getContextFor(const SampleContext &Context) { + return getOrCreateContextPath(Context, false); +} + +ContextTrieNode * +SampleContextTracker::getCalleeContextFor(const DILocation *DIL, + StringRef CalleeName) { + assert(DIL && "Expect non-null location"); + + // CSSPGO-TODO: need to support indirect callee + if (CalleeName.empty()) + return nullptr; + + ContextTrieNode *CallContext = getContextFor(DIL); + if (!CallContext) + return nullptr; + + return CallContext->getChildContext( + LineLocation(FunctionSamples::getOffset(DIL), + DIL->getBaseDiscriminator()), + CalleeName); +} + +ContextTrieNode *SampleContextTracker::getContextFor(const DILocation *DIL) { + assert(DIL && "Expect non-null location"); + SmallVector, 10> S; + + // Use C++ linkage name if possible. + const DILocation *PrevDIL = DIL; + for (DIL = DIL->getInlinedAt(); DIL; DIL = DIL->getInlinedAt()) { + StringRef Name = PrevDIL->getScope()->getSubprogram()->getLinkageName(); + if (Name.empty()) + Name = PrevDIL->getScope()->getSubprogram()->getName(); + S.push_back( + std::make_pair(LineLocation(FunctionSamples::getOffset(DIL), + DIL->getBaseDiscriminator()), Name)); + PrevDIL = DIL; + } + + // Push root node, note that root node like main may only + // a name, but not linkage name. + StringRef RootName = PrevDIL->getScope()->getSubprogram()->getLinkageName(); + if (RootName.empty()) + RootName = PrevDIL->getScope()->getSubprogram()->getName(); + S.push_back(std::make_pair(LineLocation(0, 0), RootName)); + + ContextTrieNode *ContextNode = &RootContext; + int I = S.size(); + while (--I >= 0 && ContextNode) { + LineLocation &CallSite = S[I].first; + StringRef &CalleeName = S[I].second; + ContextNode = ContextNode->getChildContext(CallSite, CalleeName); + } + + if (I < 0) + return ContextNode; + + return nullptr; +} + +ContextTrieNode * +SampleContextTracker::getOrCreateContextPath(const SampleContext &Context, + bool AllowCreate) { + ContextTrieNode *ContextNode = &RootContext; + StringRef ContextRemain = Context; + StringRef ChildContext; + StringRef CalleeName; + LineLocation CallSiteLoc(0, 0); + + while (ContextNode && !ContextRemain.empty()) { + auto ContextSplit = SampleContext::splitContextString(ContextRemain); + ChildContext = ContextSplit.first; + ContextRemain = ContextSplit.second; + LineLocation NextCallSiteLoc(0, 0); + SampleContext::decodeContextString(ChildContext, CalleeName, + NextCallSiteLoc); + + // Create child node at parent line/disc location + if (AllowCreate) { + ContextNode = + ContextNode->getOrCreateChildContext(CallSiteLoc, CalleeName); + } else { + ContextNode = ContextNode->getChildContext(CallSiteLoc, CalleeName); + } + CallSiteLoc = NextCallSiteLoc; + } + + assert((!AllowCreate || ContextNode) && + "Node must exist if creation is allowed"); + return ContextNode; +} + +ContextTrieNode *SampleContextTracker::getTopLevelContextNode(StringRef FName) { + return RootContext.getChildContext(LineLocation(0, 0), FName); +} + +ContextTrieNode &SampleContextTracker::addTopLevelContextNode(StringRef FName) { + assert(!getTopLevelContextNode(FName) && "Node to add must not exist"); + return *RootContext.getOrCreateChildContext(LineLocation(0, 0), FName); +} + +void SampleContextTracker::mergeContextNode(ContextTrieNode &FromNode, + ContextTrieNode &ToNode, + StringRef ContextStrToRemove) { + FunctionSamples *FromSamples = FromNode.getFunctionSamples(); + FunctionSamples *ToSamples = ToNode.getFunctionSamples(); + if (FromSamples && ToSamples) { + // Merge/duplicate FromSamples into ToSamples + ToSamples->merge(*FromSamples); + ToSamples->getContext().setState(SyntheticContext); + FromSamples->getContext().setState(MergedContext); + } else if (FromSamples) { + // Transfer FromSamples from FromNode to ToNode + ToNode.setFunctionSamples(FromSamples); + FromSamples->getContext().setState(SyntheticContext); + FromSamples->getContext().promoteOnPath(ContextStrToRemove); + FromNode.setFunctionSamples(nullptr); + } +} + +ContextTrieNode &SampleContextTracker::promoteMergeContextSamplesTree( + ContextTrieNode &FromNode, ContextTrieNode &ToNodeParent, + StringRef ContextStrToRemove) { + assert(!ContextStrToRemove.empty() && "Context to remove can't be empty"); + + // Ignore call site location if destination is top level under root + LineLocation NewCallSiteLoc = LineLocation(0, 0); + LineLocation OldCallSiteLoc = FromNode.getCallSiteLoc(); + ContextTrieNode &FromNodeParent = *FromNode.getParentContext(); + ContextTrieNode *ToNode = nullptr; + bool MoveToRoot = (&ToNodeParent == &RootContext); + if (!MoveToRoot) { + NewCallSiteLoc = OldCallSiteLoc; + } + + // Locate destination node, create/move if not existing + ToNode = ToNodeParent.getChildContext(NewCallSiteLoc, FromNode.getFuncName()); + if (!ToNode) { + // Do not delete node to move from its parent here because + // caller is iterating over children of that parent node. + ToNode = &ToNodeParent.moveToChildContext( + NewCallSiteLoc, std::move(FromNode), ContextStrToRemove, false); + } else { + // Destination node exists, merge samples for the context tree + mergeContextNode(FromNode, *ToNode, ContextStrToRemove); + LLVM_DEBUG(dbgs() << " Context promoted and merged to: " + << ToNode->getFunctionSamples()->getContext() << "\n"); + + // Recursively promote and merge children + for (auto &It : FromNode.getAllChildContext()) { + ContextTrieNode &FromChildNode = It.second; + promoteMergeContextSamplesTree(FromChildNode, *ToNode, + ContextStrToRemove); + } + + // Remove children once they're all merged + FromNode.getAllChildContext().clear(); + } + + // For root of subtree, remove itself from old parent too + if (MoveToRoot) + FromNodeParent.removeChildContext(OldCallSiteLoc, ToNode->getFuncName()); + + return *ToNode; +} + +} // namespace llvm diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp index b6871e260532..264ac4065e8c 100644 --- a/llvm/lib/Transforms/IPO/SampleProfile.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp @@ -43,6 +43,7 @@ #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/ProfileSummaryInfo.h" +#include "llvm/Analysis/ReplayInlineAdvisor.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/BasicBlock.h" @@ -75,10 +76,11 @@ #include "llvm/Support/GenericDomTree.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/IPO.h" +#include "llvm/Transforms/IPO/SampleContextTracker.h" +#include "llvm/Transforms/IPO/SampleProfileProbe.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/CallPromotionUtils.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/MisExpect.h" #include #include #include @@ -102,6 +104,9 @@ STATISTIC(NumCSInlined, "Number of functions inlined with context sensitive profile"); STATISTIC(NumCSNotInlined, "Number of functions not inlined with context sensitive profile"); +STATISTIC(NumMismatchedProfile, + "Number of functions with CFG mismatched profile"); +STATISTIC(NumMatchedProfile, "Number of functions with CFG matched profile"); // Command line option to specify the file to read samples from. This is // mainly used for debugging. @@ -170,6 +175,13 @@ static cl::opt SampleColdCallSiteThreshold( "sample-profile-cold-inline-threshold", cl::Hidden, cl::init(45), cl::desc("Threshold for inlining cold callsites")); +static cl::opt ProfileInlineReplayFile( + "sample-profile-inline-replay", cl::init(""), cl::value_desc("filename"), + cl::desc( + "Optimization remarks file containing inline remarks to be replayed " + "by inlining from sample profile loader."), + cl::Hidden); + namespace { using BlockWeightMap = DenseMap; @@ -309,17 +321,16 @@ private: class SampleProfileLoader { public: SampleProfileLoader( - StringRef Name, StringRef RemapName, bool IsThinLTOPreLink, + StringRef Name, StringRef RemapName, ThinOrFullLTOPhase LTOPhase, std::function GetAssumptionCache, std::function GetTargetTransformInfo, std::function GetTLI) : GetAC(std::move(GetAssumptionCache)), GetTTI(std::move(GetTargetTransformInfo)), GetTLI(std::move(GetTLI)), CoverageTracker(*this), Filename(std::string(Name)), - RemappingFilename(std::string(RemapName)), - IsThinLTOPreLink(IsThinLTOPreLink) {} + RemappingFilename(std::string(RemapName)), LTOPhase(LTOPhase) {} - bool doInitialization(Module &M); + bool doInitialization(Module &M, FunctionAnalysisManager *FAM = nullptr); bool runOnModule(Module &M, ModuleAnalysisManager *AM, ProfileSummaryInfo *_PSI, CallGraph *CG); @@ -332,6 +343,7 @@ protected: unsigned getFunctionLoc(Function &F); bool emitAnnotations(Function &F); ErrorOr getInstWeight(const Instruction &I); + ErrorOr getProbeWeight(const Instruction &I); ErrorOr getBlockWeight(const BasicBlock *BB); const FunctionSamples *findCalleeFunctionSamples(const CallBase &I) const; std::vector @@ -417,6 +429,9 @@ protected: /// Profile reader object. std::unique_ptr Reader; + /// Profile tracker for different context. + std::unique_ptr ContextTracker; + /// Samples collected for the body of this function. FunctionSamples *Samples = nullptr; @@ -429,11 +444,15 @@ protected: /// Flag indicating whether the profile input loaded successfully. bool ProfileIsValid = false; - /// Flag indicating if the pass is invoked in ThinLTO compile phase. + /// Flag indicating whether input profile is context-sensitive + bool ProfileIsCS = false; + + /// Flag indicating which LTO/ThinLTO phase the pass is invoked in. /// - /// In this phase, in annotation, we should not promote indirect calls. - /// Instead, we will mark GUIDs that needs to be annotated to the function. - bool IsThinLTOPreLink; + /// We need to know the LTO phase because for example in ThinLTOPrelink + /// phase, in annotation, we should not promote indirect calls. Instead, + /// we will mark GUIDs that needs to be annotated to the function. + ThinOrFullLTOPhase LTOPhase; /// Profile Summary Info computed from sample profile. ProfileSummaryInfo *PSI = nullptr; @@ -473,6 +492,12 @@ protected: // overriden by -profile-sample-accurate or profile-sample-accurate // attribute. bool ProfAccForSymsInList; + + // External inline advisor used to replay inline decision from remarks. + std::unique_ptr ExternalInlineAdvisor; + + // A pseudo probe helper to correlate the imported sample counts. + std::unique_ptr ProbeManager; }; class SampleProfileLoaderLegacyPass : public ModulePass { @@ -480,10 +505,11 @@ public: // Class identification, replacement for typeinfo static char ID; - SampleProfileLoaderLegacyPass(StringRef Name = SampleProfileFile, - bool IsThinLTOPreLink = false) + SampleProfileLoaderLegacyPass( + StringRef Name = SampleProfileFile, + ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None) : ModulePass(ID), SampleLoader( - Name, SampleProfileRemappingFile, IsThinLTOPreLink, + Name, SampleProfileRemappingFile, LTOPhase, [&](Function &F) -> AssumptionCache & { return ACT->getAssumptionCache(F); }, @@ -705,6 +731,9 @@ void SampleProfileLoader::printBlockWeight(raw_ostream &OS, /// /// \returns the weight of \p Inst. ErrorOr SampleProfileLoader::getInstWeight(const Instruction &Inst) { + if (FunctionSamples::ProfileIsProbeBased) + return getProbeWeight(Inst); + const DebugLoc &DLoc = Inst.getDebugLoc(); if (!DLoc) return std::error_code(); @@ -723,9 +752,10 @@ ErrorOr SampleProfileLoader::getInstWeight(const Instruction &Inst) { // (findCalleeFunctionSamples returns non-empty result), but not inlined here, // it means that the inlined callsite has no sample, thus the call // instruction should have 0 count. - if (auto *CB = dyn_cast(&Inst)) - if (!CB->isIndirectCall() && findCalleeFunctionSamples(*CB)) - return 0; + if (!ProfileIsCS) + if (const auto *CB = dyn_cast(&Inst)) + if (!CB->isIndirectCall() && findCalleeFunctionSamples(*CB)) + return 0; const DILocation *DIL = DLoc; uint32_t LineOffset = FunctionSamples::getOffset(DIL); @@ -757,6 +787,47 @@ ErrorOr SampleProfileLoader::getInstWeight(const Instruction &Inst) { return R; } +ErrorOr SampleProfileLoader::getProbeWeight(const Instruction &Inst) { + assert(FunctionSamples::ProfileIsProbeBased && + "Profile is not pseudo probe based"); + Optional Probe = extractProbe(Inst); + if (!Probe) + return std::error_code(); + + const FunctionSamples *FS = findFunctionSamples(Inst); + if (!FS) + return std::error_code(); + + // If a direct call/invoke instruction is inlined in profile + // (findCalleeFunctionSamples returns non-empty result), but not inlined here, + // it means that the inlined callsite has no sample, thus the call + // instruction should have 0 count. + if (const auto *CB = dyn_cast(&Inst)) + if (!CB->isIndirectCall() && findCalleeFunctionSamples(*CB)) + return 0; + + const ErrorOr &R = FS->findSamplesAt(Probe->Id, 0); + if (R) { + uint64_t Samples = R.get(); + bool FirstMark = CoverageTracker.markSamplesUsed(FS, Probe->Id, 0, Samples); + if (FirstMark) { + ORE->emit([&]() { + OptimizationRemarkAnalysis Remark(DEBUG_TYPE, "AppliedSamples", &Inst); + Remark << "Applied " << ore::NV("NumSamples", Samples); + Remark << " samples from profile (ProbeId="; + Remark << ore::NV("ProbeId", Probe->Id); + Remark << ")"; + return Remark; + }); + } + + LLVM_DEBUG(dbgs() << " " << Probe->Id << ":" << Inst + << " - weight: " << R.get() << ")\n"); + return Samples; + } + return R; +} + /// Compute the weight of a basic block. /// /// The weight of basic block \p BB is the maximum weight of all the @@ -820,17 +891,18 @@ SampleProfileLoader::findCalleeFunctionSamples(const CallBase &Inst) const { } StringRef CalleeName; - if (const CallInst *CI = dyn_cast(&Inst)) - if (Function *Callee = CI->getCalledFunction()) - CalleeName = Callee->getName(); + if (Function *Callee = Inst.getCalledFunction()) + CalleeName = FunctionSamples::getCanonicalFnName(*Callee); + + if (ProfileIsCS) + return ContextTracker->getCalleeContextSamplesFor(Inst, CalleeName); const FunctionSamples *FS = findFunctionSamples(Inst); if (FS == nullptr) return nullptr; - return FS->findFunctionSamplesAt(LineLocation(FunctionSamples::getOffset(DIL), - DIL->getBaseDiscriminator()), - CalleeName); + return FS->findFunctionSamplesAt(FunctionSamples::getCallSiteIdentifier(DIL), + CalleeName, Reader->getRemapper()); } /// Returns a vector of FunctionSamples that are the indirect call targets @@ -850,16 +922,13 @@ SampleProfileLoader::findIndirectCallFunctionSamples( if (FS == nullptr) return R; - uint32_t LineOffset = FunctionSamples::getOffset(DIL); - uint32_t Discriminator = DIL->getBaseDiscriminator(); - - auto T = FS->findCallTargetMapAt(LineOffset, Discriminator); + auto CallSite = FunctionSamples::getCallSiteIdentifier(DIL); + auto T = FS->findCallTargetMapAt(CallSite); Sum = 0; if (T) for (const auto &T_C : T.get()) Sum += T_C.second; - if (const FunctionSamplesMap *M = FS->findFunctionSamplesMapAt(LineLocation( - FunctionSamples::getOffset(DIL), DIL->getBaseDiscriminator()))) { + if (const FunctionSamplesMap *M = FS->findFunctionSamplesMapAt(CallSite)) { if (M->empty()) return R; for (const auto &NameFS : *M) { @@ -887,17 +956,38 @@ SampleProfileLoader::findIndirectCallFunctionSamples( /// \returns the FunctionSamples pointer to the inlined instance. const FunctionSamples * SampleProfileLoader::findFunctionSamples(const Instruction &Inst) const { + if (FunctionSamples::ProfileIsProbeBased) { + Optional Probe = extractProbe(Inst); + if (!Probe) + return nullptr; + } + const DILocation *DIL = Inst.getDebugLoc(); if (!DIL) return Samples; auto it = DILocation2SampleMap.try_emplace(DIL,nullptr); - if (it.second) - it.first->second = Samples->findFunctionSamples(DIL); + if (it.second) { + if (ProfileIsCS) + it.first->second = ContextTracker->getContextSamplesFor(DIL); + else + it.first->second = + Samples->findFunctionSamples(DIL, Reader->getRemapper()); + } return it.first->second; } bool SampleProfileLoader::inlineCallInstruction(CallBase &CB) { + if (ExternalInlineAdvisor) { + auto Advice = ExternalInlineAdvisor->getAdvice(CB); + if (!Advice->isInliningRecommended()) { + Advice->recordUnattemptedInlining(); + return false; + } + // Dummy record, we don't use it for replay. + Advice->recordInlining(); + } + Function *CalledFunction = CB.getCalledFunction(); assert(CalledFunction); DebugLoc DLoc = CB.getDebugLoc(); @@ -938,6 +1028,12 @@ bool SampleProfileLoader::shouldInlineColdCallee(CallBase &CallInst) { InlineCost Cost = getInlineCost(CallInst, getInlineParams(), GetTTI(*Callee), GetAC, GetTLI); + if (Cost.isNever()) + return false; + + if (Cost.isAlways()) + return true; + return Cost.getCost() <= SampleColdCallSiteThreshold; } @@ -995,8 +1091,10 @@ bool SampleProfileLoader::inlineHotFunctions( const FunctionSamples *FS = nullptr; if (auto *CB = dyn_cast(&I)) { if (!isa(I) && (FS = findCalleeFunctionSamples(*CB))) { + assert((!FunctionSamples::UseMD5 || FS->GUIDToFuncNameMap) && + "GUIDToFuncNameMap has to be populated"); AllCandidates.push_back(CB); - if (FS->getEntrySamples() > 0) + if (FS->getEntrySamples() > 0 || ProfileIsCS) localNotInlinedCallSites.try_emplace(CB, FS); if (callsiteIsHot(FS, PSI)) Hot = true; @@ -1005,7 +1103,7 @@ bool SampleProfileLoader::inlineHotFunctions( } } } - if (Hot) { + if (Hot || ExternalInlineAdvisor) { CIS.insert(CIS.begin(), AllCandidates.begin(), AllCandidates.end()); emitOptimizationRemarksForInlineCandidates(AllCandidates, F, true); } else { @@ -1023,29 +1121,28 @@ bool SampleProfileLoader::inlineHotFunctions( continue; uint64_t Sum; for (const auto *FS : findIndirectCallFunctionSamples(*I, Sum)) { - if (IsThinLTOPreLink) { + if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) { FS->findInlinedFunctions(InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold()); continue; } - auto CalleeFunctionName = FS->getFuncName(); + if (!callsiteIsHot(FS, PSI)) + continue; + + const char *Reason = "Callee function not available"; + // R->getValue() != &F is to prevent promoting a recursive call. // If it is a recursive call, we do not inline it as it could bloat // the code exponentially. There is way to better handle this, e.g. // clone the caller first, and inline the cloned caller if it is // recursive. As llvm does not inline recursive calls, we will // simply ignore it instead of handling it explicitly. - if (CalleeFunctionName == F.getName()) - continue; - - if (!callsiteIsHot(FS, PSI)) - continue; - - const char *Reason = "Callee function not available"; + auto CalleeFunctionName = FS->getFuncName(); auto R = SymbolMap.find(CalleeFunctionName); if (R != SymbolMap.end() && R->getValue() && !R->getValue()->isDeclaration() && R->getValue()->getSubprogram() && R->getValue()->hasFnAttribute("use-sample-profile") && + R->getValue() != &F && isLegalToPromote(*I, R->getValue(), &Reason)) { uint64_t C = FS->getEntrySamples(); auto &DI = @@ -1055,6 +1152,8 @@ bool SampleProfileLoader::inlineHotFunctions( // If profile mismatches, we should not attempt to inline DI. if ((isa(DI) || isa(DI)) && inlineCallInstruction(cast(DI))) { + if (ProfileIsCS) + ContextTracker->markContextSamplesInlined(FS); localNotInlinedCallSites.erase(I); LocalChanged = true; ++NumCSInlined; @@ -1068,11 +1167,14 @@ bool SampleProfileLoader::inlineHotFunctions( } else if (CalledFunction && CalledFunction->getSubprogram() && !CalledFunction->isDeclaration()) { if (inlineCallInstruction(*I)) { + if (ProfileIsCS) + ContextTracker->markContextSamplesInlined( + localNotInlinedCallSites[I]); localNotInlinedCallSites.erase(I); LocalChanged = true; ++NumCSInlined; } - } else if (IsThinLTOPreLink) { + } else if (LTOPhase == ThinOrFullLTOPhase::ThinLTOPreLink) { findCalleeFunctionSamples(*I)->findInlinedFunctions( InlinedGUIDs, F.getParent(), PSI->getOrCompHotCountThreshold()); } @@ -1104,16 +1206,23 @@ bool SampleProfileLoader::inlineHotFunctions( } if (ProfileMergeInlinee) { - // Use entry samples as head samples during the merge, as inlinees - // don't have head samples. - assert(FS->getHeadSamples() == 0 && "Expect 0 head sample for inlinee"); - const_cast(FS)->addHeadSamples(FS->getEntrySamples()); - - // Note that we have to do the merge right after processing function. - // This allows OutlineFS's profile to be used for annotation during - // top-down processing of functions' annotation. - FunctionSamples *OutlineFS = Reader->getOrCreateSamplesFor(*Callee); - OutlineFS->merge(*FS); + // A function call can be replicated by optimizations like callsite + // splitting or jump threading and the replicates end up sharing the + // sample nested callee profile instead of slicing the original inlinee's + // profile. We want to do merge exactly once by filtering out callee + // profiles with a non-zero head sample count. + if (FS->getHeadSamples() == 0) { + // Use entry samples as head samples during the merge, as inlinees + // don't have head samples. + const_cast(FS)->addHeadSamples( + FS->getEntrySamples()); + + // Note that we have to do the merge right after processing function. + // This allows OutlineFS's profile to be used for annotation during + // top-down processing of functions' annotation. + FunctionSamples *OutlineFS = Reader->getOrCreateSamplesFor(*Callee); + OutlineFS->merge(*FS); + } } else { auto pair = notInlinedCallInfo.try_emplace(Callee, NotInlinedProfileInfo{0}); @@ -1538,13 +1647,11 @@ void SampleProfileLoader::propagateWeights(Function &F) { if (!DLoc) continue; const DILocation *DIL = DLoc; - uint32_t LineOffset = FunctionSamples::getOffset(DIL); - uint32_t Discriminator = DIL->getBaseDiscriminator(); - const FunctionSamples *FS = findFunctionSamples(I); if (!FS) continue; - auto T = FS->findCallTargetMapAt(LineOffset, Discriminator); + auto CallSite = FunctionSamples::getCallSiteIdentifier(DIL); + auto T = FS->findCallTargetMapAt(CallSite); if (!T || T.get().empty()) continue; SmallVector SortedCallTargets = @@ -1598,8 +1705,6 @@ void SampleProfileLoader::propagateWeights(Function &F) { } } - misexpect::verifyMisExpect(TI, Weights, TI->getContext()); - uint64_t TempWeight; // Only set weights if there is at least one non-zero weight. // In any other case, let the analyzer set weights. @@ -1710,11 +1815,22 @@ void SampleProfileLoader::computeDominanceAndLoopInfo(Function &F) { bool SampleProfileLoader::emitAnnotations(Function &F) { bool Changed = false; - if (getFunctionLoc(F) == 0) - return false; + if (FunctionSamples::ProfileIsProbeBased) { + if (!ProbeManager->profileIsValid(F, *Samples)) { + LLVM_DEBUG( + dbgs() << "Profile is invalid due to CFG mismatch for Function " + << F.getName()); + ++NumMismatchedProfile; + return false; + } + ++NumMatchedProfile; + } else { + if (getFunctionLoc(F) == 0) + return false; - LLVM_DEBUG(dbgs() << "Line number for the first instruction in " - << F.getName() << ": " << getFunctionLoc(F) << "\n"); + LLVM_DEBUG(dbgs() << "Line number for the first instruction in " + << F.getName() << ": " << getFunctionLoc(F) << "\n"); + } DenseSet InlinedGUIDs; Changed |= inlineHotFunctions(F, InlinedGUIDs); @@ -1818,10 +1934,10 @@ SampleProfileLoader::buildFunctionOrder(Module &M, CallGraph *CG) { return FunctionOrderList; } -bool SampleProfileLoader::doInitialization(Module &M) { +bool SampleProfileLoader::doInitialization(Module &M, + FunctionAnalysisManager *FAM) { auto &Ctx = M.getContext(); - std::unique_ptr RemapReader; auto ReaderOrErr = SampleProfileReader::create(Filename, Ctx, RemappingFilename); if (std::error_code EC = ReaderOrErr.getError()) { @@ -1830,8 +1946,14 @@ bool SampleProfileLoader::doInitialization(Module &M) { return false; } Reader = std::move(ReaderOrErr.get()); + Reader->setSkipFlatProf(LTOPhase == ThinOrFullLTOPhase::ThinLTOPostLink); Reader->collectFuncsFrom(M); - ProfileIsValid = (Reader->read() == sampleprof_error::success); + if (std::error_code EC = Reader->read()) { + std::string Msg = "profile reading failed: " + EC.message(); + Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg)); + return false; + } + PSL = Reader->getProfileSymbolList(); // While profile-sample-accurate is on, ignore symbol list. @@ -1843,6 +1965,35 @@ bool SampleProfileLoader::doInitialization(Module &M) { NamesInProfile.insert(NameTable->begin(), NameTable->end()); } + if (FAM && !ProfileInlineReplayFile.empty()) { + ExternalInlineAdvisor = std::make_unique( + M, *FAM, Ctx, /*OriginalAdvisor=*/nullptr, ProfileInlineReplayFile, + /*EmitRemarks=*/false); + if (!ExternalInlineAdvisor->areReplayRemarksLoaded()) + ExternalInlineAdvisor.reset(); + } + + // Apply tweaks if context-sensitive profile is available. + if (Reader->profileIsCS()) { + ProfileIsCS = true; + FunctionSamples::ProfileIsCS = true; + + // Tracker for profiles under different context + ContextTracker = + std::make_unique(Reader->getProfiles()); + } + + // Load pseudo probe descriptors for probe-based function samples. + if (Reader->profileIsProbeBased()) { + ProbeManager = std::make_unique(M); + if (!ProbeManager->moduleIsProbed(M)) { + const char *Msg = + "Pseudo-probe-based profile requires SampleProfileProbePass"; + Ctx.diagnose(DiagnosticInfoSampleProfile(Filename, Msg)); + return false; + } + } + return true; } @@ -1856,8 +2007,6 @@ ModulePass *llvm::createSampleProfileLoaderPass(StringRef Name) { bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM, ProfileSummaryInfo *_PSI, CallGraph *CG) { - if (!ProfileIsValid) - return false; GUIDToFuncNameMapper Mapper(M, *Reader, GUIDToFuncNameMap); PSI = _PSI; @@ -1870,6 +2019,7 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM, for (const auto &I : Reader->getProfiles()) TotalCollectedSamples += I.second.getTotalSamples(); + auto Remapper = Reader->getRemapper(); // Populate the symbol map. for (const auto &N_F : M.getValueSymbolTable()) { StringRef OrigName = N_F.getKey(); @@ -1887,6 +2037,15 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM, // to nullptr to avoid confusion. if (!r.second) r.first->second = nullptr; + OrigName = NewName; + } + // Insert the remapped names into SymbolMap. + if (Remapper) { + if (auto MapName = Remapper->lookUpNameInProfile(OrigName)) { + if (*MapName == OrigName) + continue; + SymbolMap.insert(std::make_pair(*MapName, F)); + } } } @@ -1898,9 +2057,10 @@ bool SampleProfileLoader::runOnModule(Module &M, ModuleAnalysisManager *AM, } // Account for cold calls not inlined.... - for (const std::pair &pair : - notInlinedCallInfo) - updateProfileCallee(pair.first, pair.second.entryCount); + if (!ProfileIsCS) + for (const std::pair &pair : + notInlinedCallInfo) + updateProfileCallee(pair.first, pair.second.entryCount); return retval; } @@ -1915,7 +2075,6 @@ bool SampleProfileLoaderLegacyPass::runOnModule(Module &M) { } bool SampleProfileLoader::runOnFunction(Function &F, ModuleAnalysisManager *AM) { - DILocation2SampleMap.clear(); // By default the entry count is initialized to -1, which will be treated // conservatively by getEntryCount as the same as unknown (None). This is @@ -1957,7 +2116,10 @@ bool SampleProfileLoader::runOnFunction(Function &F, ModuleAnalysisManager *AM) initialEntryCount = -1; } - F.setEntryCount(ProfileCount(initialEntryCount, Function::PCT_Real)); + // Initialize entry count when the function has no existing entry + // count value. + if (!F.getEntryCount().hasValue()) + F.setEntryCount(ProfileCount(initialEntryCount, Function::PCT_Real)); std::unique_ptr OwnedORE; if (AM) { auto &FAM = @@ -1968,7 +2130,12 @@ bool SampleProfileLoader::runOnFunction(Function &F, ModuleAnalysisManager *AM) OwnedORE = std::make_unique(&F); ORE = OwnedORE.get(); } - Samples = Reader->getSamplesFor(F); + + if (ProfileIsCS) + Samples = ContextTracker->getBaseSamplesFor(F); + else + Samples = Reader->getSamplesFor(F); + if (Samples && !Samples->empty()) return emitAnnotations(F); return false; @@ -1993,9 +2160,9 @@ PreservedAnalyses SampleProfileLoaderPass::run(Module &M, ProfileFileName.empty() ? SampleProfileFile : ProfileFileName, ProfileRemappingFileName.empty() ? SampleProfileRemappingFile : ProfileRemappingFileName, - IsThinLTOPreLink, GetAssumptionCache, GetTTI, GetTLI); + LTOPhase, GetAssumptionCache, GetTTI, GetTLI); - if (!SampleLoader.doInitialization(M)) + if (!SampleLoader.doInitialization(M, &FAM)) return PreservedAnalyses::all(); ProfileSummaryInfo *PSI = &AM.getResult(M); diff --git a/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp new file mode 100644 index 000000000000..7cecd20b78d8 --- /dev/null +++ b/llvm/lib/Transforms/IPO/SampleProfileProbe.cpp @@ -0,0 +1,276 @@ +//===- SampleProfileProbe.cpp - Pseudo probe Instrumentation -------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file implements the SampleProfileProber transformation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/IPO/SampleProfileProbe.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/GlobalVariable.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/ProfileData/SampleProf.h" +#include "llvm/Support/CRC.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" +#include + +using namespace llvm; +#define DEBUG_TYPE "sample-profile-probe" + +STATISTIC(ArtificialDbgLine, + "Number of probes that have an artificial debug line"); + +PseudoProbeManager::PseudoProbeManager(const Module &M) { + if (NamedMDNode *FuncInfo = M.getNamedMetadata(PseudoProbeDescMetadataName)) { + for (const auto *Operand : FuncInfo->operands()) { + const auto *MD = cast(Operand); + auto GUID = + mdconst::dyn_extract(MD->getOperand(0))->getZExtValue(); + auto Hash = + mdconst::dyn_extract(MD->getOperand(1))->getZExtValue(); + GUIDToProbeDescMap.try_emplace(GUID, PseudoProbeDescriptor(GUID, Hash)); + } + } +} + +const PseudoProbeDescriptor * +PseudoProbeManager::getDesc(const Function &F) const { + auto I = GUIDToProbeDescMap.find( + Function::getGUID(FunctionSamples::getCanonicalFnName(F))); + return I == GUIDToProbeDescMap.end() ? nullptr : &I->second; +} + +bool PseudoProbeManager::moduleIsProbed(const Module &M) const { + return M.getNamedMetadata(PseudoProbeDescMetadataName); +} + +bool PseudoProbeManager::profileIsValid(const Function &F, + const FunctionSamples &Samples) const { + const auto *Desc = getDesc(F); + if (!Desc) { + LLVM_DEBUG(dbgs() << "Probe descriptor missing for Function " << F.getName() + << "\n"); + return false; + } else { + if (Desc->getFunctionHash() != Samples.getFunctionHash()) { + LLVM_DEBUG(dbgs() << "Hash mismatch for Function " << F.getName() + << "\n"); + return false; + } + } + return true; +} + +SampleProfileProber::SampleProfileProber(Function &Func, + const std::string &CurModuleUniqueId) + : F(&Func), CurModuleUniqueId(CurModuleUniqueId) { + BlockProbeIds.clear(); + CallProbeIds.clear(); + LastProbeId = (uint32_t)PseudoProbeReservedId::Last; + computeProbeIdForBlocks(); + computeProbeIdForCallsites(); + computeCFGHash(); +} + +// Compute Hash value for the CFG: the lower 32 bits are CRC32 of the index +// value of each BB in the CFG. The higher 32 bits record the number of edges +// preceded by the number of indirect calls. +// This is derived from FuncPGOInstrumentation::computeCFGHash(). +void SampleProfileProber::computeCFGHash() { + std::vector Indexes; + JamCRC JC; + for (auto &BB : *F) { + auto *TI = BB.getTerminator(); + for (unsigned I = 0, E = TI->getNumSuccessors(); I != E; ++I) { + auto *Succ = TI->getSuccessor(I); + auto Index = getBlockId(Succ); + for (int J = 0; J < 4; J++) + Indexes.push_back((uint8_t)(Index >> (J * 8))); + } + } + + JC.update(Indexes); + + FunctionHash = (uint64_t)CallProbeIds.size() << 48 | + (uint64_t)Indexes.size() << 32 | JC.getCRC(); + // Reserve bit 60-63 for other information purpose. + FunctionHash &= 0x0FFFFFFFFFFFFFFF; + assert(FunctionHash && "Function checksum should not be zero"); + LLVM_DEBUG(dbgs() << "\nFunction Hash Computation for " << F->getName() + << ":\n" + << " CRC = " << JC.getCRC() << ", Edges = " + << Indexes.size() << ", ICSites = " << CallProbeIds.size() + << ", Hash = " << FunctionHash << "\n"); +} + +void SampleProfileProber::computeProbeIdForBlocks() { + for (auto &BB : *F) { + BlockProbeIds[&BB] = ++LastProbeId; + } +} + +void SampleProfileProber::computeProbeIdForCallsites() { + for (auto &BB : *F) { + for (auto &I : BB) { + if (!isa(I)) + continue; + if (isa(&I)) + continue; + CallProbeIds[&I] = ++LastProbeId; + } + } +} + +uint32_t SampleProfileProber::getBlockId(const BasicBlock *BB) const { + auto I = BlockProbeIds.find(const_cast(BB)); + return I == BlockProbeIds.end() ? 0 : I->second; +} + +uint32_t SampleProfileProber::getCallsiteId(const Instruction *Call) const { + auto Iter = CallProbeIds.find(const_cast(Call)); + return Iter == CallProbeIds.end() ? 0 : Iter->second; +} + +void SampleProfileProber::instrumentOneFunc(Function &F, TargetMachine *TM) { + Module *M = F.getParent(); + MDBuilder MDB(F.getContext()); + // Compute a GUID without considering the function's linkage type. This is + // fine since function name is the only key in the profile database. + uint64_t Guid = Function::getGUID(F.getName()); + + // Assign an artificial debug line to a probe that doesn't come with a real + // line. A probe not having a debug line will get an incomplete inline + // context. This will cause samples collected on the probe to be counted + // into the base profile instead of a context profile. The line number + // itself is not important though. + auto AssignDebugLoc = [&](Instruction *I) { + assert((isa(I) || isa(I)) && + "Expecting pseudo probe or call instructions"); + if (!I->getDebugLoc()) { + if (auto *SP = F.getSubprogram()) { + auto DIL = DILocation::get(SP->getContext(), 0, 0, SP); + I->setDebugLoc(DIL); + ArtificialDbgLine++; + LLVM_DEBUG({ + dbgs() << "\nIn Function " << F.getName() + << " Probe gets an artificial debug line\n"; + I->dump(); + }); + } + } + }; + + // Probe basic blocks. + for (auto &I : BlockProbeIds) { + BasicBlock *BB = I.first; + uint32_t Index = I.second; + // Insert a probe before an instruction with a valid debug line number which + // will be assigned to the probe. The line number will be used later to + // model the inline context when the probe is inlined into other functions. + // Debug instructions, phi nodes and lifetime markers do not have an valid + // line number. Real instructions generated by optimizations may not come + // with a line number either. + auto HasValidDbgLine = [](Instruction *J) { + return !isa(J) && !isa(J) && + !J->isLifetimeStartOrEnd() && J->getDebugLoc(); + }; + + Instruction *J = &*BB->getFirstInsertionPt(); + while (J != BB->getTerminator() && !HasValidDbgLine(J)) { + J = J->getNextNode(); + } + + IRBuilder<> Builder(J); + assert(Builder.GetInsertPoint() != BB->end() && + "Cannot get the probing point"); + Function *ProbeFn = + llvm::Intrinsic::getDeclaration(M, Intrinsic::pseudoprobe); + Value *Args[] = {Builder.getInt64(Guid), Builder.getInt64(Index), + Builder.getInt32(0)}; + auto *Probe = Builder.CreateCall(ProbeFn, Args); + AssignDebugLoc(Probe); + } + + // Probe both direct calls and indirect calls. Direct calls are probed so that + // their probe ID can be used as an call site identifier to represent a + // calling context. + for (auto &I : CallProbeIds) { + auto *Call = I.first; + uint32_t Index = I.second; + uint32_t Type = cast(Call)->getCalledFunction() + ? (uint32_t)PseudoProbeType::DirectCall + : (uint32_t)PseudoProbeType::IndirectCall; + AssignDebugLoc(Call); + // Levarge the 32-bit discriminator field of debug data to store the ID and + // type of a callsite probe. This gets rid of the dependency on plumbing a + // customized metadata through the codegen pipeline. + uint32_t V = PseudoProbeDwarfDiscriminator::packProbeData(Index, Type); + if (auto DIL = Call->getDebugLoc()) { + DIL = DIL->cloneWithDiscriminator(V); + Call->setDebugLoc(DIL); + } + } + + // Create module-level metadata that contains function info necessary to + // synthesize probe-based sample counts, which are + // - FunctionGUID + // - FunctionHash. + // - FunctionName + auto Hash = getFunctionHash(); + auto *MD = MDB.createPseudoProbeDesc(Guid, Hash, &F); + auto *NMD = M->getNamedMetadata(PseudoProbeDescMetadataName); + assert(NMD && "llvm.pseudo_probe_desc should be pre-created"); + NMD->addOperand(MD); + + // Preserve a comdat group to hold all probes materialized later. This + // allows that when the function is considered dead and removed, the + // materialized probes are disposed too. + // Imported functions are defined in another module. They do not need + // the following handling since same care will be taken for them in their + // original module. The pseudo probes inserted into an imported functions + // above will naturally not be emitted since the imported function is free + // from object emission. However they will be emitted together with the + // inliner functions that the imported function is inlined into. We are not + // creating a comdat group for an import function since it's useless anyway. + if (!F.isDeclarationForLinker()) { + if (TM) { + auto Triple = TM->getTargetTriple(); + if (Triple.supportsCOMDAT() && TM->getFunctionSections()) { + GetOrCreateFunctionComdat(F, Triple, CurModuleUniqueId); + } + } + } +} + +PreservedAnalyses SampleProfileProbePass::run(Module &M, + ModuleAnalysisManager &AM) { + auto ModuleId = getUniqueModuleId(&M); + // Create the pseudo probe desc metadata beforehand. + // Note that modules with only data but no functions will require this to + // be set up so that they will be known as probed later. + M.getOrInsertNamedMetadata(PseudoProbeDescMetadataName); + + for (auto &F : M) { + if (F.isDeclaration()) + continue; + SampleProfileProber ProbeManager(F, ModuleId); + ProbeManager.instrumentOneFunc(F, TM); + } + + return PreservedAnalyses::none(); +} diff --git a/llvm/lib/Transforms/IPO/StripSymbols.cpp b/llvm/lib/Transforms/IPO/StripSymbols.cpp index 088091df770f..4fc71847a070 100644 --- a/llvm/lib/Transforms/IPO/StripSymbols.cpp +++ b/llvm/lib/Transforms/IPO/StripSymbols.cpp @@ -19,18 +19,21 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/IPO/StripSymbols.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/TypeFinder.h" #include "llvm/IR/ValueSymbolTable.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/Utils/Local.h" + using namespace llvm; namespace { @@ -249,9 +252,7 @@ bool StripNonDebugSymbols::runOnModule(Module &M) { return StripSymbolNames(M, true); } -bool StripDebugDeclare::runOnModule(Module &M) { - if (skipModule(M)) - return false; +static bool stripDebugDeclareImpl(Module &M) { Function *Declare = M.getFunction("llvm.dbg.declare"); std::vector DeadConstants; @@ -289,17 +290,13 @@ bool StripDebugDeclare::runOnModule(Module &M) { return true; } -/// Remove any debug info for global variables/functions in the given module for -/// which said global variable/function no longer exists (i.e. is null). -/// -/// Debugging information is encoded in llvm IR using metadata. This is designed -/// such a way that debug info for symbols preserved even if symbols are -/// optimized away by the optimizer. This special pass removes debug info for -/// such symbols. -bool StripDeadDebugInfo::runOnModule(Module &M) { +bool StripDebugDeclare::runOnModule(Module &M) { if (skipModule(M)) return false; + return stripDebugDeclareImpl(M); +} +static bool stripDeadDebugInfoImpl(Module &M) { bool Changed = false; LLVMContext &C = M.getContext(); @@ -380,3 +377,40 @@ bool StripDeadDebugInfo::runOnModule(Module &M) { return Changed; } + +/// Remove any debug info for global variables/functions in the given module for +/// which said global variable/function no longer exists (i.e. is null). +/// +/// Debugging information is encoded in llvm IR using metadata. This is designed +/// such a way that debug info for symbols preserved even if symbols are +/// optimized away by the optimizer. This special pass removes debug info for +/// such symbols. +bool StripDeadDebugInfo::runOnModule(Module &M) { + if (skipModule(M)) + return false; + return stripDeadDebugInfoImpl(M); +} + +PreservedAnalyses StripSymbolsPass::run(Module &M, ModuleAnalysisManager &AM) { + StripDebugInfo(M); + StripSymbolNames(M, false); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripNonDebugSymbolsPass::run(Module &M, + ModuleAnalysisManager &AM) { + StripSymbolNames(M, true); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripDebugDeclarePass::run(Module &M, + ModuleAnalysisManager &AM) { + stripDebugDeclareImpl(M); + return PreservedAnalyses::all(); +} + +PreservedAnalyses StripDeadDebugInfoPass::run(Module &M, + ModuleAnalysisManager &AM) { + stripDeadDebugInfoImpl(M); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp index 87a18171787f..225b4fe95f67 100644 --- a/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp +++ b/llvm/lib/Transforms/IPO/ThinLTOBitcodeWriter.cpp @@ -14,6 +14,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfo.h" +#include "llvm/IR/Instructions.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" @@ -260,7 +261,7 @@ void splitAndWriteThinLTOBitcode( if (!RT || RT->getBitWidth() > 64 || F->arg_empty() || !F->arg_begin()->use_empty()) return; - for (auto &Arg : make_range(std::next(F->arg_begin()), F->arg_end())) { + for (auto &Arg : drop_begin(F->args())) { auto *ArgT = dyn_cast(Arg.getType()); if (!ArgT || ArgT->getBitWidth() > 64) return; @@ -333,8 +334,7 @@ void splitAndWriteThinLTOBitcode( Linkage = CFL_Declaration; Elts.push_back(ConstantAsMetadata::get( llvm::ConstantInt::get(Type::getInt8Ty(Ctx), Linkage))); - for (auto Type : Types) - Elts.push_back(Type); + append_range(Elts, Types); CfiFunctionMDs.push_back(MDTuple::get(Ctx, Elts)); } diff --git a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp index 5a25f9857665..cf1ff405c493 100644 --- a/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ b/llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -59,7 +59,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Triple.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/TypeMetadataUtils.h" @@ -470,7 +470,7 @@ CallSiteInfo &VTableSlotInfo::findCallSiteInfo(CallBase &CB) { auto *CBType = dyn_cast(CB.getType()); if (!CBType || CBType->getBitWidth() > 64 || CB.arg_empty()) return CSInfo; - for (auto &&Arg : make_range(CB.arg_begin() + 1, CB.arg_end())) { + for (auto &&Arg : drop_begin(CB.args())) { auto *CI = dyn_cast(Arg); if (!CI || CI->getBitWidth() > 64) return CSInfo; @@ -753,6 +753,11 @@ PreservedAnalyses WholeProgramDevirtPass::run(Module &M, auto LookupDomTree = [&FAM](Function &F) -> DominatorTree & { return FAM.getResult(F); }; + if (UseCommandLine) { + if (DevirtModule::runForTesting(M, AARGetter, OREGetter, LookupDomTree)) + return PreservedAnalyses::all(); + return PreservedAnalyses::none(); + } if (!DevirtModule(M, AARGetter, OREGetter, LookupDomTree, ExportSummary, ImportSummary) .run()) @@ -1025,6 +1030,10 @@ bool DevirtIndex::tryFindVirtualCallTargets( void DevirtModule::applySingleImplDevirt(VTableSlotInfo &SlotInfo, Constant *TheFn, bool &IsExported) { + // Don't devirtualize function if we're told to skip it + // in -wholeprogramdevirt-skip. + if (FunctionsToSkip.match(TheFn->stripPointerCasts()->getName())) + return; auto Apply = [&](CallSiteInfo &CSInfo) { for (auto &&VCallSite : CSInfo.CallSites) { if (RemarksEnabled) @@ -1258,7 +1267,7 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo, // Jump tables are only profitable if the retpoline mitigation is enabled. Attribute FSAttr = CB.getCaller()->getFnAttribute("target-features"); - if (FSAttr.hasAttribute(Attribute::None) || + if (!FSAttr.isValid() || !FSAttr.getValueAsString().contains("+retpoline")) continue; @@ -1270,8 +1279,7 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo, // x86_64. std::vector NewArgs; NewArgs.push_back(Int8PtrTy); - for (Type *T : CB.getFunctionType()->params()) - NewArgs.push_back(T); + append_range(NewArgs, CB.getFunctionType()->params()); FunctionType *NewFT = FunctionType::get(CB.getFunctionType()->getReturnType(), NewArgs, CB.getFunctionType()->isVarArg()); @@ -1280,7 +1288,7 @@ void DevirtModule::applyICallBranchFunnel(VTableSlotInfo &SlotInfo, IRBuilder<> IRB(&CB); std::vector Args; Args.push_back(IRB.CreateBitCast(VCallSite.VTable, Int8PtrTy)); - Args.insert(Args.end(), CB.arg_begin(), CB.arg_end()); + llvm::append_range(Args, CB.args()); CallBase *NewCS = nullptr; if (isa(CB)) @@ -2205,6 +2213,4 @@ void DevirtIndex::run() { if (PrintSummaryDevirt) for (const auto &DT : DevirtTargets) errs() << "Devirtualized call to " << DT << "\n"; - - return; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index a7f5e0a7774d..bacb8689892a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -29,6 +29,7 @@ #include "llvm/Support/AlignOf.h" #include "llvm/Support/Casting.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include #include @@ -81,11 +82,11 @@ namespace { private: bool insaneIntVal(int V) { return V > 4 || V < -4; } - APFloat *getFpValPtr() - { return reinterpret_cast(&FpValBuf.buffer[0]); } + APFloat *getFpValPtr() { return reinterpret_cast(&FpValBuf); } - const APFloat *getFpValPtr() const - { return reinterpret_cast(&FpValBuf.buffer[0]); } + const APFloat *getFpValPtr() const { + return reinterpret_cast(&FpValBuf); + } const APFloat &getFpVal() const { assert(IsFp && BufHasFpVal && "Incorret state"); @@ -860,7 +861,7 @@ static Instruction *foldNoWrapAdd(BinaryOperator &Add, return nullptr; } -Instruction *InstCombiner::foldAddWithConstant(BinaryOperator &Add) { +Instruction *InstCombinerImpl::foldAddWithConstant(BinaryOperator &Add) { Value *Op0 = Add.getOperand(0), *Op1 = Add.getOperand(1); Constant *Op1C; if (!match(Op1, m_Constant(Op1C))) @@ -886,15 +887,15 @@ Instruction *InstCombiner::foldAddWithConstant(BinaryOperator &Add) { // zext(bool) + C -> bool ? C + 1 : C if (match(Op0, m_ZExt(m_Value(X))) && X->getType()->getScalarSizeInBits() == 1) - return SelectInst::Create(X, AddOne(Op1C), Op1); + return SelectInst::Create(X, InstCombiner::AddOne(Op1C), Op1); // sext(bool) + C -> bool ? C - 1 : C if (match(Op0, m_SExt(m_Value(X))) && X->getType()->getScalarSizeInBits() == 1) - return SelectInst::Create(X, SubOne(Op1C), Op1); + return SelectInst::Create(X, InstCombiner::SubOne(Op1C), Op1); // ~X + C --> (C-1) - X if (match(Op0, m_Not(m_Value(X)))) - return BinaryOperator::CreateSub(SubOne(Op1C), X); + return BinaryOperator::CreateSub(InstCombiner::SubOne(Op1C), X); const APInt *C; if (!match(Op1, m_APInt(C))) @@ -923,6 +924,39 @@ Instruction *InstCombiner::foldAddWithConstant(BinaryOperator &Add) { C2->isMinSignedValue() && C2->sext(Ty->getScalarSizeInBits()) == *C) return CastInst::Create(Instruction::SExt, X, Ty); + if (match(Op0, m_Xor(m_Value(X), m_APInt(C2)))) { + // (X ^ signmask) + C --> (X + (signmask ^ C)) + if (C2->isSignMask()) + return BinaryOperator::CreateAdd(X, ConstantInt::get(Ty, *C2 ^ *C)); + + // If X has no high-bits set above an xor mask: + // add (xor X, LowMaskC), C --> sub (LowMaskC + C), X + if (C2->isMask()) { + KnownBits LHSKnown = computeKnownBits(X, 0, &Add); + if ((*C2 | LHSKnown.Zero).isAllOnesValue()) + return BinaryOperator::CreateSub(ConstantInt::get(Ty, *C2 + *C), X); + } + + // Look for a math+logic pattern that corresponds to sext-in-register of a + // value with cleared high bits. Convert that into a pair of shifts: + // add (xor X, 0x80), 0xF..F80 --> (X << ShAmtC) >>s ShAmtC + // add (xor X, 0xF..F80), 0x80 --> (X << ShAmtC) >>s ShAmtC + if (Op0->hasOneUse() && *C2 == -(*C)) { + unsigned BitWidth = Ty->getScalarSizeInBits(); + unsigned ShAmt = 0; + if (C->isPowerOf2()) + ShAmt = BitWidth - C->logBase2() - 1; + else if (C2->isPowerOf2()) + ShAmt = BitWidth - C2->logBase2() - 1; + if (ShAmt && MaskedValueIsZero(X, APInt::getHighBitsSet(BitWidth, ShAmt), + 0, &Add)) { + Constant *ShAmtC = ConstantInt::get(Ty, ShAmt); + Value *NewShl = Builder.CreateShl(X, ShAmtC, "sext"); + return BinaryOperator::CreateAShr(NewShl, ShAmtC); + } + } + } + if (C->isOneValue() && Op0->hasOneUse()) { // add (sext i1 X), 1 --> zext (not X) // TODO: The smallest IR representation is (select X, 0, 1), and that would @@ -943,6 +977,15 @@ Instruction *InstCombiner::foldAddWithConstant(BinaryOperator &Add) { } } + // If all bits affected by the add are included in a high-bit-mask, do the + // add before the mask op: + // (X & 0xFF00) + xx00 --> (X + xx00) & 0xFF00 + if (match(Op0, m_OneUse(m_And(m_Value(X), m_APInt(C2)))) && + C2->isNegative() && C2->isShiftedMask() && *C == (*C & *C2)) { + Value *NewAdd = Builder.CreateAdd(X, ConstantInt::get(Ty, *C)); + return BinaryOperator::CreateAnd(NewAdd, ConstantInt::get(Ty, *C2)); + } + return nullptr; } @@ -1021,7 +1064,7 @@ static bool MulWillOverflow(APInt &C0, APInt &C1, bool IsSigned) { // Simplifies X % C0 + (( X / C0 ) % C1) * C0 to X % (C0 * C1), where (C0 * C1) // does not overflow. -Value *InstCombiner::SimplifyAddWithRemainder(BinaryOperator &I) { +Value *InstCombinerImpl::SimplifyAddWithRemainder(BinaryOperator &I) { Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); Value *X, *MulOpV; APInt C0, MulOpC; @@ -1097,9 +1140,9 @@ static Instruction *foldToUnsignedSaturatedAdd(BinaryOperator &I) { return nullptr; } -Instruction * -InstCombiner::canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract( - BinaryOperator &I) { +Instruction *InstCombinerImpl:: + canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract( + BinaryOperator &I) { assert((I.getOpcode() == Instruction::Add || I.getOpcode() == Instruction::Or || I.getOpcode() == Instruction::Sub) && @@ -1198,7 +1241,44 @@ InstCombiner::canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract( return TruncInst::CreateTruncOrBitCast(NewAShr, I.getType()); } -Instruction *InstCombiner::visitAdd(BinaryOperator &I) { +/// This is a specialization of a more general transform from +/// SimplifyUsingDistributiveLaws. If that code can be made to work optimally +/// for multi-use cases or propagating nsw/nuw, then we would not need this. +static Instruction *factorizeMathWithShlOps(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + // TODO: Also handle mul by doubling the shift amount? + assert((I.getOpcode() == Instruction::Add || + I.getOpcode() == Instruction::Sub) && + "Expected add/sub"); + auto *Op0 = dyn_cast(I.getOperand(0)); + auto *Op1 = dyn_cast(I.getOperand(1)); + if (!Op0 || !Op1 || !(Op0->hasOneUse() || Op1->hasOneUse())) + return nullptr; + + Value *X, *Y, *ShAmt; + if (!match(Op0, m_Shl(m_Value(X), m_Value(ShAmt))) || + !match(Op1, m_Shl(m_Value(Y), m_Specific(ShAmt)))) + return nullptr; + + // No-wrap propagates only when all ops have no-wrap. + bool HasNSW = I.hasNoSignedWrap() && Op0->hasNoSignedWrap() && + Op1->hasNoSignedWrap(); + bool HasNUW = I.hasNoUnsignedWrap() && Op0->hasNoUnsignedWrap() && + Op1->hasNoUnsignedWrap(); + + // add/sub (X << ShAmt), (Y << ShAmt) --> (add/sub X, Y) << ShAmt + Value *NewMath = Builder.CreateBinOp(I.getOpcode(), X, Y); + if (auto *NewI = dyn_cast(NewMath)) { + NewI->setHasNoSignedWrap(HasNSW); + NewI->setHasNoUnsignedWrap(HasNUW); + } + auto *NewShl = BinaryOperator::CreateShl(NewMath, ShAmt); + NewShl->setHasNoSignedWrap(HasNSW); + NewShl->setHasNoUnsignedWrap(HasNUW); + return NewShl; +} + +Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) { if (Value *V = SimplifyAddInst(I.getOperand(0), I.getOperand(1), I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), SQ.getWithInstruction(&I))) @@ -1214,59 +1294,17 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) { if (Value *V = SimplifyUsingDistributiveLaws(I)) return replaceInstUsesWith(I, V); + if (Instruction *R = factorizeMathWithShlOps(I, Builder)) + return R; + if (Instruction *X = foldAddWithConstant(I)) return X; if (Instruction *X = foldNoWrapAdd(I, Builder)) return X; - // FIXME: This should be moved into the above helper function to allow these - // transforms for general constant or constant splat vectors. Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); Type *Ty = I.getType(); - if (ConstantInt *CI = dyn_cast(RHS)) { - Value *XorLHS = nullptr; ConstantInt *XorRHS = nullptr; - if (match(LHS, m_Xor(m_Value(XorLHS), m_ConstantInt(XorRHS)))) { - unsigned TySizeBits = Ty->getScalarSizeInBits(); - const APInt &RHSVal = CI->getValue(); - unsigned ExtendAmt = 0; - // If we have ADD(XOR(AND(X, 0xFF), 0x80), 0xF..F80), it's a sext. - // If we have ADD(XOR(AND(X, 0xFF), 0xF..F80), 0x80), it's a sext. - if (XorRHS->getValue() == -RHSVal) { - if (RHSVal.isPowerOf2()) - ExtendAmt = TySizeBits - RHSVal.logBase2() - 1; - else if (XorRHS->getValue().isPowerOf2()) - ExtendAmt = TySizeBits - XorRHS->getValue().logBase2() - 1; - } - - if (ExtendAmt) { - APInt Mask = APInt::getHighBitsSet(TySizeBits, ExtendAmt); - if (!MaskedValueIsZero(XorLHS, Mask, 0, &I)) - ExtendAmt = 0; - } - - if (ExtendAmt) { - Constant *ShAmt = ConstantInt::get(Ty, ExtendAmt); - Value *NewShl = Builder.CreateShl(XorLHS, ShAmt, "sext"); - return BinaryOperator::CreateAShr(NewShl, ShAmt); - } - - // If this is a xor that was canonicalized from a sub, turn it back into - // a sub and fuse this add with it. - if (LHS->hasOneUse() && (XorRHS->getValue()+1).isPowerOf2()) { - KnownBits LHSKnown = computeKnownBits(XorLHS, 0, &I); - if ((XorRHS->getValue() | LHSKnown.Zero).isAllOnesValue()) - return BinaryOperator::CreateSub(ConstantExpr::getAdd(XorRHS, CI), - XorLHS); - } - // (X + signmask) + C could have gotten canonicalized to (X^signmask) + C, - // transform them into (X + (signmask ^ C)) - if (XorRHS->getValue().isSignMask()) - return BinaryOperator::CreateAdd(XorLHS, - ConstantExpr::getXor(XorRHS, CI)); - } - } - if (Ty->isIntOrIntVectorTy(1)) return BinaryOperator::CreateXor(LHS, RHS); @@ -1329,34 +1367,6 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) { if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT)) return BinaryOperator::CreateOr(LHS, RHS); - // FIXME: We already did a check for ConstantInt RHS above this. - // FIXME: Is this pattern covered by another fold? No regression tests fail on - // removal. - if (ConstantInt *CRHS = dyn_cast(RHS)) { - // (X & FF00) + xx00 -> (X+xx00) & FF00 - Value *X; - ConstantInt *C2; - if (LHS->hasOneUse() && - match(LHS, m_And(m_Value(X), m_ConstantInt(C2))) && - CRHS->getValue() == (CRHS->getValue() & C2->getValue())) { - // See if all bits from the first bit set in the Add RHS up are included - // in the mask. First, get the rightmost bit. - const APInt &AddRHSV = CRHS->getValue(); - - // Form a mask of all bits from the lowest bit added through the top. - APInt AddRHSHighBits(~((AddRHSV & -AddRHSV)-1)); - - // See if the and mask includes all of these bits. - APInt AddRHSHighBitsAnd(AddRHSHighBits & C2->getValue()); - - if (AddRHSHighBits == AddRHSHighBitsAnd) { - // Okay, the xform is safe. Insert the new add pronto. - Value *NewAdd = Builder.CreateAdd(X, CRHS, LHS->getName()); - return BinaryOperator::CreateAnd(NewAdd, C2); - } - } - } - // add (select X 0 (sub n A)) A --> select X A n { SelectInst *SI = dyn_cast(LHS); @@ -1424,6 +1434,14 @@ Instruction *InstCombiner::visitAdd(BinaryOperator &I) { if (Instruction *SatAdd = foldToUnsignedSaturatedAdd(I)) return SatAdd; + // usub.sat(A, B) + B => umax(A, B) + if (match(&I, m_c_BinOp( + m_OneUse(m_Intrinsic(m_Value(A), m_Value(B))), + m_Deferred(B)))) { + return replaceInstUsesWith(I, + Builder.CreateIntrinsic(Intrinsic::umax, {I.getType()}, {A, B})); + } + return Changed ? &I : nullptr; } @@ -1486,7 +1504,7 @@ static Instruction *factorizeFAddFSub(BinaryOperator &I, : BinaryOperator::CreateFDivFMF(XY, Z, &I); } -Instruction *InstCombiner::visitFAdd(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) { if (Value *V = SimplifyFAddInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), SQ.getWithInstruction(&I))) @@ -1600,49 +1618,33 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) { /// Optimize pointer differences into the same array into a size. Consider: /// &A[10] - &A[0]: we should compile this to "10". LHS/RHS are the pointer /// operands to the ptrtoint instructions for the LHS/RHS of the subtract. -Value *InstCombiner::OptimizePointerDifference(Value *LHS, Value *RHS, - Type *Ty, bool IsNUW) { +Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS, + Type *Ty, bool IsNUW) { // If LHS is a gep based on RHS or RHS is a gep based on LHS, we can optimize // this. bool Swapped = false; GEPOperator *GEP1 = nullptr, *GEP2 = nullptr; + if (!isa(LHS) && isa(RHS)) { + std::swap(LHS, RHS); + Swapped = true; + } - // For now we require one side to be the base pointer "A" or a constant - // GEP derived from it. - if (GEPOperator *LHSGEP = dyn_cast(LHS)) { + // Require at least one GEP with a common base pointer on both sides. + if (auto *LHSGEP = dyn_cast(LHS)) { // (gep X, ...) - X if (LHSGEP->getOperand(0) == RHS) { GEP1 = LHSGEP; - Swapped = false; - } else if (GEPOperator *RHSGEP = dyn_cast(RHS)) { + } else if (auto *RHSGEP = dyn_cast(RHS)) { // (gep X, ...) - (gep X, ...) if (LHSGEP->getOperand(0)->stripPointerCasts() == - RHSGEP->getOperand(0)->stripPointerCasts()) { - GEP2 = RHSGEP; + RHSGEP->getOperand(0)->stripPointerCasts()) { GEP1 = LHSGEP; - Swapped = false; - } - } - } - - if (GEPOperator *RHSGEP = dyn_cast(RHS)) { - // X - (gep X, ...) - if (RHSGEP->getOperand(0) == LHS) { - GEP1 = RHSGEP; - Swapped = true; - } else if (GEPOperator *LHSGEP = dyn_cast(LHS)) { - // (gep X, ...) - (gep X, ...) - if (RHSGEP->getOperand(0)->stripPointerCasts() == - LHSGEP->getOperand(0)->stripPointerCasts()) { - GEP2 = LHSGEP; - GEP1 = RHSGEP; - Swapped = true; + GEP2 = RHSGEP; } } } if (!GEP1) - // No GEP found. return nullptr; if (GEP2) { @@ -1670,19 +1672,18 @@ Value *InstCombiner::OptimizePointerDifference(Value *LHS, Value *RHS, Value *Result = EmitGEPOffset(GEP1); // If this is a single inbounds GEP and the original sub was nuw, - // then the final multiplication is also nuw. We match an extra add zero - // here, because that's what EmitGEPOffset() generates. - Instruction *I; - if (IsNUW && !GEP2 && !Swapped && GEP1->isInBounds() && - match(Result, m_Add(m_Instruction(I), m_Zero())) && - I->getOpcode() == Instruction::Mul) - I->setHasNoUnsignedWrap(); - - // If we had a constant expression GEP on the other side offsetting the - // pointer, subtract it from the offset we have. + // then the final multiplication is also nuw. + if (auto *I = dyn_cast(Result)) + if (IsNUW && !GEP2 && !Swapped && GEP1->isInBounds() && + I->getOpcode() == Instruction::Mul) + I->setHasNoUnsignedWrap(); + + // If we have a 2nd GEP of the same base pointer, subtract the offsets. + // If both GEPs are inbounds, then the subtract does not have signed overflow. if (GEP2) { Value *Offset = EmitGEPOffset(GEP2); - Result = Builder.CreateSub(Result, Offset); + Result = Builder.CreateSub(Result, Offset, "gepdiff", /* NUW */ false, + GEP1->isInBounds() && GEP2->isInBounds()); } // If we have p - gep(p, ...) then we have to negate the result. @@ -1692,7 +1693,7 @@ Value *InstCombiner::OptimizePointerDifference(Value *LHS, Value *RHS, return Builder.CreateIntCast(Result, Ty, true); } -Instruction *InstCombiner::visitSub(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { if (Value *V = SimplifySubInst(I.getOperand(0), I.getOperand(1), I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), SQ.getWithInstruction(&I))) @@ -1721,6 +1722,19 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { return Res; } + // Try this before Negator to preserve NSW flag. + if (Instruction *R = factorizeMathWithShlOps(I, Builder)) + return R; + + if (Constant *C = dyn_cast(Op0)) { + Value *X; + Constant *C2; + + // C-(X+C2) --> (C-C2)-X + if (match(Op1, m_Add(m_Value(X), m_Constant(C2)))) + return BinaryOperator::CreateSub(ConstantExpr::getSub(C, C2), X); + } + auto TryToNarrowDeduceFlags = [this, &I, &Op0, &Op1]() -> Instruction * { if (Instruction *Ext = narrowMathIfNoOverflow(I)) return Ext; @@ -1788,8 +1802,7 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { } auto m_AddRdx = [](Value *&Vec) { - return m_OneUse( - m_Intrinsic(m_Value(Vec))); + return m_OneUse(m_Intrinsic(m_Value(Vec))); }; Value *V0, *V1; if (match(Op0, m_AddRdx(V0)) && match(Op1, m_AddRdx(V1)) && @@ -1797,8 +1810,8 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { // Difference of sums is sum of differences: // add_rdx(V0) - add_rdx(V1) --> add_rdx(V0 - V1) Value *Sub = Builder.CreateSub(V0, V1); - Value *Rdx = Builder.CreateIntrinsic( - Intrinsic::experimental_vector_reduce_add, {Sub->getType()}, {Sub}); + Value *Rdx = Builder.CreateIntrinsic(Intrinsic::vector_reduce_add, + {Sub->getType()}, {Sub}); return replaceInstUsesWith(I, Rdx); } @@ -1806,14 +1819,14 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { Value *X; if (match(Op1, m_ZExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)) // C - (zext bool) --> bool ? C - 1 : C - return SelectInst::Create(X, SubOne(C), C); + return SelectInst::Create(X, InstCombiner::SubOne(C), C); if (match(Op1, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1)) // C - (sext bool) --> bool ? C + 1 : C - return SelectInst::Create(X, AddOne(C), C); + return SelectInst::Create(X, InstCombiner::AddOne(C), C); // C - ~X == X + (1+C) if (match(Op1, m_Not(m_Value(X)))) - return BinaryOperator::CreateAdd(X, AddOne(C)); + return BinaryOperator::CreateAdd(X, InstCombiner::AddOne(C)); // Try to fold constant sub into select arguments. if (SelectInst *SI = dyn_cast(Op1)) @@ -1828,12 +1841,8 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { Constant *C2; // C-(C2-X) --> X+(C-C2) - if (match(Op1, m_Sub(m_Constant(C2), m_Value(X))) && !isa(C2)) + if (match(Op1, m_Sub(m_ImmConstant(C2), m_Value(X)))) return BinaryOperator::CreateAdd(X, ConstantExpr::getSub(C, C2)); - - // C-(X+C2) --> (C-C2)-X - if (match(Op1, m_Add(m_Value(X), m_Constant(C2)))) - return BinaryOperator::CreateSub(ConstantExpr::getSub(C, C2), X); } const APInt *Op0C; @@ -1864,6 +1873,22 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { return BinaryOperator::CreateXor(A, B); } + // (sub (add A, B) (or A, B)) --> (and A, B) + { + Value *A, *B; + if (match(Op0, m_Add(m_Value(A), m_Value(B))) && + match(Op1, m_c_Or(m_Specific(A), m_Specific(B)))) + return BinaryOperator::CreateAnd(A, B); + } + + // (sub (add A, B) (and A, B)) --> (or A, B) + { + Value *A, *B; + if (match(Op0, m_Add(m_Value(A), m_Value(B))) && + match(Op1, m_c_And(m_Specific(A), m_Specific(B)))) + return BinaryOperator::CreateOr(A, B); + } + // (sub (and A, B) (or A, B)) --> neg (xor A, B) { Value *A, *B; @@ -2042,6 +2067,20 @@ Instruction *InstCombiner::visitSub(BinaryOperator &I) { return SelectInst::Create(Cmp, Neg, A); } + // If we are subtracting a low-bit masked subset of some value from an add + // of that same value with no low bits changed, that is clearing some low bits + // of the sum: + // sub (X + AddC), (X & AndC) --> and (X + AddC), ~AndC + const APInt *AddC, *AndC; + if (match(Op0, m_Add(m_Value(X), m_APInt(AddC))) && + match(Op1, m_And(m_Specific(X), m_APInt(AndC)))) { + unsigned BitWidth = Ty->getScalarSizeInBits(); + unsigned Cttz = AddC->countTrailingZeros(); + APInt HighMask(APInt::getHighBitsSet(BitWidth, BitWidth - Cttz)); + if ((HighMask & *AndC).isNullValue()) + return BinaryOperator::CreateAnd(Op0, ConstantInt::get(Ty, ~(*AndC))); + } + if (Instruction *V = canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract(I)) return V; @@ -2094,11 +2133,11 @@ static Instruction *hoistFNegAboveFMulFDiv(Instruction &I, return nullptr; } -Instruction *InstCombiner::visitFNeg(UnaryOperator &I) { +Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) { Value *Op = I.getOperand(0); if (Value *V = SimplifyFNegInst(Op, I.getFastMathFlags(), - SQ.getWithInstruction(&I))) + getSimplifyQuery().getWithInstruction(&I))) return replaceInstUsesWith(I, V); if (Instruction *X = foldFNegIntoConstant(I)) @@ -2117,10 +2156,10 @@ Instruction *InstCombiner::visitFNeg(UnaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitFSub(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitFSub(BinaryOperator &I) { if (Value *V = SimplifyFSubInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), - SQ.getWithInstruction(&I))) + getSimplifyQuery().getWithInstruction(&I))) return replaceInstUsesWith(I, V); if (Instruction *X = foldVectorBinop(I)) @@ -2175,7 +2214,7 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) { // X - C --> X + (-C) // But don't transform constant expressions because there's an inverse fold // for X + (-Y) --> X - Y. - if (match(Op1, m_Constant(C)) && !isa(Op1)) + if (match(Op1, m_ImmConstant(C))) return BinaryOperator::CreateFAddFMF(Op0, ConstantExpr::getFNeg(C), &I); // X - (-Y) --> X + Y @@ -2244,9 +2283,8 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) { } auto m_FaddRdx = [](Value *&Sum, Value *&Vec) { - return m_OneUse( - m_Intrinsic( - m_Value(Sum), m_Value(Vec))); + return m_OneUse(m_Intrinsic(m_Value(Sum), + m_Value(Vec))); }; Value *A0, *A1, *V0, *V1; if (match(Op0, m_FaddRdx(A0, V0)) && match(Op1, m_FaddRdx(A1, V1)) && @@ -2254,9 +2292,8 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) { // Difference of sums is sum of differences: // add_rdx(A0, V0) - add_rdx(A1, V1) --> add_rdx(A0, V0 - V1) - A1 Value *Sub = Builder.CreateFSubFMF(V0, V1, &I); - Value *Rdx = Builder.CreateIntrinsic( - Intrinsic::experimental_vector_reduce_v2_fadd, - {A0->getType(), Sub->getType()}, {A0, Sub}, &I); + Value *Rdx = Builder.CreateIntrinsic(Intrinsic::vector_reduce_fadd, + {Sub->getType()}, {A0, Sub}, &I); return BinaryOperator::CreateFSubFMF(Rdx, A1, &I); } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index d3c718a919c0..68c4156af2c4 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -13,10 +13,12 @@ #include "InstCombineInternal.h" #include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/Analysis/InstructionSimplify.h" -#include "llvm/Transforms/Utils/Local.h" #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" +#include "llvm/Transforms/Utils/Local.h" + using namespace llvm; using namespace PatternMatch; @@ -112,57 +114,12 @@ static Value *SimplifyBSwap(BinaryOperator &I, return Builder.CreateCall(F, BinOp); } -/// This handles expressions of the form ((val OP C1) & C2). Where -/// the Op parameter is 'OP', OpRHS is 'C1', and AndRHS is 'C2'. -Instruction *InstCombiner::OptAndOp(BinaryOperator *Op, - ConstantInt *OpRHS, - ConstantInt *AndRHS, - BinaryOperator &TheAnd) { - Value *X = Op->getOperand(0); - - switch (Op->getOpcode()) { - default: break; - case Instruction::Add: - if (Op->hasOneUse()) { - // Adding a one to a single bit bit-field should be turned into an XOR - // of the bit. First thing to check is to see if this AND is with a - // single bit constant. - const APInt &AndRHSV = AndRHS->getValue(); - - // If there is only one bit set. - if (AndRHSV.isPowerOf2()) { - // Ok, at this point, we know that we are masking the result of the - // ADD down to exactly one bit. If the constant we are adding has - // no bits set below this bit, then we can eliminate the ADD. - const APInt& AddRHS = OpRHS->getValue(); - - // Check to see if any bits below the one bit set in AndRHSV are set. - if ((AddRHS & (AndRHSV - 1)).isNullValue()) { - // If not, the only thing that can effect the output of the AND is - // the bit specified by AndRHSV. If that bit is set, the effect of - // the XOR is to toggle the bit. If it is clear, then the ADD has - // no effect. - if ((AddRHS & AndRHSV).isNullValue()) { // Bit is not set, noop - return replaceOperand(TheAnd, 0, X); - } else { - // Pull the XOR out of the AND. - Value *NewAnd = Builder.CreateAnd(X, AndRHS); - NewAnd->takeName(Op); - return BinaryOperator::CreateXor(NewAnd, AndRHS); - } - } - } - } - break; - } - return nullptr; -} - /// Emit a computation of: (V >= Lo && V < Hi) if Inside is true, otherwise /// (V < Lo || V >= Hi). This method expects that Lo < Hi. IsSigned indicates /// whether to treat V, Lo, and Hi as signed or not. -Value *InstCombiner::insertRangeTest(Value *V, const APInt &Lo, const APInt &Hi, - bool isSigned, bool Inside) { +Value *InstCombinerImpl::insertRangeTest(Value *V, const APInt &Lo, + const APInt &Hi, bool isSigned, + bool Inside) { assert((isSigned ? Lo.slt(Hi) : Lo.ult(Hi)) && "Lo is not < Hi in range emission code!"); @@ -437,11 +394,10 @@ getMaskedTypeForICmpPair(Value *&A, Value *&B, Value *&C, /// (icmp(A & X) ==/!= Y), where the left-hand side is of type Mask_NotAllZeros /// and the right hand side is of type BMask_Mixed. For example, /// (icmp (A & 12) != 0) & (icmp (A & 15) == 8) -> (icmp (A & 15) == 8). -static Value * foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed( - ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, - Value *A, Value *B, Value *C, Value *D, Value *E, - ICmpInst::Predicate PredL, ICmpInst::Predicate PredR, - llvm::InstCombiner::BuilderTy &Builder) { +static Value *foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed( + ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, Value *A, Value *B, Value *C, + Value *D, Value *E, ICmpInst::Predicate PredL, ICmpInst::Predicate PredR, + InstCombiner::BuilderTy &Builder) { // We are given the canonical form: // (icmp ne (A & B), 0) & (icmp eq (A & D), E). // where D & E == E. @@ -452,17 +408,9 @@ static Value * foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed( // // We currently handle the case of B, C, D, E are constant. // - ConstantInt *BCst = dyn_cast(B); - if (!BCst) - return nullptr; - ConstantInt *CCst = dyn_cast(C); - if (!CCst) - return nullptr; - ConstantInt *DCst = dyn_cast(D); - if (!DCst) - return nullptr; - ConstantInt *ECst = dyn_cast(E); - if (!ECst) + ConstantInt *BCst, *CCst, *DCst, *ECst; + if (!match(B, m_ConstantInt(BCst)) || !match(C, m_ConstantInt(CCst)) || + !match(D, m_ConstantInt(DCst)) || !match(E, m_ConstantInt(ECst))) return nullptr; ICmpInst::Predicate NewCC = IsAnd ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE; @@ -568,11 +516,9 @@ static Value * foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed( /// (icmp(A & X) ==/!= Y), where the left-hand side and the right hand side /// aren't of the common mask pattern type. static Value *foldLogOpOfMaskedICmpsAsymmetric( - ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, - Value *A, Value *B, Value *C, Value *D, Value *E, - ICmpInst::Predicate PredL, ICmpInst::Predicate PredR, - unsigned LHSMask, unsigned RHSMask, - llvm::InstCombiner::BuilderTy &Builder) { + ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, Value *A, Value *B, Value *C, + Value *D, Value *E, ICmpInst::Predicate PredL, ICmpInst::Predicate PredR, + unsigned LHSMask, unsigned RHSMask, InstCombiner::BuilderTy &Builder) { assert(ICmpInst::isEquality(PredL) && ICmpInst::isEquality(PredR) && "Expected equality predicates for masked type of icmps."); // Handle Mask_NotAllZeros-BMask_Mixed cases. @@ -603,7 +549,7 @@ static Value *foldLogOpOfMaskedICmpsAsymmetric( /// Try to fold (icmp(A & B) ==/!= C) &/| (icmp(A & D) ==/!= E) /// into a single (icmp(A & X) ==/!= Y). static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, - llvm::InstCombiner::BuilderTy &Builder) { + InstCombiner::BuilderTy &Builder) { Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr, *E = nullptr; ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); Optional> MaskPair = @@ -673,11 +619,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, // Remaining cases assume at least that B and D are constant, and depend on // their actual values. This isn't strictly necessary, just a "handle the // easy cases for now" decision. - ConstantInt *BCst = dyn_cast(B); - if (!BCst) - return nullptr; - ConstantInt *DCst = dyn_cast(D); - if (!DCst) + ConstantInt *BCst, *DCst; + if (!match(B, m_ConstantInt(BCst)) || !match(D, m_ConstantInt(DCst))) return nullptr; if (Mask & (Mask_NotAllZeros | BMask_NotAllOnes)) { @@ -718,11 +661,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, // We can't simply use C and E because we might actually handle // (icmp ne (A & B), B) & (icmp eq (A & D), D) // with B and D, having a single bit set. - ConstantInt *CCst = dyn_cast(C); - if (!CCst) - return nullptr; - ConstantInt *ECst = dyn_cast(E); - if (!ECst) + ConstantInt *CCst, *ECst; + if (!match(C, m_ConstantInt(CCst)) || !match(E, m_ConstantInt(ECst))) return nullptr; if (PredL != NewCC) CCst = cast(ConstantExpr::getXor(BCst, CCst)); @@ -748,8 +688,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, /// Example: (icmp sge x, 0) & (icmp slt x, n) --> icmp ult x, n /// If \p Inverted is true then the check is for the inverted range, e.g. /// (icmp slt x, 0) | (icmp sgt x, n) --> icmp ugt x, n -Value *InstCombiner::simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, - bool Inverted) { +Value *InstCombinerImpl::simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, + bool Inverted) { // Check the lower range comparison, e.g. x >= 0 // InstCombine already ensured that if there is a constant it's on the RHS. ConstantInt *RangeStart = dyn_cast(Cmp0->getOperand(1)); @@ -856,8 +796,9 @@ foldAndOrOfEqualityCmpsWithConstants(ICmpInst *LHS, ICmpInst *RHS, // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2) -Value *InstCombiner::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, ICmpInst *RHS, - BinaryOperator &Logic) { +Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, + ICmpInst *RHS, + BinaryOperator &Logic) { bool JoinedByAnd = Logic.getOpcode() == Instruction::And; assert((JoinedByAnd || Logic.getOpcode() == Instruction::Or) && "Wrong opcode"); @@ -869,10 +810,8 @@ Value *InstCombiner::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, ICmpInst *RHS, if (!JoinedByAnd && Pred != ICmpInst::ICMP_EQ) return nullptr; - // TODO support vector splats - ConstantInt *LHSC = dyn_cast(LHS->getOperand(1)); - ConstantInt *RHSC = dyn_cast(RHS->getOperand(1)); - if (!LHSC || !RHSC || !LHSC->isZero() || !RHSC->isZero()) + if (!match(LHS->getOperand(1), m_Zero()) || + !match(RHS->getOperand(1), m_Zero())) return nullptr; Value *A, *B, *C, *D; @@ -1148,11 +1087,12 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1, assert((IsAnd || Logic.getOpcode() == Instruction::Or) && "Wrong logic op"); // Match an equality compare with a non-poison constant as Cmp0. + // Also, give up if the compare can be constant-folded to avoid looping. ICmpInst::Predicate Pred0; Value *X; Constant *C; if (!match(Cmp0, m_ICmp(Pred0, m_Value(X), m_Constant(C))) || - !isGuaranteedNotToBeUndefOrPoison(C)) + !isGuaranteedNotToBeUndefOrPoison(C) || isa(X)) return nullptr; if ((IsAnd && Pred0 != ICmpInst::ICMP_EQ) || (!IsAnd && Pred0 != ICmpInst::ICMP_NE)) @@ -1183,8 +1123,8 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1, } /// Fold (icmp)&(icmp) if possible. -Value *InstCombiner::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, - BinaryOperator &And) { +Value *InstCombinerImpl::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, + BinaryOperator &And) { const SimplifyQuery Q = SQ.getWithInstruction(&And); // Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2) @@ -1243,9 +1183,10 @@ Value *InstCombiner::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, // This only handles icmp of constants: (icmp1 A, C1) & (icmp2 B, C2). Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0); - ConstantInt *LHSC = dyn_cast(LHS->getOperand(1)); - ConstantInt *RHSC = dyn_cast(RHS->getOperand(1)); - if (!LHSC || !RHSC) + + ConstantInt *LHSC, *RHSC; + if (!match(LHS->getOperand(1), m_ConstantInt(LHSC)) || + !match(RHS->getOperand(1), m_ConstantInt(RHSC))) return nullptr; if (LHSC == RHSC && PredL == PredR) { @@ -1403,7 +1344,8 @@ Value *InstCombiner::foldAndOfICmps(ICmpInst *LHS, ICmpInst *RHS, return nullptr; } -Value *InstCombiner::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS, bool IsAnd) { +Value *InstCombinerImpl::foldLogicOfFCmps(FCmpInst *LHS, FCmpInst *RHS, + bool IsAnd) { Value *LHS0 = LHS->getOperand(0), *LHS1 = LHS->getOperand(1); Value *RHS0 = RHS->getOperand(0), *RHS1 = RHS->getOperand(1); FCmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); @@ -1513,8 +1455,8 @@ static Instruction *matchDeMorgansLaws(BinaryOperator &I, Value *A, *B; if (match(I.getOperand(0), m_OneUse(m_Not(m_Value(A)))) && match(I.getOperand(1), m_OneUse(m_Not(m_Value(B)))) && - !isFreeToInvert(A, A->hasOneUse()) && - !isFreeToInvert(B, B->hasOneUse())) { + !InstCombiner::isFreeToInvert(A, A->hasOneUse()) && + !InstCombiner::isFreeToInvert(B, B->hasOneUse())) { Value *AndOr = Builder.CreateBinOp(Opcode, A, B, I.getName() + ".demorgan"); return BinaryOperator::CreateNot(AndOr); } @@ -1522,7 +1464,7 @@ static Instruction *matchDeMorgansLaws(BinaryOperator &I, return nullptr; } -bool InstCombiner::shouldOptimizeCast(CastInst *CI) { +bool InstCombinerImpl::shouldOptimizeCast(CastInst *CI) { Value *CastSrc = CI->getOperand(0); // Noop casts and casts of constants should be eliminated trivially. @@ -1578,7 +1520,7 @@ static Instruction *foldLogicCastConstant(BinaryOperator &Logic, CastInst *Cast, } /// Fold {and,or,xor} (cast X), Y. -Instruction *InstCombiner::foldCastedBitwiseLogic(BinaryOperator &I) { +Instruction *InstCombinerImpl::foldCastedBitwiseLogic(BinaryOperator &I) { auto LogicOpc = I.getOpcode(); assert(I.isBitwiseLogicOp() && "Unexpected opcode for bitwise logic folding"); @@ -1685,6 +1627,14 @@ static Instruction *foldOrToXor(BinaryOperator &I, match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) return BinaryOperator::CreateNot(Builder.CreateXor(A, B)); + // Operand complexity canonicalization guarantees that the 'xor' is Op0. + // (A ^ B) | ~(A | B) --> ~(A & B) + // (A ^ B) | ~(B | A) --> ~(A & B) + if (Op0->hasOneUse() || Op1->hasOneUse()) + if (match(Op0, m_Xor(m_Value(A), m_Value(B))) && + match(Op1, m_Not(m_c_Or(m_Specific(A), m_Specific(B))))) + return BinaryOperator::CreateNot(Builder.CreateAnd(A, B)); + // (A & ~B) | (~A & B) --> A ^ B // (A & ~B) | (B & ~A) --> A ^ B // (~B & A) | (~A & B) --> A ^ B @@ -1699,32 +1649,13 @@ static Instruction *foldOrToXor(BinaryOperator &I, /// Return true if a constant shift amount is always less than the specified /// bit-width. If not, the shift could create poison in the narrower type. static bool canNarrowShiftAmt(Constant *C, unsigned BitWidth) { - if (auto *ScalarC = dyn_cast(C)) - return ScalarC->getZExtValue() < BitWidth; - - if (C->getType()->isVectorTy()) { - // Check each element of a constant vector. - unsigned NumElts = cast(C->getType())->getNumElements(); - for (unsigned i = 0; i != NumElts; ++i) { - Constant *Elt = C->getAggregateElement(i); - if (!Elt) - return false; - if (isa(Elt)) - continue; - auto *CI = dyn_cast(Elt); - if (!CI || CI->getZExtValue() >= BitWidth) - return false; - } - return true; - } - - // The constant is a constant expression or unknown. - return false; + APInt Threshold(C->getType()->getScalarSizeInBits(), BitWidth); + return match(C, m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, Threshold)); } /// Try to use narrower ops (sink zext ops) for an 'and' with binop operand and /// a common zext operand: and (binop (zext X), C), (zext X). -Instruction *InstCombiner::narrowMaskedBinOp(BinaryOperator &And) { +Instruction *InstCombinerImpl::narrowMaskedBinOp(BinaryOperator &And) { // This transform could also apply to {or, and, xor}, but there are better // folds for those cases, so we don't expect those patterns here. AShr is not // handled because it should always be transformed to LShr in this sequence. @@ -1766,7 +1697,9 @@ Instruction *InstCombiner::narrowMaskedBinOp(BinaryOperator &And) { // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. -Instruction *InstCombiner::visitAnd(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { + Type *Ty = I.getType(); + if (Value *V = SimplifyAndInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1794,21 +1727,22 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { return replaceInstUsesWith(I, V); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + + Value *X, *Y; + if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) && + match(Op1, m_One())) { + // (1 << X) & 1 --> zext(X == 0) + // (1 >> X) & 1 --> zext(X == 0) + Value *IsZero = Builder.CreateICmpEQ(X, ConstantInt::get(Ty, 0)); + return new ZExtInst(IsZero, Ty); + } + const APInt *C; if (match(Op1, m_APInt(C))) { - Value *X, *Y; - if (match(Op0, m_OneUse(m_LogicalShift(m_One(), m_Value(X)))) && - C->isOneValue()) { - // (1 << X) & 1 --> zext(X == 0) - // (1 >> X) & 1 --> zext(X == 0) - Value *IsZero = Builder.CreateICmpEQ(X, ConstantInt::get(I.getType(), 0)); - return new ZExtInst(IsZero, I.getType()); - } - const APInt *XorC; if (match(Op0, m_OneUse(m_Xor(m_Value(X), m_APInt(XorC))))) { // (X ^ C1) & C2 --> (X & C2) ^ (C1&C2) - Constant *NewC = ConstantInt::get(I.getType(), *C & *XorC); + Constant *NewC = ConstantInt::get(Ty, *C & *XorC); Value *And = Builder.CreateAnd(X, Op1); And->takeName(Op0); return BinaryOperator::CreateXor(And, NewC); @@ -1823,11 +1757,9 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { // that aren't set in C2. Meaning we can replace (C1&C2) with C1 in // above, but this feels safer. APInt Together = *C & *OrC; - Value *And = Builder.CreateAnd(X, ConstantInt::get(I.getType(), - Together ^ *C)); + Value *And = Builder.CreateAnd(X, ConstantInt::get(Ty, Together ^ *C)); And->takeName(Op0); - return BinaryOperator::CreateOr(And, ConstantInt::get(I.getType(), - Together)); + return BinaryOperator::CreateOr(And, ConstantInt::get(Ty, Together)); } // If the mask is only needed on one incoming arm, push the 'and' op up. @@ -1848,27 +1780,49 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { return BinaryOperator::Create(BinOp, NewLHS, Y); } } + + unsigned Width = Ty->getScalarSizeInBits(); const APInt *ShiftC; if (match(Op0, m_OneUse(m_SExt(m_AShr(m_Value(X), m_APInt(ShiftC)))))) { - unsigned Width = I.getType()->getScalarSizeInBits(); if (*C == APInt::getLowBitsSet(Width, Width - ShiftC->getZExtValue())) { // We are clearing high bits that were potentially set by sext+ashr: // and (sext (ashr X, ShiftC)), C --> lshr (sext X), ShiftC - Value *Sext = Builder.CreateSExt(X, I.getType()); - Constant *ShAmtC = ConstantInt::get(I.getType(), ShiftC->zext(Width)); + Value *Sext = Builder.CreateSExt(X, Ty); + Constant *ShAmtC = ConstantInt::get(Ty, ShiftC->zext(Width)); return BinaryOperator::CreateLShr(Sext, ShAmtC); } } + + const APInt *AddC; + if (match(Op0, m_Add(m_Value(X), m_APInt(AddC)))) { + // If we add zeros to every bit below a mask, the add has no effect: + // (X + AddC) & LowMaskC --> X & LowMaskC + unsigned Ctlz = C->countLeadingZeros(); + APInt LowMask(APInt::getLowBitsSet(Width, Width - Ctlz)); + if ((*AddC & LowMask).isNullValue()) + return BinaryOperator::CreateAnd(X, Op1); + + // If we are masking the result of the add down to exactly one bit and + // the constant we are adding has no bits set below that bit, then the + // add is flipping a single bit. Example: + // (X + 4) & 4 --> (X & 4) ^ 4 + if (Op0->hasOneUse() && C->isPowerOf2() && (*AddC & (*C - 1)) == 0) { + assert((*C & *AddC) != 0 && "Expected common bit"); + Value *NewAnd = Builder.CreateAnd(X, Op1); + return BinaryOperator::CreateXor(NewAnd, Op1); + } + } } - if (ConstantInt *AndRHS = dyn_cast(Op1)) { + ConstantInt *AndRHS; + if (match(Op1, m_ConstantInt(AndRHS))) { const APInt &AndRHSMask = AndRHS->getValue(); // Optimize a variety of ((val OP C1) & C2) combinations... if (BinaryOperator *Op0I = dyn_cast(Op0)) { // ((C1 OP zext(X)) & C2) -> zext((C1-X) & C2) if C2 fits in the bitwidth // of X and OP behaves well when given trunc(C1) and X. - // TODO: Do this for vectors by using m_APInt isntead of m_ConstantInt. + // TODO: Do this for vectors by using m_APInt instead of m_ConstantInt. switch (Op0I->getOpcode()) { default: break; @@ -1893,31 +1847,30 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { BinOp = Builder.CreateBinOp(Op0I->getOpcode(), TruncC1, X); auto *TruncC2 = ConstantExpr::getTrunc(AndRHS, X->getType()); auto *And = Builder.CreateAnd(BinOp, TruncC2); - return new ZExtInst(And, I.getType()); + return new ZExtInst(And, Ty); } } } - - if (ConstantInt *Op0CI = dyn_cast(Op0I->getOperand(1))) - if (Instruction *Res = OptAndOp(Op0I, Op0CI, AndRHS, I)) - return Res; } + } - // If this is an integer truncation, and if the source is an 'and' with - // immediate, transform it. This frequently occurs for bitfield accesses. - { - Value *X = nullptr; ConstantInt *YC = nullptr; - if (match(Op0, m_Trunc(m_And(m_Value(X), m_ConstantInt(YC))))) { - // Change: and (trunc (and X, YC) to T), C2 - // into : and (trunc X to T), trunc(YC) & C2 - // This will fold the two constants together, which may allow - // other simplifications. - Value *NewCast = Builder.CreateTrunc(X, I.getType(), "and.shrunk"); - Constant *C3 = ConstantExpr::getTrunc(YC, I.getType()); - C3 = ConstantExpr::getAnd(C3, AndRHS); - return BinaryOperator::CreateAnd(NewCast, C3); - } - } + if (match(&I, m_And(m_OneUse(m_Shl(m_ZExt(m_Value(X)), m_Value(Y))), + m_SignMask())) && + match(Y, m_SpecificInt_ICMP( + ICmpInst::Predicate::ICMP_EQ, + APInt(Ty->getScalarSizeInBits(), + Ty->getScalarSizeInBits() - + X->getType()->getScalarSizeInBits())))) { + auto *SExt = Builder.CreateSExt(X, Ty, X->getName() + ".signext"); + auto *SanitizedSignMask = cast(Op1); + // We must be careful with the undef elements of the sign bit mask, however: + // the mask elt can be undef iff the shift amount for that lane was undef, + // otherwise we need to sanitize undef masks to zero. + SanitizedSignMask = Constant::replaceUndefsWith( + SanitizedSignMask, ConstantInt::getNullValue(Ty->getScalarType())); + SanitizedSignMask = + Constant::mergeUndefsWith(SanitizedSignMask, cast(Y)); + return BinaryOperator::CreateAnd(SExt, SanitizedSignMask); } if (Instruction *Z = narrowMaskedBinOp(I)) @@ -1938,6 +1891,13 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { if (match(Op0, m_OneUse(m_c_Xor(m_Specific(Op1), m_Value(B))))) return BinaryOperator::CreateAnd(Op1, Builder.CreateNot(B)); + // A & ~(A ^ B) --> A & B + if (match(Op1, m_Not(m_c_Xor(m_Specific(Op0), m_Value(B))))) + return BinaryOperator::CreateAnd(Op0, B); + // ~(A ^ B) & A --> A & B + if (match(Op0, m_Not(m_c_Xor(m_Specific(Op1), m_Value(B))))) + return BinaryOperator::CreateAnd(Op1, B); + // (A ^ B) & ((B ^ C) ^ A) -> (A ^ B) & ~C if (match(Op0, m_Xor(m_Value(A), m_Value(B)))) if (match(Op1, m_Xor(m_Xor(m_Specific(B), m_Value(C)), m_Specific(A)))) @@ -1976,7 +1936,6 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { // TODO: Make this recursive; it's a little tricky because an arbitrary // number of 'and' instructions might have to be created. - Value *X, *Y; if (LHS && match(Op1, m_OneUse(m_And(m_Value(X), m_Value(Y))))) { if (auto *Cmp = dyn_cast(X)) if (Value *Res = foldAndOfICmps(LHS, Cmp, I)) @@ -2010,29 +1969,30 @@ Instruction *InstCombiner::visitAnd(BinaryOperator &I) { Value *A; if (match(Op0, m_OneUse(m_SExt(m_Value(A)))) && A->getType()->isIntOrIntVectorTy(1)) - return SelectInst::Create(A, Op1, Constant::getNullValue(I.getType())); + return SelectInst::Create(A, Op1, Constant::getNullValue(Ty)); if (match(Op1, m_OneUse(m_SExt(m_Value(A)))) && A->getType()->isIntOrIntVectorTy(1)) - return SelectInst::Create(A, Op0, Constant::getNullValue(I.getType())); + return SelectInst::Create(A, Op0, Constant::getNullValue(Ty)); // and(ashr(subNSW(Y, X), ScalarSizeInBits(Y)-1), X) --> X s> Y ? X : 0. - { - Value *X, *Y; - const APInt *ShAmt; - Type *Ty = I.getType(); - if (match(&I, m_c_And(m_OneUse(m_AShr(m_NSWSub(m_Value(Y), m_Value(X)), - m_APInt(ShAmt))), - m_Deferred(X))) && - *ShAmt == Ty->getScalarSizeInBits() - 1) { - Value *NewICmpInst = Builder.CreateICmpSGT(X, Y); - return SelectInst::Create(NewICmpInst, X, ConstantInt::getNullValue(Ty)); - } + if (match(&I, m_c_And(m_OneUse(m_AShr( + m_NSWSub(m_Value(Y), m_Value(X)), + m_SpecificInt(Ty->getScalarSizeInBits() - 1))), + m_Deferred(X)))) { + Value *NewICmpInst = Builder.CreateICmpSGT(X, Y); + return SelectInst::Create(NewICmpInst, X, ConstantInt::getNullValue(Ty)); } + // (~x) & y --> ~(x | (~y)) iff that gets rid of inversions + if (sinkNotIntoOtherHandOfAndOrOr(I)) + return &I; + return nullptr; } -Instruction *InstCombiner::matchBSwap(BinaryOperator &Or) { +Instruction *InstCombinerImpl::matchBSwapOrBitReverse(BinaryOperator &Or, + bool MatchBSwaps, + bool MatchBitReversals) { assert(Or.getOpcode() == Instruction::Or && "bswap requires an 'or'"); Value *Op0 = Or.getOperand(0), *Op1 = Or.getOperand(1); @@ -2044,33 +2004,32 @@ Instruction *InstCombiner::matchBSwap(BinaryOperator &Or) { Op1 = Ext->getOperand(0); // (A | B) | C and A | (B | C) -> bswap if possible. - bool OrOfOrs = match(Op0, m_Or(m_Value(), m_Value())) || - match(Op1, m_Or(m_Value(), m_Value())); + bool OrWithOrs = match(Op0, m_Or(m_Value(), m_Value())) || + match(Op1, m_Or(m_Value(), m_Value())); - // (A >> B) | (C << D) and (A << B) | (B >> C) -> bswap if possible. - bool OrOfShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) && - match(Op1, m_LogicalShift(m_Value(), m_Value())); + // (A >> B) | C and (A << B) | C -> bswap if possible. + bool OrWithShifts = match(Op0, m_LogicalShift(m_Value(), m_Value())) || + match(Op1, m_LogicalShift(m_Value(), m_Value())); - // (A & B) | (C & D) -> bswap if possible. - bool OrOfAnds = match(Op0, m_And(m_Value(), m_Value())) && - match(Op1, m_And(m_Value(), m_Value())); + // (A & B) | C and A | (B & C) -> bswap if possible. + bool OrWithAnds = match(Op0, m_And(m_Value(), m_Value())) || + match(Op1, m_And(m_Value(), m_Value())); - // (A << B) | (C & D) -> bswap if possible. - // The bigger pattern here is ((A & C1) << C2) | ((B >> C2) & C1), which is a - // part of the bswap idiom for specific values of C1, C2 (e.g. C1 = 16711935, - // C2 = 8 for i32). - // This pattern can occur when the operands of the 'or' are not canonicalized - // for some reason (not having only one use, for example). - bool OrOfAndAndSh = (match(Op0, m_LogicalShift(m_Value(), m_Value())) && - match(Op1, m_And(m_Value(), m_Value()))) || - (match(Op0, m_And(m_Value(), m_Value())) && - match(Op1, m_LogicalShift(m_Value(), m_Value()))); + // fshl(A,B,C) | D and A | fshl(B,C,D) -> bswap if possible. + // fshr(A,B,C) | D and A | fshr(B,C,D) -> bswap if possible. + bool OrWithFunnels = match(Op0, m_FShl(m_Value(), m_Value(), m_Value())) || + match(Op0, m_FShr(m_Value(), m_Value(), m_Value())) || + match(Op0, m_FShl(m_Value(), m_Value(), m_Value())) || + match(Op0, m_FShr(m_Value(), m_Value(), m_Value())); - if (!OrOfOrs && !OrOfShifts && !OrOfAnds && !OrOfAndAndSh) + // TODO: Do we need all these filtering checks or should we just rely on + // recognizeBSwapOrBitReverseIdiom + collectBitParts to reject them quickly? + if (!OrWithOrs && !OrWithShifts && !OrWithAnds && !OrWithFunnels) return nullptr; - SmallVector Insts; - if (!recognizeBSwapOrBitReverseIdiom(&Or, true, false, Insts)) + SmallVector Insts; + if (!recognizeBSwapOrBitReverseIdiom(&Or, MatchBSwaps, MatchBitReversals, + Insts)) return nullptr; Instruction *LastInst = Insts.pop_back_val(); LastInst->removeFromParent(); @@ -2080,34 +2039,72 @@ Instruction *InstCombiner::matchBSwap(BinaryOperator &Or) { return LastInst; } -/// Transform UB-safe variants of bitwise rotate to the funnel shift intrinsic. -static Instruction *matchRotate(Instruction &Or) { +/// Match UB-safe variants of the funnel shift intrinsic. +static Instruction *matchFunnelShift(Instruction &Or, InstCombinerImpl &IC) { // TODO: Can we reduce the code duplication between this and the related // rotate matching code under visitSelect and visitTrunc? unsigned Width = Or.getType()->getScalarSizeInBits(); - if (!isPowerOf2_32(Width)) - return nullptr; - // First, find an or'd pair of opposite shifts with the same shifted operand: - // or (lshr ShVal, ShAmt0), (shl ShVal, ShAmt1) + // First, find an or'd pair of opposite shifts: + // or (lshr ShVal0, ShAmt0), (shl ShVal1, ShAmt1) BinaryOperator *Or0, *Or1; if (!match(Or.getOperand(0), m_BinOp(Or0)) || !match(Or.getOperand(1), m_BinOp(Or1))) return nullptr; - Value *ShVal, *ShAmt0, *ShAmt1; - if (!match(Or0, m_OneUse(m_LogicalShift(m_Value(ShVal), m_Value(ShAmt0)))) || - !match(Or1, m_OneUse(m_LogicalShift(m_Specific(ShVal), m_Value(ShAmt1))))) - return nullptr; + Value *ShVal0, *ShVal1, *ShAmt0, *ShAmt1; + if (!match(Or0, m_OneUse(m_LogicalShift(m_Value(ShVal0), m_Value(ShAmt0)))) || + !match(Or1, m_OneUse(m_LogicalShift(m_Value(ShVal1), m_Value(ShAmt1)))) || + Or0->getOpcode() == Or1->getOpcode()) + return nullptr; + + // Canonicalize to or(shl(ShVal0, ShAmt0), lshr(ShVal1, ShAmt1)). + if (Or0->getOpcode() == BinaryOperator::LShr) { + std::swap(Or0, Or1); + std::swap(ShVal0, ShVal1); + std::swap(ShAmt0, ShAmt1); + } + assert(Or0->getOpcode() == BinaryOperator::Shl && + Or1->getOpcode() == BinaryOperator::LShr && + "Illegal or(shift,shift) pair"); + + // Match the shift amount operands for a funnel shift pattern. This always + // matches a subtraction on the R operand. + auto matchShiftAmount = [&](Value *L, Value *R, unsigned Width) -> Value * { + // Check for constant shift amounts that sum to the bitwidth. + const APInt *LI, *RI; + if (match(L, m_APIntAllowUndef(LI)) && match(R, m_APIntAllowUndef(RI))) + if (LI->ult(Width) && RI->ult(Width) && (*LI + *RI) == Width) + return ConstantInt::get(L->getType(), *LI); + + Constant *LC, *RC; + if (match(L, m_Constant(LC)) && match(R, m_Constant(RC)) && + match(L, m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, APInt(Width, Width))) && + match(R, m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, APInt(Width, Width))) && + match(ConstantExpr::getAdd(LC, RC), m_SpecificIntAllowUndef(Width))) + return ConstantExpr::mergeUndefsWith(LC, RC); + + // (shl ShVal, X) | (lshr ShVal, (Width - x)) iff X < Width. + // We limit this to X < Width in case the backend re-expands the intrinsic, + // and has to reintroduce a shift modulo operation (InstCombine might remove + // it after this fold). This still doesn't guarantee that the final codegen + // will match this original pattern. + if (match(R, m_OneUse(m_Sub(m_SpecificInt(Width), m_Specific(L))))) { + KnownBits KnownL = IC.computeKnownBits(L, /*Depth*/ 0, &Or); + return KnownL.getMaxValue().ult(Width) ? L : nullptr; + } - BinaryOperator::BinaryOps ShiftOpcode0 = Or0->getOpcode(); - BinaryOperator::BinaryOps ShiftOpcode1 = Or1->getOpcode(); - if (ShiftOpcode0 == ShiftOpcode1) - return nullptr; + // For non-constant cases, the following patterns currently only work for + // rotation patterns. + // TODO: Add general funnel-shift compatible patterns. + if (ShVal0 != ShVal1) + return nullptr; + + // For non-constant cases we don't support non-pow2 shift masks. + // TODO: Is it worth matching urem as well? + if (!isPowerOf2_32(Width)) + return nullptr; - // Match the shift amount operands for a rotate pattern. This always matches - // a subtraction on the R operand. - auto matchShiftAmount = [](Value *L, Value *R, unsigned Width) -> Value * { // The shift amount may be masked with negation: // (shl ShVal, (X & (Width - 1))) | (lshr ShVal, ((-X) & (Width - 1))) Value *X; @@ -2123,23 +2120,25 @@ static Instruction *matchRotate(Instruction &Or) { m_SpecificInt(Mask)))) return L; + if (match(L, m_ZExt(m_And(m_Value(X), m_SpecificInt(Mask)))) && + match(R, m_ZExt(m_And(m_Neg(m_Specific(X)), m_SpecificInt(Mask))))) + return L; + return nullptr; }; Value *ShAmt = matchShiftAmount(ShAmt0, ShAmt1, Width); - bool SubIsOnLHS = false; + bool IsFshl = true; // Sub on LSHR. if (!ShAmt) { ShAmt = matchShiftAmount(ShAmt1, ShAmt0, Width); - SubIsOnLHS = true; + IsFshl = false; // Sub on SHL. } if (!ShAmt) return nullptr; - bool IsFshl = (!SubIsOnLHS && ShiftOpcode0 == BinaryOperator::Shl) || - (SubIsOnLHS && ShiftOpcode1 == BinaryOperator::Shl); Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr; Function *F = Intrinsic::getDeclaration(Or.getModule(), IID, Or.getType()); - return IntrinsicInst::Create(F, { ShVal, ShVal, ShAmt }); + return IntrinsicInst::Create(F, {ShVal0, ShVal1, ShAmt}); } /// Attempt to combine or(zext(x),shl(zext(y),bw/2) concat packing patterns. @@ -2197,7 +2196,7 @@ static Instruction *matchOrConcat(Instruction &Or, /// If all elements of two constant vectors are 0/-1 and inverses, return true. static bool areInverseVectorBitmasks(Constant *C1, Constant *C2) { - unsigned NumElts = cast(C1->getType())->getNumElements(); + unsigned NumElts = cast(C1->getType())->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) { Constant *EltC1 = C1->getAggregateElement(i); Constant *EltC2 = C2->getAggregateElement(i); @@ -2215,7 +2214,7 @@ static bool areInverseVectorBitmasks(Constant *C1, Constant *C2) { /// We have an expression of the form (A & C) | (B & D). If A is a scalar or /// vector composed of all-zeros or all-ones values and is the bitwise 'not' of /// B, it can be used as the condition operand of a select instruction. -Value *InstCombiner::getSelectCondition(Value *A, Value *B) { +Value *InstCombinerImpl::getSelectCondition(Value *A, Value *B) { // Step 1: We may have peeked through bitcasts in the caller. // Exit immediately if we don't have (vector) integer types. Type *Ty = A->getType(); @@ -2272,8 +2271,8 @@ Value *InstCombiner::getSelectCondition(Value *A, Value *B) { /// We have an expression of the form (A & C) | (B & D). Try to simplify this /// to "A' ? C : D", where A' is a boolean or vector of booleans. -Value *InstCombiner::matchSelectFromAndOr(Value *A, Value *C, Value *B, - Value *D) { +Value *InstCombinerImpl::matchSelectFromAndOr(Value *A, Value *C, Value *B, + Value *D) { // The potential condition of the select may be bitcasted. In that case, look // through its bitcast and the corresponding bitcast of the 'not' condition. Type *OrigType = A->getType(); @@ -2293,8 +2292,8 @@ Value *InstCombiner::matchSelectFromAndOr(Value *A, Value *C, Value *B, } /// Fold (icmp)|(icmp) if possible. -Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, - BinaryOperator &Or) { +Value *InstCombinerImpl::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, + BinaryOperator &Or) { const SimplifyQuery Q = SQ.getWithInstruction(&Or); // Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2) @@ -2303,9 +2302,10 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, return V; ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate(); - - ConstantInt *LHSC = dyn_cast(LHS->getOperand(1)); - ConstantInt *RHSC = dyn_cast(RHS->getOperand(1)); + Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0); + Value *LHS1 = LHS->getOperand(1), *RHS1 = RHS->getOperand(1); + auto *LHSC = dyn_cast(LHS1); + auto *RHSC = dyn_cast(RHS1); // Fold (icmp ult/ule (A + C1), C3) | (icmp ult/ule (A + C2), C3) // --> (icmp ult/ule ((A & ~(C1 ^ C2)) + max(C1, C2)), C3) @@ -2317,24 +2317,20 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, // 3) C1 ^ C2 is one-bit mask. // 4) LowRange1 ^ LowRange2 and HighRange1 ^ HighRange2 are one-bit mask. // This implies all values in the two ranges differ by exactly one bit. - if ((PredL == ICmpInst::ICMP_ULT || PredL == ICmpInst::ICMP_ULE) && PredL == PredR && LHSC && RHSC && LHS->hasOneUse() && RHS->hasOneUse() && LHSC->getType() == RHSC->getType() && LHSC->getValue() == (RHSC->getValue())) { - Value *LAdd = LHS->getOperand(0); - Value *RAdd = RHS->getOperand(0); - - Value *LAddOpnd, *RAddOpnd; + Value *AddOpnd; ConstantInt *LAddC, *RAddC; - if (match(LAdd, m_Add(m_Value(LAddOpnd), m_ConstantInt(LAddC))) && - match(RAdd, m_Add(m_Value(RAddOpnd), m_ConstantInt(RAddC))) && + if (match(LHS0, m_Add(m_Value(AddOpnd), m_ConstantInt(LAddC))) && + match(RHS0, m_Add(m_Specific(AddOpnd), m_ConstantInt(RAddC))) && LAddC->getValue().ugt(LHSC->getValue()) && RAddC->getValue().ugt(LHSC->getValue())) { APInt DiffC = LAddC->getValue() ^ RAddC->getValue(); - if (LAddOpnd == RAddOpnd && DiffC.isPowerOf2()) { + if (DiffC.isPowerOf2()) { ConstantInt *MaxAddC = nullptr; if (LAddC->getValue().ult(RAddC->getValue())) MaxAddC = RAddC; @@ -2354,7 +2350,7 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, RangeDiff.ugt(LHSC->getValue())) { Value *MaskC = ConstantInt::get(LAddC->getType(), ~DiffC); - Value *NewAnd = Builder.CreateAnd(LAddOpnd, MaskC); + Value *NewAnd = Builder.CreateAnd(AddOpnd, MaskC); Value *NewAdd = Builder.CreateAdd(NewAnd, MaxAddC); return Builder.CreateICmp(LHS->getPredicate(), NewAdd, LHSC); } @@ -2364,15 +2360,12 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, // (icmp1 A, B) | (icmp2 A, B) --> (icmp3 A, B) if (predicatesFoldable(PredL, PredR)) { - if (LHS->getOperand(0) == RHS->getOperand(1) && - LHS->getOperand(1) == RHS->getOperand(0)) + if (LHS0 == RHS1 && LHS1 == RHS0) LHS->swapOperands(); - if (LHS->getOperand(0) == RHS->getOperand(0) && - LHS->getOperand(1) == RHS->getOperand(1)) { - Value *Op0 = LHS->getOperand(0), *Op1 = LHS->getOperand(1); + if (LHS0 == RHS0 && LHS1 == RHS1) { unsigned Code = getICmpCode(LHS) | getICmpCode(RHS); bool IsSigned = LHS->isSigned() || RHS->isSigned(); - return getNewICmpValue(Code, IsSigned, Op0, Op1, Builder); + return getNewICmpValue(Code, IsSigned, LHS0, LHS1, Builder); } } @@ -2381,31 +2374,30 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, false, Builder)) return V; - Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0); if (LHS->hasOneUse() || RHS->hasOneUse()) { // (icmp eq B, 0) | (icmp ult A, B) -> (icmp ule A, B-1) // (icmp eq B, 0) | (icmp ugt B, A) -> (icmp ule A, B-1) Value *A = nullptr, *B = nullptr; - if (PredL == ICmpInst::ICMP_EQ && LHSC && LHSC->isZero()) { + if (PredL == ICmpInst::ICMP_EQ && match(LHS1, m_Zero())) { B = LHS0; - if (PredR == ICmpInst::ICMP_ULT && LHS0 == RHS->getOperand(1)) + if (PredR == ICmpInst::ICMP_ULT && LHS0 == RHS1) A = RHS0; else if (PredR == ICmpInst::ICMP_UGT && LHS0 == RHS0) - A = RHS->getOperand(1); + A = RHS1; } // (icmp ult A, B) | (icmp eq B, 0) -> (icmp ule A, B-1) // (icmp ugt B, A) | (icmp eq B, 0) -> (icmp ule A, B-1) - else if (PredR == ICmpInst::ICMP_EQ && RHSC && RHSC->isZero()) { + else if (PredR == ICmpInst::ICMP_EQ && match(RHS1, m_Zero())) { B = RHS0; - if (PredL == ICmpInst::ICMP_ULT && RHS0 == LHS->getOperand(1)) + if (PredL == ICmpInst::ICMP_ULT && RHS0 == LHS1) A = LHS0; - else if (PredL == ICmpInst::ICMP_UGT && LHS0 == RHS0) - A = LHS->getOperand(1); + else if (PredL == ICmpInst::ICMP_UGT && RHS0 == LHS0) + A = LHS1; } - if (A && B) + if (A && B && B->getType()->isIntOrIntVectorTy()) return Builder.CreateICmp( ICmpInst::ICMP_UGE, - Builder.CreateAdd(B, ConstantInt::getSigned(B->getType(), -1)), A); + Builder.CreateAdd(B, Constant::getAllOnesValue(B->getType())), A); } if (Value *V = foldAndOrOfICmpsWithConstEq(LHS, RHS, Or, Builder, Q)) @@ -2434,18 +2426,21 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, foldUnsignedUnderflowCheck(RHS, LHS, /*IsAnd=*/false, Q, Builder)) return X; + // (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0) + // TODO: Remove this when foldLogOpOfMaskedICmps can handle vectors. + if (PredL == ICmpInst::ICMP_NE && match(LHS1, m_Zero()) && + PredR == ICmpInst::ICMP_NE && match(RHS1, m_Zero()) && + LHS0->getType()->isIntOrIntVectorTy() && + LHS0->getType() == RHS0->getType()) { + Value *NewOr = Builder.CreateOr(LHS0, RHS0); + return Builder.CreateICmp(PredL, NewOr, + Constant::getNullValue(NewOr->getType())); + } + // This only handles icmp of constants: (icmp1 A, C1) | (icmp2 B, C2). if (!LHSC || !RHSC) return nullptr; - if (LHSC == RHSC && PredL == PredR) { - // (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0) - if (PredL == ICmpInst::ICMP_NE && LHSC->isZero()) { - Value *NewOr = Builder.CreateOr(LHS0, RHS0); - return Builder.CreateICmp(PredL, NewOr, LHSC); - } - } - // (icmp ult (X + CA), C1) | (icmp eq X, C2) -> (icmp ule (X + CA), C1) // iff C2 + CA == C1. if (PredL == ICmpInst::ICMP_ULT && PredR == ICmpInst::ICMP_EQ) { @@ -2559,7 +2554,7 @@ Value *InstCombiner::foldOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. -Instruction *InstCombiner::visitOr(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) { if (Value *V = SimplifyOrInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -2589,11 +2584,12 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { if (Instruction *FoldedLogic = foldBinOpIntoSelectOrPhi(I)) return FoldedLogic; - if (Instruction *BSwap = matchBSwap(I)) + if (Instruction *BSwap = matchBSwapOrBitReverse(I, /*MatchBSwaps*/ true, + /*MatchBitReversals*/ false)) return BSwap; - if (Instruction *Rotate = matchRotate(I)) - return Rotate; + if (Instruction *Funnel = matchFunnelShift(I, *this)) + return Funnel; if (Instruction *Concat = matchOrConcat(I, Builder)) return replaceInstUsesWith(I, Concat); @@ -2613,9 +2609,9 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { Value *A, *B, *C, *D; if (match(Op0, m_And(m_Value(A), m_Value(C))) && match(Op1, m_And(m_Value(B), m_Value(D)))) { - ConstantInt *C1 = dyn_cast(C); - ConstantInt *C2 = dyn_cast(D); - if (C1 && C2) { // (A & C1)|(B & C2) + // (A & C1)|(B & C2) + ConstantInt *C1, *C2; + if (match(C, m_ConstantInt(C1)) && match(D, m_ConstantInt(C2))) { Value *V1 = nullptr, *V2 = nullptr; if ((C1->getValue() & C2->getValue()).isNullValue()) { // ((V | N) & C1) | (V & C2) --> (V|N) & (C1|C2) @@ -2806,7 +2802,7 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { // ORs in the hopes that we'll be able to simplify it this way. // (X|C) | V --> (X|V) | C ConstantInt *CI; - if (Op0->hasOneUse() && !isa(Op1) && + if (Op0->hasOneUse() && !match(Op1, m_ConstantInt()) && match(Op0, m_Or(m_Value(A), m_ConstantInt(CI)))) { Value *Inner = Builder.CreateOr(A, Op1); Inner->takeName(Op0); @@ -2827,18 +2823,17 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { } } - // or(ashr(subNSW(Y, X), ScalarSizeInBits(Y)-1), X) --> X s> Y ? -1 : X. + // or(ashr(subNSW(Y, X), ScalarSizeInBits(Y) - 1), X) --> X s> Y ? -1 : X. { Value *X, *Y; - const APInt *ShAmt; Type *Ty = I.getType(); - if (match(&I, m_c_Or(m_OneUse(m_AShr(m_NSWSub(m_Value(Y), m_Value(X)), - m_APInt(ShAmt))), - m_Deferred(X))) && - *ShAmt == Ty->getScalarSizeInBits() - 1) { + if (match(&I, m_c_Or(m_OneUse(m_AShr( + m_NSWSub(m_Value(Y), m_Value(X)), + m_SpecificInt(Ty->getScalarSizeInBits() - 1))), + m_Deferred(X)))) { Value *NewICmpInst = Builder.CreateICmpSGT(X, Y); - return SelectInst::Create(NewICmpInst, ConstantInt::getAllOnesValue(Ty), - X); + Value *AllOnes = ConstantInt::getAllOnesValue(Ty); + return SelectInst::Create(NewICmpInst, AllOnes, X); } } @@ -2872,6 +2867,10 @@ Instruction *InstCombiner::visitOr(BinaryOperator &I) { } } + // (~x) | y --> ~(x & (~y)) iff that gets rid of inversions + if (sinkNotIntoOtherHandOfAndOrOr(I)) + return &I; + return nullptr; } @@ -2928,8 +2927,8 @@ static Instruction *foldXorToXor(BinaryOperator &I, return nullptr; } -Value *InstCombiner::foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS, - BinaryOperator &I) { +Value *InstCombinerImpl::foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS, + BinaryOperator &I) { assert(I.getOpcode() == Instruction::Xor && I.getOperand(0) == LHS && I.getOperand(1) == RHS && "Should be 'xor' with these operands"); @@ -3087,9 +3086,9 @@ static Instruction *sinkNotIntoXor(BinaryOperator &I, return nullptr; // We only want to do the transform if it is free to do. - if (isFreeToInvert(X, X->hasOneUse())) { + if (InstCombiner::isFreeToInvert(X, X->hasOneUse())) { // Ok, good. - } else if (isFreeToInvert(Y, Y->hasOneUse())) { + } else if (InstCombiner::isFreeToInvert(Y, Y->hasOneUse())) { std::swap(X, Y); } else return nullptr; @@ -3098,10 +3097,52 @@ static Instruction *sinkNotIntoXor(BinaryOperator &I, return BinaryOperator::CreateXor(NotX, Y, I.getName() + ".demorgan"); } +// Transform +// z = (~x) &/| y +// into: +// z = ~(x |/& (~y)) +// iff y is free to invert and all uses of z can be freely updated. +bool InstCombinerImpl::sinkNotIntoOtherHandOfAndOrOr(BinaryOperator &I) { + Instruction::BinaryOps NewOpc; + switch (I.getOpcode()) { + case Instruction::And: + NewOpc = Instruction::Or; + break; + case Instruction::Or: + NewOpc = Instruction::And; + break; + default: + return false; + }; + + Value *X, *Y; + if (!match(&I, m_c_BinOp(m_Not(m_Value(X)), m_Value(Y)))) + return false; + + // Will we be able to fold the `not` into Y eventually? + if (!InstCombiner::isFreeToInvert(Y, Y->hasOneUse())) + return false; + + // And can our users be adapted? + if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr)) + return false; + + Value *NotY = Builder.CreateNot(Y, Y->getName() + ".not"); + Value *NewBinOp = + BinaryOperator::Create(NewOpc, X, NotY, I.getName() + ".not"); + Builder.Insert(NewBinOp); + replaceInstUsesWith(I, NewBinOp); + // We can not just create an outer `not`, it will most likely be immediately + // folded back, reconstructing our initial pattern, and causing an + // infinite combine loop, so immediately manually fold it away. + freelyInvertAllUsersOf(NewBinOp); + return true; +} + // FIXME: We use commutative matchers (m_c_*) for some, but not all, matches // here. We should standardize that construct where it is needed or choose some // other way to ensure that commutated variants of patterns are not missed. -Instruction *InstCombiner::visitXor(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { if (Value *V = SimplifyXorInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -3128,6 +3169,7 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { return replaceInstUsesWith(I, V); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + Type *Ty = I.getType(); // Fold (X & M) ^ (Y & ~M) -> (X & M) | (Y & ~M) // This it a special case in haveNoCommonBitsSet, but the computeKnownBits @@ -3199,7 +3241,7 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { match(C, m_Negative())) { // We matched a negative constant, so propagating undef is unsafe. // Clamp undef elements to -1. - Type *EltTy = C->getType()->getScalarType(); + Type *EltTy = Ty->getScalarType(); C = Constant::replaceUndefsWith(C, ConstantInt::getAllOnesValue(EltTy)); return BinaryOperator::CreateLShr(ConstantExpr::getNot(C), Y); } @@ -3209,7 +3251,7 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { match(C, m_NonNegative())) { // We matched a non-negative constant, so propagating undef is unsafe. // Clamp undef elements to 0. - Type *EltTy = C->getType()->getScalarType(); + Type *EltTy = Ty->getScalarType(); C = Constant::replaceUndefsWith(C, ConstantInt::getNullValue(EltTy)); return BinaryOperator::CreateAShr(ConstantExpr::getNot(C), Y); } @@ -3217,6 +3259,11 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { // ~(X + C) --> -(C + 1) - X if (match(Op0, m_Add(m_Value(X), m_Constant(C)))) return BinaryOperator::CreateSub(ConstantExpr::getNeg(AddOne(C)), X); + + // ~(~X + Y) --> X - Y + if (match(NotVal, m_c_Add(m_Not(m_Value(X)), m_Value(Y)))) + return BinaryOperator::CreateWithCopiedFlags(Instruction::Sub, X, Y, + NotVal); } // Use DeMorgan and reassociation to eliminate a 'not' op. @@ -3247,52 +3294,56 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { if (match(Op1, m_APInt(RHSC))) { Value *X; const APInt *C; - if (RHSC->isSignMask() && match(Op0, m_Sub(m_APInt(C), m_Value(X)))) { - // (C - X) ^ signmask -> (C + signmask - X) - Constant *NewC = ConstantInt::get(I.getType(), *C + *RHSC); - return BinaryOperator::CreateSub(NewC, X); - } - if (RHSC->isSignMask() && match(Op0, m_Add(m_Value(X), m_APInt(C)))) { - // (X + C) ^ signmask -> (X + C + signmask) - Constant *NewC = ConstantInt::get(I.getType(), *C + *RHSC); - return BinaryOperator::CreateAdd(X, NewC); - } + // (C - X) ^ signmaskC --> (C + signmaskC) - X + if (RHSC->isSignMask() && match(Op0, m_Sub(m_APInt(C), m_Value(X)))) + return BinaryOperator::CreateSub(ConstantInt::get(Ty, *C + *RHSC), X); + + // (X + C) ^ signmaskC --> X + (C + signmaskC) + if (RHSC->isSignMask() && match(Op0, m_Add(m_Value(X), m_APInt(C)))) + return BinaryOperator::CreateAdd(X, ConstantInt::get(Ty, *C + *RHSC)); - // (X|C1)^C2 -> X^(C1^C2) iff X&~C1 == 0 + // (X | C) ^ RHSC --> X ^ (C ^ RHSC) iff X & C == 0 if (match(Op0, m_Or(m_Value(X), m_APInt(C))) && - MaskedValueIsZero(X, *C, 0, &I)) { - Constant *NewC = ConstantInt::get(I.getType(), *C ^ *RHSC); - return BinaryOperator::CreateXor(X, NewC); + MaskedValueIsZero(X, *C, 0, &I)) + return BinaryOperator::CreateXor(X, ConstantInt::get(Ty, *C ^ *RHSC)); + + // If RHSC is inverting the remaining bits of shifted X, + // canonicalize to a 'not' before the shift to help SCEV and codegen: + // (X << C) ^ RHSC --> ~X << C + if (match(Op0, m_OneUse(m_Shl(m_Value(X), m_APInt(C)))) && + *RHSC == APInt::getAllOnesValue(Ty->getScalarSizeInBits()).shl(*C)) { + Value *NotX = Builder.CreateNot(X); + return BinaryOperator::CreateShl(NotX, ConstantInt::get(Ty, *C)); } + // (X >>u C) ^ RHSC --> ~X >>u C + if (match(Op0, m_OneUse(m_LShr(m_Value(X), m_APInt(C)))) && + *RHSC == APInt::getAllOnesValue(Ty->getScalarSizeInBits()).lshr(*C)) { + Value *NotX = Builder.CreateNot(X); + return BinaryOperator::CreateLShr(NotX, ConstantInt::get(Ty, *C)); + } + // TODO: We could handle 'ashr' here as well. That would be matching + // a 'not' op and moving it before the shift. Doing that requires + // preventing the inverse fold in canShiftBinOpWithConstantRHS(). } } - if (ConstantInt *RHSC = dyn_cast(Op1)) { - if (BinaryOperator *Op0I = dyn_cast(Op0)) { - if (ConstantInt *Op0CI = dyn_cast(Op0I->getOperand(1))) { - if (Op0I->getOpcode() == Instruction::LShr) { - // ((X^C1) >> C2) ^ C3 -> (X>>C2) ^ ((C1>>C2)^C3) - // E1 = "X ^ C1" - BinaryOperator *E1; - ConstantInt *C1; - if (Op0I->hasOneUse() && - (E1 = dyn_cast(Op0I->getOperand(0))) && - E1->getOpcode() == Instruction::Xor && - (C1 = dyn_cast(E1->getOperand(1)))) { - // fold (C1 >> C2) ^ C3 - ConstantInt *C2 = Op0CI, *C3 = RHSC; - APInt FoldConst = C1->getValue().lshr(C2->getValue()); - FoldConst ^= C3->getValue(); - // Prepare the two operands. - Value *Opnd0 = Builder.CreateLShr(E1->getOperand(0), C2); - Opnd0->takeName(Op0I); - cast(Opnd0)->setDebugLoc(I.getDebugLoc()); - Value *FoldVal = ConstantInt::get(Opnd0->getType(), FoldConst); - - return BinaryOperator::CreateXor(Opnd0, FoldVal); - } - } - } + // FIXME: This should not be limited to scalar (pull into APInt match above). + { + Value *X; + ConstantInt *C1, *C2, *C3; + // ((X^C1) >> C2) ^ C3 -> (X>>C2) ^ ((C1>>C2)^C3) + if (match(Op1, m_ConstantInt(C3)) && + match(Op0, m_LShr(m_Xor(m_Value(X), m_ConstantInt(C1)), + m_ConstantInt(C2))) && + Op0->hasOneUse()) { + // fold (C1 >> C2) ^ C3 + APInt FoldConst = C1->getValue().lshr(C2->getValue()); + FoldConst ^= C3->getValue(); + // Prepare the two operands. + auto *Opnd0 = cast(Builder.CreateLShr(X, C2)); + Opnd0->takeName(cast(Op0)); + Opnd0->setDebugLoc(I.getDebugLoc()); + return BinaryOperator::CreateXor(Opnd0, ConstantInt::get(Ty, FoldConst)); } } @@ -3349,6 +3400,25 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { match(Op1, m_Not(m_Specific(A)))) return BinaryOperator::CreateNot(Builder.CreateAnd(A, B)); + // (~A & B) ^ A --> A | B -- There are 4 commuted variants. + if (match(&I, m_c_Xor(m_c_And(m_Not(m_Value(A)), m_Value(B)), m_Deferred(A)))) + return BinaryOperator::CreateOr(A, B); + + // (A | B) ^ (A | C) --> (B ^ C) & ~A -- There are 4 commuted variants. + // TODO: Loosen one-use restriction if common operand is a constant. + Value *D; + if (match(Op0, m_OneUse(m_Or(m_Value(A), m_Value(B)))) && + match(Op1, m_OneUse(m_Or(m_Value(C), m_Value(D))))) { + if (B == C || B == D) + std::swap(A, B); + if (A == C) + std::swap(C, D); + if (A == D) { + Value *NotA = Builder.CreateNot(A); + return BinaryOperator::CreateAnd(Builder.CreateXor(B, C), NotA); + } + } + if (auto *LHS = dyn_cast(I.getOperand(0))) if (auto *RHS = dyn_cast(I.getOperand(1))) if (Value *V = foldXorOfICmps(LHS, RHS, I)) @@ -3366,7 +3436,6 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { std::swap(Op0, Op1); const APInt *ShAmt; - Type *Ty = I.getType(); if (match(Op1, m_AShr(m_Value(A), m_APInt(ShAmt))) && Op1->hasNUses(2) && *ShAmt == Ty->getScalarSizeInBits() - 1 && match(Op0, m_OneUse(m_c_Add(m_Specific(A), m_Specific(Op1))))) { @@ -3425,19 +3494,30 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { } } - // Pull 'not' into operands of select if both operands are one-use compares. + // Pull 'not' into operands of select if both operands are one-use compares + // or one is one-use compare and the other one is a constant. // Inverting the predicates eliminates the 'not' operation. // Example: - // not (select ?, (cmp TPred, ?, ?), (cmp FPred, ?, ?) --> + // not (select ?, (cmp TPred, ?, ?), (cmp FPred, ?, ?) --> // select ?, (cmp InvTPred, ?, ?), (cmp InvFPred, ?, ?) - // TODO: Canonicalize by hoisting 'not' into an arm of the select if only - // 1 select operand is a cmp? + // not (select ?, (cmp TPred, ?, ?), true --> + // select ?, (cmp InvTPred, ?, ?), false if (auto *Sel = dyn_cast(Op0)) { - auto *CmpT = dyn_cast(Sel->getTrueValue()); - auto *CmpF = dyn_cast(Sel->getFalseValue()); - if (CmpT && CmpF && CmpT->hasOneUse() && CmpF->hasOneUse()) { - CmpT->setPredicate(CmpT->getInversePredicate()); - CmpF->setPredicate(CmpF->getInversePredicate()); + Value *TV = Sel->getTrueValue(); + Value *FV = Sel->getFalseValue(); + auto *CmpT = dyn_cast(TV); + auto *CmpF = dyn_cast(FV); + bool InvertibleT = (CmpT && CmpT->hasOneUse()) || isa(TV); + bool InvertibleF = (CmpF && CmpF->hasOneUse()) || isa(FV); + if (InvertibleT && InvertibleF) { + if (CmpT) + CmpT->setPredicate(CmpT->getInversePredicate()); + else + Sel->setTrueValue(ConstantExpr::getNot(cast(TV))); + if (CmpF) + CmpF->setPredicate(CmpF->getInversePredicate()); + else + Sel->setFalseValue(ConstantExpr::getNot(cast(FV))); return replaceInstUsesWith(I, Sel); } } @@ -3446,5 +3526,15 @@ Instruction *InstCombiner::visitXor(BinaryOperator &I) { if (Instruction *NewXor = sinkNotIntoXor(I, Builder)) return NewXor; + // Otherwise, if all else failed, try to hoist the xor-by-constant: + // (X ^ C) ^ Y --> (X ^ Y) ^ C + // Just like we do in other places, we completely avoid the fold + // for constantexprs, at least to avoid endless combine loop. + if (match(&I, m_c_Xor(m_OneUse(m_Xor(m_CombineAnd(m_Value(X), + m_Unless(m_ConstantExpr())), + m_ImmConstant(C1))), + m_Value(Y)))) + return BinaryOperator::CreateXor(Builder.CreateXor(X, Y), C1); + return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp index ba1cf982229d..495493aab4b5 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp @@ -9,8 +9,10 @@ // This file implements the visit functions for atomic rmw instructions. // //===----------------------------------------------------------------------===// + #include "InstCombineInternal.h" #include "llvm/IR/Instructions.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" using namespace llvm; @@ -30,7 +32,7 @@ bool isIdempotentRMW(AtomicRMWInst& RMWI) { default: return false; }; - + auto C = dyn_cast(RMWI.getValOperand()); if(!C) return false; @@ -91,13 +93,13 @@ bool isSaturating(AtomicRMWInst& RMWI) { return C->isMaxValue(false); }; } -} +} // namespace -Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) { +Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) { // Volatile RMWs perform a load and a store, we cannot replace this by just a // load or just a store. We chose not to canonicalize out of general paranoia - // about user expectations around volatile. + // about user expectations around volatile. if (RMWI.isVolatile()) return nullptr; @@ -115,7 +117,7 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) { "AtomicRMWs don't make sense with Unordered or NotAtomic"); // Any atomicrmw xchg with no uses can be converted to a atomic store if the - // ordering is compatible. + // ordering is compatible. if (RMWI.getOperation() == AtomicRMWInst::Xchg && RMWI.use_empty()) { if (Ordering != AtomicOrdering::Release && @@ -127,14 +129,14 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) { SI->setAlignment(DL.getABITypeAlign(RMWI.getType())); return eraseInstFromFunction(RMWI); } - + if (!isIdempotentRMW(RMWI)) return nullptr; // We chose to canonicalize all idempotent operations to an single // operation code and constant. This makes it easier for the rest of the // optimizer to match easily. The choices of or w/0 and fadd w/-0.0 are - // arbitrary. + // arbitrary. if (RMWI.getType()->isIntegerTy() && RMWI.getOperation() != AtomicRMWInst::Or) { RMWI.setOperation(AtomicRMWInst::Or); @@ -149,7 +151,7 @@ Instruction *InstCombiner::visitAtomicRMWInst(AtomicRMWInst &RMWI) { if (Ordering != AtomicOrdering::Acquire && Ordering != AtomicOrdering::Monotonic) return nullptr; - + LoadInst *Load = new LoadInst(RMWI.getType(), RMWI.getPointerOperand(), "", false, DL.getABITypeAlign(RMWI.getType()), Ordering, RMWI.getSyncScopeID()); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index c734c9a68fb2..5482b944e347 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -28,6 +28,7 @@ #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/MemoryBuiltins.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/Attributes.h" @@ -47,9 +48,6 @@ #include "llvm/IR/IntrinsicsAMDGPU.h" #include "llvm/IR/IntrinsicsARM.h" #include "llvm/IR/IntrinsicsHexagon.h" -#include "llvm/IR/IntrinsicsNVPTX.h" -#include "llvm/IR/IntrinsicsPowerPC.h" -#include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/PatternMatch.h" @@ -68,6 +66,7 @@ #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/SimplifyLibCalls.h" #include @@ -100,24 +99,7 @@ static Type *getPromotedType(Type *Ty) { return Ty; } -/// Return a constant boolean vector that has true elements in all positions -/// where the input constant data vector has an element with the sign bit set. -static Constant *getNegativeIsTrueBoolVec(ConstantDataVector *V) { - SmallVector BoolVec; - IntegerType *BoolTy = Type::getInt1Ty(V->getContext()); - for (unsigned I = 0, E = V->getNumElements(); I != E; ++I) { - Constant *Elt = V->getElementAsConstant(I); - assert((isa(Elt) || isa(Elt)) && - "Unexpected constant data vector element type"); - bool Sign = V->getElementType()->isIntegerTy() - ? cast(Elt)->isNegative() - : cast(Elt)->isNegative(); - BoolVec.push_back(ConstantInt::get(BoolTy, Sign)); - } - return ConstantVector::get(BoolVec); -} - -Instruction *InstCombiner::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { +Instruction *InstCombinerImpl::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { Align DstAlign = getKnownAlignment(MI->getRawDest(), DL, MI, &AC, &DT); MaybeAlign CopyDstAlign = MI->getDestAlign(); if (!CopyDstAlign || *CopyDstAlign < DstAlign) { @@ -232,7 +214,7 @@ Instruction *InstCombiner::SimplifyAnyMemTransfer(AnyMemTransferInst *MI) { return MI; } -Instruction *InstCombiner::SimplifyAnyMemSet(AnyMemSetInst *MI) { +Instruction *InstCombinerImpl::SimplifyAnyMemSet(AnyMemSetInst *MI) { const Align KnownAlignment = getKnownAlignment(MI->getDest(), DL, MI, &AC, &DT); MaybeAlign MemSetAlign = MI->getDestAlign(); @@ -292,820 +274,9 @@ Instruction *InstCombiner::SimplifyAnyMemSet(AnyMemSetInst *MI) { return nullptr; } -static Value *simplifyX86immShift(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - bool LogicalShift = false; - bool ShiftLeft = false; - bool IsImm = false; - - switch (II.getIntrinsicID()) { - default: llvm_unreachable("Unexpected intrinsic!"); - case Intrinsic::x86_sse2_psrai_d: - case Intrinsic::x86_sse2_psrai_w: - case Intrinsic::x86_avx2_psrai_d: - case Intrinsic::x86_avx2_psrai_w: - case Intrinsic::x86_avx512_psrai_q_128: - case Intrinsic::x86_avx512_psrai_q_256: - case Intrinsic::x86_avx512_psrai_d_512: - case Intrinsic::x86_avx512_psrai_q_512: - case Intrinsic::x86_avx512_psrai_w_512: - IsImm = true; - LLVM_FALLTHROUGH; - case Intrinsic::x86_sse2_psra_d: - case Intrinsic::x86_sse2_psra_w: - case Intrinsic::x86_avx2_psra_d: - case Intrinsic::x86_avx2_psra_w: - case Intrinsic::x86_avx512_psra_q_128: - case Intrinsic::x86_avx512_psra_q_256: - case Intrinsic::x86_avx512_psra_d_512: - case Intrinsic::x86_avx512_psra_q_512: - case Intrinsic::x86_avx512_psra_w_512: - LogicalShift = false; - ShiftLeft = false; - break; - case Intrinsic::x86_sse2_psrli_d: - case Intrinsic::x86_sse2_psrli_q: - case Intrinsic::x86_sse2_psrli_w: - case Intrinsic::x86_avx2_psrli_d: - case Intrinsic::x86_avx2_psrli_q: - case Intrinsic::x86_avx2_psrli_w: - case Intrinsic::x86_avx512_psrli_d_512: - case Intrinsic::x86_avx512_psrli_q_512: - case Intrinsic::x86_avx512_psrli_w_512: - IsImm = true; - LLVM_FALLTHROUGH; - case Intrinsic::x86_sse2_psrl_d: - case Intrinsic::x86_sse2_psrl_q: - case Intrinsic::x86_sse2_psrl_w: - case Intrinsic::x86_avx2_psrl_d: - case Intrinsic::x86_avx2_psrl_q: - case Intrinsic::x86_avx2_psrl_w: - case Intrinsic::x86_avx512_psrl_d_512: - case Intrinsic::x86_avx512_psrl_q_512: - case Intrinsic::x86_avx512_psrl_w_512: - LogicalShift = true; - ShiftLeft = false; - break; - case Intrinsic::x86_sse2_pslli_d: - case Intrinsic::x86_sse2_pslli_q: - case Intrinsic::x86_sse2_pslli_w: - case Intrinsic::x86_avx2_pslli_d: - case Intrinsic::x86_avx2_pslli_q: - case Intrinsic::x86_avx2_pslli_w: - case Intrinsic::x86_avx512_pslli_d_512: - case Intrinsic::x86_avx512_pslli_q_512: - case Intrinsic::x86_avx512_pslli_w_512: - IsImm = true; - LLVM_FALLTHROUGH; - case Intrinsic::x86_sse2_psll_d: - case Intrinsic::x86_sse2_psll_q: - case Intrinsic::x86_sse2_psll_w: - case Intrinsic::x86_avx2_psll_d: - case Intrinsic::x86_avx2_psll_q: - case Intrinsic::x86_avx2_psll_w: - case Intrinsic::x86_avx512_psll_d_512: - case Intrinsic::x86_avx512_psll_q_512: - case Intrinsic::x86_avx512_psll_w_512: - LogicalShift = true; - ShiftLeft = true; - break; - } - assert((LogicalShift || !ShiftLeft) && "Only logical shifts can shift left"); - - auto Vec = II.getArgOperand(0); - auto Amt = II.getArgOperand(1); - auto VT = cast(Vec->getType()); - auto SVT = VT->getElementType(); - auto AmtVT = Amt->getType(); - unsigned VWidth = VT->getNumElements(); - unsigned BitWidth = SVT->getPrimitiveSizeInBits(); - - // If the shift amount is guaranteed to be in-range we can replace it with a - // generic shift. If its guaranteed to be out of range, logical shifts combine to - // zero and arithmetic shifts are clamped to (BitWidth - 1). - if (IsImm) { - assert(AmtVT ->isIntegerTy(32) && - "Unexpected shift-by-immediate type"); - KnownBits KnownAmtBits = - llvm::computeKnownBits(Amt, II.getModule()->getDataLayout()); - if (KnownAmtBits.getMaxValue().ult(BitWidth)) { - Amt = Builder.CreateZExtOrTrunc(Amt, SVT); - Amt = Builder.CreateVectorSplat(VWidth, Amt); - return (LogicalShift ? (ShiftLeft ? Builder.CreateShl(Vec, Amt) - : Builder.CreateLShr(Vec, Amt)) - : Builder.CreateAShr(Vec, Amt)); - } - if (KnownAmtBits.getMinValue().uge(BitWidth)) { - if (LogicalShift) - return ConstantAggregateZero::get(VT); - Amt = ConstantInt::get(SVT, BitWidth - 1); - return Builder.CreateAShr(Vec, Builder.CreateVectorSplat(VWidth, Amt)); - } - } else { - // Ensure the first element has an in-range value and the rest of the - // elements in the bottom 64 bits are zero. - assert(AmtVT->isVectorTy() && AmtVT->getPrimitiveSizeInBits() == 128 && - cast(AmtVT)->getElementType() == SVT && - "Unexpected shift-by-scalar type"); - unsigned NumAmtElts = cast(AmtVT)->getNumElements(); - APInt DemandedLower = APInt::getOneBitSet(NumAmtElts, 0); - APInt DemandedUpper = APInt::getBitsSet(NumAmtElts, 1, NumAmtElts / 2); - KnownBits KnownLowerBits = llvm::computeKnownBits( - Amt, DemandedLower, II.getModule()->getDataLayout()); - KnownBits KnownUpperBits = llvm::computeKnownBits( - Amt, DemandedUpper, II.getModule()->getDataLayout()); - if (KnownLowerBits.getMaxValue().ult(BitWidth) && - (DemandedUpper.isNullValue() || KnownUpperBits.isZero())) { - SmallVector ZeroSplat(VWidth, 0); - Amt = Builder.CreateShuffleVector(Amt, Amt, ZeroSplat); - return (LogicalShift ? (ShiftLeft ? Builder.CreateShl(Vec, Amt) - : Builder.CreateLShr(Vec, Amt)) - : Builder.CreateAShr(Vec, Amt)); - } - } - - // Simplify if count is constant vector. - auto CDV = dyn_cast(Amt); - if (!CDV) - return nullptr; - - // SSE2/AVX2 uses all the first 64-bits of the 128-bit vector - // operand to compute the shift amount. - assert(AmtVT->isVectorTy() && AmtVT->getPrimitiveSizeInBits() == 128 && - cast(AmtVT)->getElementType() == SVT && - "Unexpected shift-by-scalar type"); - - // Concatenate the sub-elements to create the 64-bit value. - APInt Count(64, 0); - for (unsigned i = 0, NumSubElts = 64 / BitWidth; i != NumSubElts; ++i) { - unsigned SubEltIdx = (NumSubElts - 1) - i; - auto SubElt = cast(CDV->getElementAsConstant(SubEltIdx)); - Count <<= BitWidth; - Count |= SubElt->getValue().zextOrTrunc(64); - } - - // If shift-by-zero then just return the original value. - if (Count.isNullValue()) - return Vec; - - // Handle cases when Shift >= BitWidth. - if (Count.uge(BitWidth)) { - // If LogicalShift - just return zero. - if (LogicalShift) - return ConstantAggregateZero::get(VT); - - // If ArithmeticShift - clamp Shift to (BitWidth - 1). - Count = APInt(64, BitWidth - 1); - } - - // Get a constant vector of the same type as the first operand. - auto ShiftAmt = ConstantInt::get(SVT, Count.zextOrTrunc(BitWidth)); - auto ShiftVec = Builder.CreateVectorSplat(VWidth, ShiftAmt); - - if (ShiftLeft) - return Builder.CreateShl(Vec, ShiftVec); - - if (LogicalShift) - return Builder.CreateLShr(Vec, ShiftVec); - - return Builder.CreateAShr(Vec, ShiftVec); -} - -// Attempt to simplify AVX2 per-element shift intrinsics to a generic IR shift. -// Unlike the generic IR shifts, the intrinsics have defined behaviour for out -// of range shift amounts (logical - set to zero, arithmetic - splat sign bit). -static Value *simplifyX86varShift(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - bool LogicalShift = false; - bool ShiftLeft = false; - - switch (II.getIntrinsicID()) { - default: llvm_unreachable("Unexpected intrinsic!"); - case Intrinsic::x86_avx2_psrav_d: - case Intrinsic::x86_avx2_psrav_d_256: - case Intrinsic::x86_avx512_psrav_q_128: - case Intrinsic::x86_avx512_psrav_q_256: - case Intrinsic::x86_avx512_psrav_d_512: - case Intrinsic::x86_avx512_psrav_q_512: - case Intrinsic::x86_avx512_psrav_w_128: - case Intrinsic::x86_avx512_psrav_w_256: - case Intrinsic::x86_avx512_psrav_w_512: - LogicalShift = false; - ShiftLeft = false; - break; - case Intrinsic::x86_avx2_psrlv_d: - case Intrinsic::x86_avx2_psrlv_d_256: - case Intrinsic::x86_avx2_psrlv_q: - case Intrinsic::x86_avx2_psrlv_q_256: - case Intrinsic::x86_avx512_psrlv_d_512: - case Intrinsic::x86_avx512_psrlv_q_512: - case Intrinsic::x86_avx512_psrlv_w_128: - case Intrinsic::x86_avx512_psrlv_w_256: - case Intrinsic::x86_avx512_psrlv_w_512: - LogicalShift = true; - ShiftLeft = false; - break; - case Intrinsic::x86_avx2_psllv_d: - case Intrinsic::x86_avx2_psllv_d_256: - case Intrinsic::x86_avx2_psllv_q: - case Intrinsic::x86_avx2_psllv_q_256: - case Intrinsic::x86_avx512_psllv_d_512: - case Intrinsic::x86_avx512_psllv_q_512: - case Intrinsic::x86_avx512_psllv_w_128: - case Intrinsic::x86_avx512_psllv_w_256: - case Intrinsic::x86_avx512_psllv_w_512: - LogicalShift = true; - ShiftLeft = true; - break; - } - assert((LogicalShift || !ShiftLeft) && "Only logical shifts can shift left"); - - auto Vec = II.getArgOperand(0); - auto Amt = II.getArgOperand(1); - auto VT = cast(II.getType()); - auto SVT = VT->getElementType(); - int NumElts = VT->getNumElements(); - int BitWidth = SVT->getIntegerBitWidth(); - - // If the shift amount is guaranteed to be in-range we can replace it with a - // generic shift. - APInt UpperBits = - APInt::getHighBitsSet(BitWidth, BitWidth - Log2_32(BitWidth)); - if (llvm::MaskedValueIsZero(Amt, UpperBits, - II.getModule()->getDataLayout())) { - return (LogicalShift ? (ShiftLeft ? Builder.CreateShl(Vec, Amt) - : Builder.CreateLShr(Vec, Amt)) - : Builder.CreateAShr(Vec, Amt)); - } - - // Simplify if all shift amounts are constant/undef. - auto *CShift = dyn_cast(Amt); - if (!CShift) - return nullptr; - - // Collect each element's shift amount. - // We also collect special cases: UNDEF = -1, OUT-OF-RANGE = BitWidth. - bool AnyOutOfRange = false; - SmallVector ShiftAmts; - for (int I = 0; I < NumElts; ++I) { - auto *CElt = CShift->getAggregateElement(I); - if (CElt && isa(CElt)) { - ShiftAmts.push_back(-1); - continue; - } - - auto *COp = dyn_cast_or_null(CElt); - if (!COp) - return nullptr; - - // Handle out of range shifts. - // If LogicalShift - set to BitWidth (special case). - // If ArithmeticShift - set to (BitWidth - 1) (sign splat). - APInt ShiftVal = COp->getValue(); - if (ShiftVal.uge(BitWidth)) { - AnyOutOfRange = LogicalShift; - ShiftAmts.push_back(LogicalShift ? BitWidth : BitWidth - 1); - continue; - } - - ShiftAmts.push_back((int)ShiftVal.getZExtValue()); - } - - // If all elements out of range or UNDEF, return vector of zeros/undefs. - // ArithmeticShift should only hit this if they are all UNDEF. - auto OutOfRange = [&](int Idx) { return (Idx < 0) || (BitWidth <= Idx); }; - if (llvm::all_of(ShiftAmts, OutOfRange)) { - SmallVector ConstantVec; - for (int Idx : ShiftAmts) { - if (Idx < 0) { - ConstantVec.push_back(UndefValue::get(SVT)); - } else { - assert(LogicalShift && "Logical shift expected"); - ConstantVec.push_back(ConstantInt::getNullValue(SVT)); - } - } - return ConstantVector::get(ConstantVec); - } - - // We can't handle only some out of range values with generic logical shifts. - if (AnyOutOfRange) - return nullptr; - - // Build the shift amount constant vector. - SmallVector ShiftVecAmts; - for (int Idx : ShiftAmts) { - if (Idx < 0) - ShiftVecAmts.push_back(UndefValue::get(SVT)); - else - ShiftVecAmts.push_back(ConstantInt::get(SVT, Idx)); - } - auto ShiftVec = ConstantVector::get(ShiftVecAmts); - - if (ShiftLeft) - return Builder.CreateShl(Vec, ShiftVec); - - if (LogicalShift) - return Builder.CreateLShr(Vec, ShiftVec); - - return Builder.CreateAShr(Vec, ShiftVec); -} - -static Value *simplifyX86pack(IntrinsicInst &II, - InstCombiner::BuilderTy &Builder, bool IsSigned) { - Value *Arg0 = II.getArgOperand(0); - Value *Arg1 = II.getArgOperand(1); - Type *ResTy = II.getType(); - - // Fast all undef handling. - if (isa(Arg0) && isa(Arg1)) - return UndefValue::get(ResTy); - - auto *ArgTy = cast(Arg0->getType()); - unsigned NumLanes = ResTy->getPrimitiveSizeInBits() / 128; - unsigned NumSrcElts = ArgTy->getNumElements(); - assert(cast(ResTy)->getNumElements() == (2 * NumSrcElts) && - "Unexpected packing types"); - - unsigned NumSrcEltsPerLane = NumSrcElts / NumLanes; - unsigned DstScalarSizeInBits = ResTy->getScalarSizeInBits(); - unsigned SrcScalarSizeInBits = ArgTy->getScalarSizeInBits(); - assert(SrcScalarSizeInBits == (2 * DstScalarSizeInBits) && - "Unexpected packing types"); - - // Constant folding. - if (!isa(Arg0) || !isa(Arg1)) - return nullptr; - - // Clamp Values - signed/unsigned both use signed clamp values, but they - // differ on the min/max values. - APInt MinValue, MaxValue; - if (IsSigned) { - // PACKSS: Truncate signed value with signed saturation. - // Source values less than dst minint are saturated to minint. - // Source values greater than dst maxint are saturated to maxint. - MinValue = - APInt::getSignedMinValue(DstScalarSizeInBits).sext(SrcScalarSizeInBits); - MaxValue = - APInt::getSignedMaxValue(DstScalarSizeInBits).sext(SrcScalarSizeInBits); - } else { - // PACKUS: Truncate signed value with unsigned saturation. - // Source values less than zero are saturated to zero. - // Source values greater than dst maxuint are saturated to maxuint. - MinValue = APInt::getNullValue(SrcScalarSizeInBits); - MaxValue = APInt::getLowBitsSet(SrcScalarSizeInBits, DstScalarSizeInBits); - } - - auto *MinC = Constant::getIntegerValue(ArgTy, MinValue); - auto *MaxC = Constant::getIntegerValue(ArgTy, MaxValue); - Arg0 = Builder.CreateSelect(Builder.CreateICmpSLT(Arg0, MinC), MinC, Arg0); - Arg1 = Builder.CreateSelect(Builder.CreateICmpSLT(Arg1, MinC), MinC, Arg1); - Arg0 = Builder.CreateSelect(Builder.CreateICmpSGT(Arg0, MaxC), MaxC, Arg0); - Arg1 = Builder.CreateSelect(Builder.CreateICmpSGT(Arg1, MaxC), MaxC, Arg1); - - // Shuffle clamped args together at the lane level. - SmallVector PackMask; - for (unsigned Lane = 0; Lane != NumLanes; ++Lane) { - for (unsigned Elt = 0; Elt != NumSrcEltsPerLane; ++Elt) - PackMask.push_back(Elt + (Lane * NumSrcEltsPerLane)); - for (unsigned Elt = 0; Elt != NumSrcEltsPerLane; ++Elt) - PackMask.push_back(Elt + (Lane * NumSrcEltsPerLane) + NumSrcElts); - } - auto *Shuffle = Builder.CreateShuffleVector(Arg0, Arg1, PackMask); - - // Truncate to dst size. - return Builder.CreateTrunc(Shuffle, ResTy); -} - -static Value *simplifyX86movmsk(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - Value *Arg = II.getArgOperand(0); - Type *ResTy = II.getType(); - - // movmsk(undef) -> zero as we must ensure the upper bits are zero. - if (isa(Arg)) - return Constant::getNullValue(ResTy); - - auto *ArgTy = dyn_cast(Arg->getType()); - // We can't easily peek through x86_mmx types. - if (!ArgTy) - return nullptr; - - // Expand MOVMSK to compare/bitcast/zext: - // e.g. PMOVMSKB(v16i8 x): - // %cmp = icmp slt <16 x i8> %x, zeroinitializer - // %int = bitcast <16 x i1> %cmp to i16 - // %res = zext i16 %int to i32 - unsigned NumElts = ArgTy->getNumElements(); - Type *IntegerVecTy = VectorType::getInteger(ArgTy); - Type *IntegerTy = Builder.getIntNTy(NumElts); - - Value *Res = Builder.CreateBitCast(Arg, IntegerVecTy); - Res = Builder.CreateICmpSLT(Res, Constant::getNullValue(IntegerVecTy)); - Res = Builder.CreateBitCast(Res, IntegerTy); - Res = Builder.CreateZExtOrTrunc(Res, ResTy); - return Res; -} - -static Value *simplifyX86addcarry(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - Value *CarryIn = II.getArgOperand(0); - Value *Op1 = II.getArgOperand(1); - Value *Op2 = II.getArgOperand(2); - Type *RetTy = II.getType(); - Type *OpTy = Op1->getType(); - assert(RetTy->getStructElementType(0)->isIntegerTy(8) && - RetTy->getStructElementType(1) == OpTy && OpTy == Op2->getType() && - "Unexpected types for x86 addcarry"); - - // If carry-in is zero, this is just an unsigned add with overflow. - if (match(CarryIn, m_ZeroInt())) { - Value *UAdd = Builder.CreateIntrinsic(Intrinsic::uadd_with_overflow, OpTy, - { Op1, Op2 }); - // The types have to be adjusted to match the x86 call types. - Value *UAddResult = Builder.CreateExtractValue(UAdd, 0); - Value *UAddOV = Builder.CreateZExt(Builder.CreateExtractValue(UAdd, 1), - Builder.getInt8Ty()); - Value *Res = UndefValue::get(RetTy); - Res = Builder.CreateInsertValue(Res, UAddOV, 0); - return Builder.CreateInsertValue(Res, UAddResult, 1); - } - - return nullptr; -} - -static Value *simplifyX86insertps(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - auto *CInt = dyn_cast(II.getArgOperand(2)); - if (!CInt) - return nullptr; - - VectorType *VecTy = cast(II.getType()); - assert(VecTy->getNumElements() == 4 && "insertps with wrong vector type"); - - // The immediate permute control byte looks like this: - // [3:0] - zero mask for each 32-bit lane - // [5:4] - select one 32-bit destination lane - // [7:6] - select one 32-bit source lane - - uint8_t Imm = CInt->getZExtValue(); - uint8_t ZMask = Imm & 0xf; - uint8_t DestLane = (Imm >> 4) & 0x3; - uint8_t SourceLane = (Imm >> 6) & 0x3; - - ConstantAggregateZero *ZeroVector = ConstantAggregateZero::get(VecTy); - - // If all zero mask bits are set, this was just a weird way to - // generate a zero vector. - if (ZMask == 0xf) - return ZeroVector; - - // Initialize by passing all of the first source bits through. - int ShuffleMask[4] = {0, 1, 2, 3}; - - // We may replace the second operand with the zero vector. - Value *V1 = II.getArgOperand(1); - - if (ZMask) { - // If the zero mask is being used with a single input or the zero mask - // overrides the destination lane, this is a shuffle with the zero vector. - if ((II.getArgOperand(0) == II.getArgOperand(1)) || - (ZMask & (1 << DestLane))) { - V1 = ZeroVector; - // We may still move 32-bits of the first source vector from one lane - // to another. - ShuffleMask[DestLane] = SourceLane; - // The zero mask may override the previous insert operation. - for (unsigned i = 0; i < 4; ++i) - if ((ZMask >> i) & 0x1) - ShuffleMask[i] = i + 4; - } else { - // TODO: Model this case as 2 shuffles or a 'logical and' plus shuffle? - return nullptr; - } - } else { - // Replace the selected destination lane with the selected source lane. - ShuffleMask[DestLane] = SourceLane + 4; - } - - return Builder.CreateShuffleVector(II.getArgOperand(0), V1, ShuffleMask); -} - -/// Attempt to simplify SSE4A EXTRQ/EXTRQI instructions using constant folding -/// or conversion to a shuffle vector. -static Value *simplifyX86extrq(IntrinsicInst &II, Value *Op0, - ConstantInt *CILength, ConstantInt *CIIndex, - InstCombiner::BuilderTy &Builder) { - auto LowConstantHighUndef = [&](uint64_t Val) { - Type *IntTy64 = Type::getInt64Ty(II.getContext()); - Constant *Args[] = {ConstantInt::get(IntTy64, Val), - UndefValue::get(IntTy64)}; - return ConstantVector::get(Args); - }; - - // See if we're dealing with constant values. - Constant *C0 = dyn_cast(Op0); - ConstantInt *CI0 = - C0 ? dyn_cast_or_null(C0->getAggregateElement((unsigned)0)) - : nullptr; - - // Attempt to constant fold. - if (CILength && CIIndex) { - // From AMD documentation: "The bit index and field length are each six - // bits in length other bits of the field are ignored." - APInt APIndex = CIIndex->getValue().zextOrTrunc(6); - APInt APLength = CILength->getValue().zextOrTrunc(6); - - unsigned Index = APIndex.getZExtValue(); - - // From AMD documentation: "a value of zero in the field length is - // defined as length of 64". - unsigned Length = APLength == 0 ? 64 : APLength.getZExtValue(); - - // From AMD documentation: "If the sum of the bit index + length field - // is greater than 64, the results are undefined". - unsigned End = Index + Length; - - // Note that both field index and field length are 8-bit quantities. - // Since variables 'Index' and 'Length' are unsigned values - // obtained from zero-extending field index and field length - // respectively, their sum should never wrap around. - if (End > 64) - return UndefValue::get(II.getType()); - - // If we are inserting whole bytes, we can convert this to a shuffle. - // Lowering can recognize EXTRQI shuffle masks. - if ((Length % 8) == 0 && (Index % 8) == 0) { - // Convert bit indices to byte indices. - Length /= 8; - Index /= 8; - - Type *IntTy8 = Type::getInt8Ty(II.getContext()); - auto *ShufTy = FixedVectorType::get(IntTy8, 16); - - SmallVector ShuffleMask; - for (int i = 0; i != (int)Length; ++i) - ShuffleMask.push_back(i + Index); - for (int i = Length; i != 8; ++i) - ShuffleMask.push_back(i + 16); - for (int i = 8; i != 16; ++i) - ShuffleMask.push_back(-1); - - Value *SV = Builder.CreateShuffleVector( - Builder.CreateBitCast(Op0, ShufTy), - ConstantAggregateZero::get(ShufTy), ShuffleMask); - return Builder.CreateBitCast(SV, II.getType()); - } - - // Constant Fold - shift Index'th bit to lowest position and mask off - // Length bits. - if (CI0) { - APInt Elt = CI0->getValue(); - Elt.lshrInPlace(Index); - Elt = Elt.zextOrTrunc(Length); - return LowConstantHighUndef(Elt.getZExtValue()); - } - - // If we were an EXTRQ call, we'll save registers if we convert to EXTRQI. - if (II.getIntrinsicID() == Intrinsic::x86_sse4a_extrq) { - Value *Args[] = {Op0, CILength, CIIndex}; - Module *M = II.getModule(); - Function *F = Intrinsic::getDeclaration(M, Intrinsic::x86_sse4a_extrqi); - return Builder.CreateCall(F, Args); - } - } - - // Constant Fold - extraction from zero is always {zero, undef}. - if (CI0 && CI0->isZero()) - return LowConstantHighUndef(0); - - return nullptr; -} - -/// Attempt to simplify SSE4A INSERTQ/INSERTQI instructions using constant -/// folding or conversion to a shuffle vector. -static Value *simplifyX86insertq(IntrinsicInst &II, Value *Op0, Value *Op1, - APInt APLength, APInt APIndex, - InstCombiner::BuilderTy &Builder) { - // From AMD documentation: "The bit index and field length are each six bits - // in length other bits of the field are ignored." - APIndex = APIndex.zextOrTrunc(6); - APLength = APLength.zextOrTrunc(6); - - // Attempt to constant fold. - unsigned Index = APIndex.getZExtValue(); - - // From AMD documentation: "a value of zero in the field length is - // defined as length of 64". - unsigned Length = APLength == 0 ? 64 : APLength.getZExtValue(); - - // From AMD documentation: "If the sum of the bit index + length field - // is greater than 64, the results are undefined". - unsigned End = Index + Length; - - // Note that both field index and field length are 8-bit quantities. - // Since variables 'Index' and 'Length' are unsigned values - // obtained from zero-extending field index and field length - // respectively, their sum should never wrap around. - if (End > 64) - return UndefValue::get(II.getType()); - - // If we are inserting whole bytes, we can convert this to a shuffle. - // Lowering can recognize INSERTQI shuffle masks. - if ((Length % 8) == 0 && (Index % 8) == 0) { - // Convert bit indices to byte indices. - Length /= 8; - Index /= 8; - - Type *IntTy8 = Type::getInt8Ty(II.getContext()); - auto *ShufTy = FixedVectorType::get(IntTy8, 16); - - SmallVector ShuffleMask; - for (int i = 0; i != (int)Index; ++i) - ShuffleMask.push_back(i); - for (int i = 0; i != (int)Length; ++i) - ShuffleMask.push_back(i + 16); - for (int i = Index + Length; i != 8; ++i) - ShuffleMask.push_back(i); - for (int i = 8; i != 16; ++i) - ShuffleMask.push_back(-1); - - Value *SV = Builder.CreateShuffleVector(Builder.CreateBitCast(Op0, ShufTy), - Builder.CreateBitCast(Op1, ShufTy), - ShuffleMask); - return Builder.CreateBitCast(SV, II.getType()); - } - - // See if we're dealing with constant values. - Constant *C0 = dyn_cast(Op0); - Constant *C1 = dyn_cast(Op1); - ConstantInt *CI00 = - C0 ? dyn_cast_or_null(C0->getAggregateElement((unsigned)0)) - : nullptr; - ConstantInt *CI10 = - C1 ? dyn_cast_or_null(C1->getAggregateElement((unsigned)0)) - : nullptr; - - // Constant Fold - insert bottom Length bits starting at the Index'th bit. - if (CI00 && CI10) { - APInt V00 = CI00->getValue(); - APInt V10 = CI10->getValue(); - APInt Mask = APInt::getLowBitsSet(64, Length).shl(Index); - V00 = V00 & ~Mask; - V10 = V10.zextOrTrunc(Length).zextOrTrunc(64).shl(Index); - APInt Val = V00 | V10; - Type *IntTy64 = Type::getInt64Ty(II.getContext()); - Constant *Args[] = {ConstantInt::get(IntTy64, Val.getZExtValue()), - UndefValue::get(IntTy64)}; - return ConstantVector::get(Args); - } - - // If we were an INSERTQ call, we'll save demanded elements if we convert to - // INSERTQI. - if (II.getIntrinsicID() == Intrinsic::x86_sse4a_insertq) { - Type *IntTy8 = Type::getInt8Ty(II.getContext()); - Constant *CILength = ConstantInt::get(IntTy8, Length, false); - Constant *CIIndex = ConstantInt::get(IntTy8, Index, false); - - Value *Args[] = {Op0, Op1, CILength, CIIndex}; - Module *M = II.getModule(); - Function *F = Intrinsic::getDeclaration(M, Intrinsic::x86_sse4a_insertqi); - return Builder.CreateCall(F, Args); - } - - return nullptr; -} - -/// Attempt to convert pshufb* to shufflevector if the mask is constant. -static Value *simplifyX86pshufb(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - Constant *V = dyn_cast(II.getArgOperand(1)); - if (!V) - return nullptr; - - auto *VecTy = cast(II.getType()); - unsigned NumElts = VecTy->getNumElements(); - assert((NumElts == 16 || NumElts == 32 || NumElts == 64) && - "Unexpected number of elements in shuffle mask!"); - - // Construct a shuffle mask from constant integers or UNDEFs. - int Indexes[64]; - - // Each byte in the shuffle control mask forms an index to permute the - // corresponding byte in the destination operand. - for (unsigned I = 0; I < NumElts; ++I) { - Constant *COp = V->getAggregateElement(I); - if (!COp || (!isa(COp) && !isa(COp))) - return nullptr; - - if (isa(COp)) { - Indexes[I] = -1; - continue; - } - - int8_t Index = cast(COp)->getValue().getZExtValue(); - - // If the most significant bit (bit[7]) of each byte of the shuffle - // control mask is set, then zero is written in the result byte. - // The zero vector is in the right-hand side of the resulting - // shufflevector. - - // The value of each index for the high 128-bit lane is the least - // significant 4 bits of the respective shuffle control byte. - Index = ((Index < 0) ? NumElts : Index & 0x0F) + (I & 0xF0); - Indexes[I] = Index; - } - - auto V1 = II.getArgOperand(0); - auto V2 = Constant::getNullValue(VecTy); - return Builder.CreateShuffleVector(V1, V2, makeArrayRef(Indexes, NumElts)); -} - -/// Attempt to convert vpermilvar* to shufflevector if the mask is constant. -static Value *simplifyX86vpermilvar(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - Constant *V = dyn_cast(II.getArgOperand(1)); - if (!V) - return nullptr; - - auto *VecTy = cast(II.getType()); - unsigned NumElts = VecTy->getNumElements(); - bool IsPD = VecTy->getScalarType()->isDoubleTy(); - unsigned NumLaneElts = IsPD ? 2 : 4; - assert(NumElts == 16 || NumElts == 8 || NumElts == 4 || NumElts == 2); - - // Construct a shuffle mask from constant integers or UNDEFs. - int Indexes[16]; - - // The intrinsics only read one or two bits, clear the rest. - for (unsigned I = 0; I < NumElts; ++I) { - Constant *COp = V->getAggregateElement(I); - if (!COp || (!isa(COp) && !isa(COp))) - return nullptr; - - if (isa(COp)) { - Indexes[I] = -1; - continue; - } - - APInt Index = cast(COp)->getValue(); - Index = Index.zextOrTrunc(32).getLoBits(2); - - // The PD variants uses bit 1 to select per-lane element index, so - // shift down to convert to generic shuffle mask index. - if (IsPD) - Index.lshrInPlace(1); - - // The _256 variants are a bit trickier since the mask bits always index - // into the corresponding 128 half. In order to convert to a generic - // shuffle, we have to make that explicit. - Index += APInt(32, (I / NumLaneElts) * NumLaneElts); - - Indexes[I] = Index.getZExtValue(); - } - - auto V1 = II.getArgOperand(0); - auto V2 = UndefValue::get(V1->getType()); - return Builder.CreateShuffleVector(V1, V2, makeArrayRef(Indexes, NumElts)); -} - -/// Attempt to convert vpermd/vpermps to shufflevector if the mask is constant. -static Value *simplifyX86vpermv(const IntrinsicInst &II, - InstCombiner::BuilderTy &Builder) { - auto *V = dyn_cast(II.getArgOperand(1)); - if (!V) - return nullptr; - - auto *VecTy = cast(II.getType()); - unsigned Size = VecTy->getNumElements(); - assert((Size == 4 || Size == 8 || Size == 16 || Size == 32 || Size == 64) && - "Unexpected shuffle mask size"); - - // Construct a shuffle mask from constant integers or UNDEFs. - int Indexes[64]; - - for (unsigned I = 0; I < Size; ++I) { - Constant *COp = V->getAggregateElement(I); - if (!COp || (!isa(COp) && !isa(COp))) - return nullptr; - - if (isa(COp)) { - Indexes[I] = -1; - continue; - } - - uint32_t Index = cast(COp)->getZExtValue(); - Index &= Size - 1; - Indexes[I] = Index; - } - - auto V1 = II.getArgOperand(0); - auto V2 = UndefValue::get(VecTy); - return Builder.CreateShuffleVector(V1, V2, makeArrayRef(Indexes, Size)); -} - // TODO, Obvious Missing Transforms: // * Narrow width by halfs excluding zero/undef lanes -Value *InstCombiner::simplifyMaskedLoad(IntrinsicInst &II) { +Value *InstCombinerImpl::simplifyMaskedLoad(IntrinsicInst &II) { Value *LoadPtr = II.getArgOperand(0); const Align Alignment = cast(II.getArgOperand(1))->getAlignValue(); @@ -1118,9 +289,8 @@ Value *InstCombiner::simplifyMaskedLoad(IntrinsicInst &II) { // If we can unconditionally load from this address, replace with a // load/select idiom. TODO: use DT for context sensitive query - if (isDereferenceableAndAlignedPointer(LoadPtr, II.getType(), Alignment, - II.getModule()->getDataLayout(), &II, - nullptr)) { + if (isDereferenceablePointer(LoadPtr, II.getType(), + II.getModule()->getDataLayout(), &II, nullptr)) { Value *LI = Builder.CreateAlignedLoad(II.getType(), LoadPtr, Alignment, "unmaskedload"); return Builder.CreateSelect(II.getArgOperand(2), LI, II.getArgOperand(3)); @@ -1132,7 +302,7 @@ Value *InstCombiner::simplifyMaskedLoad(IntrinsicInst &II) { // TODO, Obvious Missing Transforms: // * Single constant active lane -> store // * Narrow width by halfs excluding zero/undef lanes -Instruction *InstCombiner::simplifyMaskedStore(IntrinsicInst &II) { +Instruction *InstCombinerImpl::simplifyMaskedStore(IntrinsicInst &II) { auto *ConstMask = dyn_cast(II.getArgOperand(3)); if (!ConstMask) return nullptr; @@ -1148,11 +318,14 @@ Instruction *InstCombiner::simplifyMaskedStore(IntrinsicInst &II) { return new StoreInst(II.getArgOperand(0), StorePtr, false, Alignment); } + if (isa(ConstMask->getType())) + return nullptr; + // Use masked off lanes to simplify operands via SimplifyDemandedVectorElts APInt DemandedElts = possiblyDemandedEltsInMask(ConstMask); APInt UndefElts(DemandedElts.getBitWidth(), 0); - if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), - DemandedElts, UndefElts)) + if (Value *V = + SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts, UndefElts)) return replaceOperand(II, 0, V); return nullptr; @@ -1165,7 +338,7 @@ Instruction *InstCombiner::simplifyMaskedStore(IntrinsicInst &II) { // * Narrow width by halfs excluding zero/undef lanes // * Vector splat address w/known mask -> scalar load // * Vector incrementing address -> vector masked load -Instruction *InstCombiner::simplifyMaskedGather(IntrinsicInst &II) { +Instruction *InstCombinerImpl::simplifyMaskedGather(IntrinsicInst &II) { return nullptr; } @@ -1175,7 +348,7 @@ Instruction *InstCombiner::simplifyMaskedGather(IntrinsicInst &II) { // * Narrow store width by halfs excluding zero/undef lanes // * Vector splat address w/known mask -> scalar store // * Vector incrementing address -> vector masked store -Instruction *InstCombiner::simplifyMaskedScatter(IntrinsicInst &II) { +Instruction *InstCombinerImpl::simplifyMaskedScatter(IntrinsicInst &II) { auto *ConstMask = dyn_cast(II.getArgOperand(3)); if (!ConstMask) return nullptr; @@ -1184,14 +357,17 @@ Instruction *InstCombiner::simplifyMaskedScatter(IntrinsicInst &II) { if (ConstMask->isNullValue()) return eraseInstFromFunction(II); + if (isa(ConstMask->getType())) + return nullptr; + // Use masked off lanes to simplify operands via SimplifyDemandedVectorElts APInt DemandedElts = possiblyDemandedEltsInMask(ConstMask); APInt UndefElts(DemandedElts.getBitWidth(), 0); - if (Value *V = SimplifyDemandedVectorElts(II.getOperand(0), - DemandedElts, UndefElts)) + if (Value *V = + SimplifyDemandedVectorElts(II.getOperand(0), DemandedElts, UndefElts)) return replaceOperand(II, 0, V); - if (Value *V = SimplifyDemandedVectorElts(II.getOperand(1), - DemandedElts, UndefElts)) + if (Value *V = + SimplifyDemandedVectorElts(II.getOperand(1), DemandedElts, UndefElts)) return replaceOperand(II, 1, V); return nullptr; @@ -1206,7 +382,7 @@ Instruction *InstCombiner::simplifyMaskedScatter(IntrinsicInst &II) { /// This is legal because it preserves the most recent information about /// the presence or absence of invariant.group. static Instruction *simplifyInvariantGroupIntrinsic(IntrinsicInst &II, - InstCombiner &IC) { + InstCombinerImpl &IC) { auto *Arg = II.getArgOperand(0); auto *StrippedArg = Arg->stripPointerCasts(); auto *StrippedInvariantGroupsArg = Arg->stripPointerCastsAndInvariantGroups(); @@ -1231,7 +407,7 @@ static Instruction *simplifyInvariantGroupIntrinsic(IntrinsicInst &II, return cast(Result); } -static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombiner &IC) { +static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) { assert((II.getIntrinsicID() == Intrinsic::cttz || II.getIntrinsicID() == Intrinsic::ctlz) && "Expected cttz or ctlz intrinsic"); @@ -1257,6 +433,9 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombiner &IC) { SelectPatternFlavor SPF = matchSelectPattern(Op0, X, Y).Flavor; if (SPF == SPF_ABS || SPF == SPF_NABS) return IC.replaceOperand(II, 0, X); + + if (match(Op0, m_Intrinsic(m_Value(X)))) + return IC.replaceOperand(II, 0, X); } KnownBits Known = IC.computeKnownBits(Op0, 0, &II); @@ -1301,7 +480,7 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombiner &IC) { return nullptr; } -static Instruction *foldCtpop(IntrinsicInst &II, InstCombiner &IC) { +static Instruction *foldCtpop(IntrinsicInst &II, InstCombinerImpl &IC) { assert(II.getIntrinsicID() == Intrinsic::ctpop && "Expected ctpop intrinsic"); Type *Ty = II.getType(); @@ -1356,107 +535,6 @@ static Instruction *foldCtpop(IntrinsicInst &II, InstCombiner &IC) { return nullptr; } -// TODO: If the x86 backend knew how to convert a bool vector mask back to an -// XMM register mask efficiently, we could transform all x86 masked intrinsics -// to LLVM masked intrinsics and remove the x86 masked intrinsic defs. -static Instruction *simplifyX86MaskedLoad(IntrinsicInst &II, InstCombiner &IC) { - Value *Ptr = II.getOperand(0); - Value *Mask = II.getOperand(1); - Constant *ZeroVec = Constant::getNullValue(II.getType()); - - // Special case a zero mask since that's not a ConstantDataVector. - // This masked load instruction creates a zero vector. - if (isa(Mask)) - return IC.replaceInstUsesWith(II, ZeroVec); - - auto *ConstMask = dyn_cast(Mask); - if (!ConstMask) - return nullptr; - - // The mask is constant. Convert this x86 intrinsic to the LLVM instrinsic - // to allow target-independent optimizations. - - // First, cast the x86 intrinsic scalar pointer to a vector pointer to match - // the LLVM intrinsic definition for the pointer argument. - unsigned AddrSpace = cast(Ptr->getType())->getAddressSpace(); - PointerType *VecPtrTy = PointerType::get(II.getType(), AddrSpace); - Value *PtrCast = IC.Builder.CreateBitCast(Ptr, VecPtrTy, "castvec"); - - // Second, convert the x86 XMM integer vector mask to a vector of bools based - // on each element's most significant bit (the sign bit). - Constant *BoolMask = getNegativeIsTrueBoolVec(ConstMask); - - // The pass-through vector for an x86 masked load is a zero vector. - CallInst *NewMaskedLoad = - IC.Builder.CreateMaskedLoad(PtrCast, Align(1), BoolMask, ZeroVec); - return IC.replaceInstUsesWith(II, NewMaskedLoad); -} - -// TODO: If the x86 backend knew how to convert a bool vector mask back to an -// XMM register mask efficiently, we could transform all x86 masked intrinsics -// to LLVM masked intrinsics and remove the x86 masked intrinsic defs. -static bool simplifyX86MaskedStore(IntrinsicInst &II, InstCombiner &IC) { - Value *Ptr = II.getOperand(0); - Value *Mask = II.getOperand(1); - Value *Vec = II.getOperand(2); - - // Special case a zero mask since that's not a ConstantDataVector: - // this masked store instruction does nothing. - if (isa(Mask)) { - IC.eraseInstFromFunction(II); - return true; - } - - // The SSE2 version is too weird (eg, unaligned but non-temporal) to do - // anything else at this level. - if (II.getIntrinsicID() == Intrinsic::x86_sse2_maskmov_dqu) - return false; - - auto *ConstMask = dyn_cast(Mask); - if (!ConstMask) - return false; - - // The mask is constant. Convert this x86 intrinsic to the LLVM instrinsic - // to allow target-independent optimizations. - - // First, cast the x86 intrinsic scalar pointer to a vector pointer to match - // the LLVM intrinsic definition for the pointer argument. - unsigned AddrSpace = cast(Ptr->getType())->getAddressSpace(); - PointerType *VecPtrTy = PointerType::get(Vec->getType(), AddrSpace); - Value *PtrCast = IC.Builder.CreateBitCast(Ptr, VecPtrTy, "castvec"); - - // Second, convert the x86 XMM integer vector mask to a vector of bools based - // on each element's most significant bit (the sign bit). - Constant *BoolMask = getNegativeIsTrueBoolVec(ConstMask); - - IC.Builder.CreateMaskedStore(Vec, PtrCast, Align(1), BoolMask); - - // 'Replace uses' doesn't work for stores. Erase the original masked store. - IC.eraseInstFromFunction(II); - return true; -} - -// Constant fold llvm.amdgcn.fmed3 intrinsics for standard inputs. -// -// A single NaN input is folded to minnum, so we rely on that folding for -// handling NaNs. -static APFloat fmed3AMDGCN(const APFloat &Src0, const APFloat &Src1, - const APFloat &Src2) { - APFloat Max3 = maxnum(maxnum(Src0, Src1), Src2); - - APFloat::cmpResult Cmp0 = Max3.compare(Src0); - assert(Cmp0 != APFloat::cmpUnordered && "nans handled separately"); - if (Cmp0 == APFloat::cmpEqual) - return maxnum(Src1, Src2); - - APFloat::cmpResult Cmp1 = Max3.compare(Src1); - assert(Cmp1 != APFloat::cmpUnordered && "nans handled separately"); - if (Cmp1 == APFloat::cmpEqual) - return maxnum(Src0, Src2); - - return maxnum(Src0, Src1); -} - /// Convert a table lookup to shufflevector if the mask is constant. /// This could benefit tbl1 if the mask is { 7,6,5,4,3,2,1,0 }, in /// which case we could lower the shufflevector with rev64 instructions @@ -1468,7 +546,7 @@ static Value *simplifyNeonTbl1(const IntrinsicInst &II, if (!C) return nullptr; - auto *VecTy = cast(II.getType()); + auto *VecTy = cast(II.getType()); unsigned NumElts = VecTy->getNumElements(); // Only perform this transformation for <8 x i8> vector types. @@ -1495,28 +573,6 @@ static Value *simplifyNeonTbl1(const IntrinsicInst &II, return Builder.CreateShuffleVector(V1, V2, makeArrayRef(Indexes)); } -/// Convert a vector load intrinsic into a simple llvm load instruction. -/// This is beneficial when the underlying object being addressed comes -/// from a constant, since we get constant-folding for free. -static Value *simplifyNeonVld1(const IntrinsicInst &II, - unsigned MemAlign, - InstCombiner::BuilderTy &Builder) { - auto *IntrAlign = dyn_cast(II.getArgOperand(1)); - - if (!IntrAlign) - return nullptr; - - unsigned Alignment = IntrAlign->getLimitedValue() < MemAlign ? - MemAlign : IntrAlign->getLimitedValue(); - - if (!isPowerOf2_32(Alignment)) - return nullptr; - - auto *BCastInst = Builder.CreateBitCast(II.getArgOperand(0), - PointerType::get(II.getType(), 0)); - return Builder.CreateAlignedLoad(II.getType(), BCastInst, Align(Alignment)); -} - // Returns true iff the 2 intrinsics have the same operands, limiting the // comparison to the first NumOperands. static bool haveSameOperands(const IntrinsicInst &I, const IntrinsicInst &E, @@ -1538,9 +594,9 @@ static bool haveSameOperands(const IntrinsicInst &I, const IntrinsicInst &E, // call @llvm.foo.start(i1 0) ; This one won't be skipped: it will be removed // call @llvm.foo.end(i1 0) // call @llvm.foo.end(i1 0) ; &I -static bool removeTriviallyEmptyRange( - IntrinsicInst &EndI, InstCombiner &IC, - std::function IsStart) { +static bool +removeTriviallyEmptyRange(IntrinsicInst &EndI, InstCombinerImpl &IC, + std::function IsStart) { // We start from the end intrinsic and scan backwards, so that InstCombine // has already processed (and potentially removed) all the instructions // before the end intrinsic. @@ -1566,256 +622,7 @@ static bool removeTriviallyEmptyRange( return false; } -// Convert NVVM intrinsics to target-generic LLVM code where possible. -static Instruction *SimplifyNVVMIntrinsic(IntrinsicInst *II, InstCombiner &IC) { - // Each NVVM intrinsic we can simplify can be replaced with one of: - // - // * an LLVM intrinsic, - // * an LLVM cast operation, - // * an LLVM binary operation, or - // * ad-hoc LLVM IR for the particular operation. - - // Some transformations are only valid when the module's - // flush-denormals-to-zero (ftz) setting is true/false, whereas other - // transformations are valid regardless of the module's ftz setting. - enum FtzRequirementTy { - FTZ_Any, // Any ftz setting is ok. - FTZ_MustBeOn, // Transformation is valid only if ftz is on. - FTZ_MustBeOff, // Transformation is valid only if ftz is off. - }; - // Classes of NVVM intrinsics that can't be replaced one-to-one with a - // target-generic intrinsic, cast op, or binary op but that we can nonetheless - // simplify. - enum SpecialCase { - SPC_Reciprocal, - }; - - // SimplifyAction is a poor-man's variant (plus an additional flag) that - // represents how to replace an NVVM intrinsic with target-generic LLVM IR. - struct SimplifyAction { - // Invariant: At most one of these Optionals has a value. - Optional IID; - Optional CastOp; - Optional BinaryOp; - Optional Special; - - FtzRequirementTy FtzRequirement = FTZ_Any; - - SimplifyAction() = default; - - SimplifyAction(Intrinsic::ID IID, FtzRequirementTy FtzReq) - : IID(IID), FtzRequirement(FtzReq) {} - - // Cast operations don't have anything to do with FTZ, so we skip that - // argument. - SimplifyAction(Instruction::CastOps CastOp) : CastOp(CastOp) {} - - SimplifyAction(Instruction::BinaryOps BinaryOp, FtzRequirementTy FtzReq) - : BinaryOp(BinaryOp), FtzRequirement(FtzReq) {} - - SimplifyAction(SpecialCase Special, FtzRequirementTy FtzReq) - : Special(Special), FtzRequirement(FtzReq) {} - }; - - // Try to generate a SimplifyAction describing how to replace our - // IntrinsicInstr with target-generic LLVM IR. - const SimplifyAction Action = [II]() -> SimplifyAction { - switch (II->getIntrinsicID()) { - // NVVM intrinsics that map directly to LLVM intrinsics. - case Intrinsic::nvvm_ceil_d: - return {Intrinsic::ceil, FTZ_Any}; - case Intrinsic::nvvm_ceil_f: - return {Intrinsic::ceil, FTZ_MustBeOff}; - case Intrinsic::nvvm_ceil_ftz_f: - return {Intrinsic::ceil, FTZ_MustBeOn}; - case Intrinsic::nvvm_fabs_d: - return {Intrinsic::fabs, FTZ_Any}; - case Intrinsic::nvvm_fabs_f: - return {Intrinsic::fabs, FTZ_MustBeOff}; - case Intrinsic::nvvm_fabs_ftz_f: - return {Intrinsic::fabs, FTZ_MustBeOn}; - case Intrinsic::nvvm_floor_d: - return {Intrinsic::floor, FTZ_Any}; - case Intrinsic::nvvm_floor_f: - return {Intrinsic::floor, FTZ_MustBeOff}; - case Intrinsic::nvvm_floor_ftz_f: - return {Intrinsic::floor, FTZ_MustBeOn}; - case Intrinsic::nvvm_fma_rn_d: - return {Intrinsic::fma, FTZ_Any}; - case Intrinsic::nvvm_fma_rn_f: - return {Intrinsic::fma, FTZ_MustBeOff}; - case Intrinsic::nvvm_fma_rn_ftz_f: - return {Intrinsic::fma, FTZ_MustBeOn}; - case Intrinsic::nvvm_fmax_d: - return {Intrinsic::maxnum, FTZ_Any}; - case Intrinsic::nvvm_fmax_f: - return {Intrinsic::maxnum, FTZ_MustBeOff}; - case Intrinsic::nvvm_fmax_ftz_f: - return {Intrinsic::maxnum, FTZ_MustBeOn}; - case Intrinsic::nvvm_fmin_d: - return {Intrinsic::minnum, FTZ_Any}; - case Intrinsic::nvvm_fmin_f: - return {Intrinsic::minnum, FTZ_MustBeOff}; - case Intrinsic::nvvm_fmin_ftz_f: - return {Intrinsic::minnum, FTZ_MustBeOn}; - case Intrinsic::nvvm_round_d: - return {Intrinsic::round, FTZ_Any}; - case Intrinsic::nvvm_round_f: - return {Intrinsic::round, FTZ_MustBeOff}; - case Intrinsic::nvvm_round_ftz_f: - return {Intrinsic::round, FTZ_MustBeOn}; - case Intrinsic::nvvm_sqrt_rn_d: - return {Intrinsic::sqrt, FTZ_Any}; - case Intrinsic::nvvm_sqrt_f: - // nvvm_sqrt_f is a special case. For most intrinsics, foo_ftz_f is the - // ftz version, and foo_f is the non-ftz version. But nvvm_sqrt_f adopts - // the ftz-ness of the surrounding code. sqrt_rn_f and sqrt_rn_ftz_f are - // the versions with explicit ftz-ness. - return {Intrinsic::sqrt, FTZ_Any}; - case Intrinsic::nvvm_sqrt_rn_f: - return {Intrinsic::sqrt, FTZ_MustBeOff}; - case Intrinsic::nvvm_sqrt_rn_ftz_f: - return {Intrinsic::sqrt, FTZ_MustBeOn}; - case Intrinsic::nvvm_trunc_d: - return {Intrinsic::trunc, FTZ_Any}; - case Intrinsic::nvvm_trunc_f: - return {Intrinsic::trunc, FTZ_MustBeOff}; - case Intrinsic::nvvm_trunc_ftz_f: - return {Intrinsic::trunc, FTZ_MustBeOn}; - - // NVVM intrinsics that map to LLVM cast operations. - // - // Note that llvm's target-generic conversion operators correspond to the rz - // (round to zero) versions of the nvvm conversion intrinsics, even though - // most everything else here uses the rn (round to nearest even) nvvm ops. - case Intrinsic::nvvm_d2i_rz: - case Intrinsic::nvvm_f2i_rz: - case Intrinsic::nvvm_d2ll_rz: - case Intrinsic::nvvm_f2ll_rz: - return {Instruction::FPToSI}; - case Intrinsic::nvvm_d2ui_rz: - case Intrinsic::nvvm_f2ui_rz: - case Intrinsic::nvvm_d2ull_rz: - case Intrinsic::nvvm_f2ull_rz: - return {Instruction::FPToUI}; - case Intrinsic::nvvm_i2d_rz: - case Intrinsic::nvvm_i2f_rz: - case Intrinsic::nvvm_ll2d_rz: - case Intrinsic::nvvm_ll2f_rz: - return {Instruction::SIToFP}; - case Intrinsic::nvvm_ui2d_rz: - case Intrinsic::nvvm_ui2f_rz: - case Intrinsic::nvvm_ull2d_rz: - case Intrinsic::nvvm_ull2f_rz: - return {Instruction::UIToFP}; - - // NVVM intrinsics that map to LLVM binary ops. - case Intrinsic::nvvm_add_rn_d: - return {Instruction::FAdd, FTZ_Any}; - case Intrinsic::nvvm_add_rn_f: - return {Instruction::FAdd, FTZ_MustBeOff}; - case Intrinsic::nvvm_add_rn_ftz_f: - return {Instruction::FAdd, FTZ_MustBeOn}; - case Intrinsic::nvvm_mul_rn_d: - return {Instruction::FMul, FTZ_Any}; - case Intrinsic::nvvm_mul_rn_f: - return {Instruction::FMul, FTZ_MustBeOff}; - case Intrinsic::nvvm_mul_rn_ftz_f: - return {Instruction::FMul, FTZ_MustBeOn}; - case Intrinsic::nvvm_div_rn_d: - return {Instruction::FDiv, FTZ_Any}; - case Intrinsic::nvvm_div_rn_f: - return {Instruction::FDiv, FTZ_MustBeOff}; - case Intrinsic::nvvm_div_rn_ftz_f: - return {Instruction::FDiv, FTZ_MustBeOn}; - - // The remainder of cases are NVVM intrinsics that map to LLVM idioms, but - // need special handling. - // - // We seem to be missing intrinsics for rcp.approx.{ftz.}f32, which is just - // as well. - case Intrinsic::nvvm_rcp_rn_d: - return {SPC_Reciprocal, FTZ_Any}; - case Intrinsic::nvvm_rcp_rn_f: - return {SPC_Reciprocal, FTZ_MustBeOff}; - case Intrinsic::nvvm_rcp_rn_ftz_f: - return {SPC_Reciprocal, FTZ_MustBeOn}; - - // We do not currently simplify intrinsics that give an approximate answer. - // These include: - // - // - nvvm_cos_approx_{f,ftz_f} - // - nvvm_ex2_approx_{d,f,ftz_f} - // - nvvm_lg2_approx_{d,f,ftz_f} - // - nvvm_sin_approx_{f,ftz_f} - // - nvvm_sqrt_approx_{f,ftz_f} - // - nvvm_rsqrt_approx_{d,f,ftz_f} - // - nvvm_div_approx_{ftz_d,ftz_f,f} - // - nvvm_rcp_approx_ftz_d - // - // Ideally we'd encode them as e.g. "fast call @llvm.cos", where "fast" - // means that fastmath is enabled in the intrinsic. Unfortunately only - // binary operators (currently) have a fastmath bit in SelectionDAG, so this - // information gets lost and we can't select on it. - // - // TODO: div and rcp are lowered to a binary op, so these we could in theory - // lower them to "fast fdiv". - - default: - return {}; - } - }(); - - // If Action.FtzRequirementTy is not satisfied by the module's ftz state, we - // can bail out now. (Notice that in the case that IID is not an NVVM - // intrinsic, we don't have to look up any module metadata, as - // FtzRequirementTy will be FTZ_Any.) - if (Action.FtzRequirement != FTZ_Any) { - StringRef Attr = II->getFunction() - ->getFnAttribute("denormal-fp-math-f32") - .getValueAsString(); - DenormalMode Mode = parseDenormalFPAttribute(Attr); - bool FtzEnabled = Mode.Output != DenormalMode::IEEE; - - if (FtzEnabled != (Action.FtzRequirement == FTZ_MustBeOn)) - return nullptr; - } - - // Simplify to target-generic intrinsic. - if (Action.IID) { - SmallVector Args(II->arg_operands()); - // All the target-generic intrinsics currently of interest to us have one - // type argument, equal to that of the nvvm intrinsic's argument. - Type *Tys[] = {II->getArgOperand(0)->getType()}; - return CallInst::Create( - Intrinsic::getDeclaration(II->getModule(), *Action.IID, Tys), Args); - } - - // Simplify to target-generic binary op. - if (Action.BinaryOp) - return BinaryOperator::Create(*Action.BinaryOp, II->getArgOperand(0), - II->getArgOperand(1), II->getName()); - - // Simplify to target-generic cast op. - if (Action.CastOp) - return CastInst::Create(*Action.CastOp, II->getArgOperand(0), II->getType(), - II->getName()); - - // All that's left are the special cases. - if (!Action.Special) - return nullptr; - - switch (*Action.Special) { - case SPC_Reciprocal: - // Simplify reciprocal. - return BinaryOperator::Create( - Instruction::FDiv, ConstantFP::get(II->getArgOperand(0)->getType(), 1), - II->getArgOperand(0), II->getName()); - } - llvm_unreachable("All SpecialCase enumerators should be handled in switch."); -} - -Instruction *InstCombiner::visitVAEndInst(VAEndInst &I) { +Instruction *InstCombinerImpl::visitVAEndInst(VAEndInst &I) { removeTriviallyEmptyRange(I, *this, [](const IntrinsicInst &I) { return I.getIntrinsicID() == Intrinsic::vastart || I.getIntrinsicID() == Intrinsic::vacopy; @@ -1823,7 +630,7 @@ Instruction *InstCombiner::visitVAEndInst(VAEndInst &I) { return nullptr; } -static Instruction *canonicalizeConstantArg0ToArg1(CallInst &Call) { +static CallInst *canonicalizeConstantArg0ToArg1(CallInst &Call) { assert(Call.getNumArgOperands() > 1 && "Need at least 2 args to swap"); Value *Arg0 = Call.getArgOperand(0), *Arg1 = Call.getArgOperand(1); if (isa(Arg0) && !isa(Arg1)) { @@ -1834,20 +641,44 @@ static Instruction *canonicalizeConstantArg0ToArg1(CallInst &Call) { return nullptr; } -Instruction *InstCombiner::foldIntrinsicWithOverflowCommon(IntrinsicInst *II) { +/// Creates a result tuple for an overflow intrinsic \p II with a given +/// \p Result and a constant \p Overflow value. +static Instruction *createOverflowTuple(IntrinsicInst *II, Value *Result, + Constant *Overflow) { + Constant *V[] = {UndefValue::get(Result->getType()), Overflow}; + StructType *ST = cast(II->getType()); + Constant *Struct = ConstantStruct::get(ST, V); + return InsertValueInst::Create(Struct, Result, 0); +} + +Instruction * +InstCombinerImpl::foldIntrinsicWithOverflowCommon(IntrinsicInst *II) { WithOverflowInst *WO = cast(II); Value *OperationResult = nullptr; Constant *OverflowResult = nullptr; if (OptimizeOverflowCheck(WO->getBinaryOp(), WO->isSigned(), WO->getLHS(), WO->getRHS(), *WO, OperationResult, OverflowResult)) - return CreateOverflowTuple(WO, OperationResult, OverflowResult); + return createOverflowTuple(WO, OperationResult, OverflowResult); return nullptr; } +static Optional getKnownSign(Value *Op, Instruction *CxtI, + const DataLayout &DL, AssumptionCache *AC, + DominatorTree *DT) { + KnownBits Known = computeKnownBits(Op, DL, 0, AC, CxtI, DT); + if (Known.isNonNegative()) + return false; + if (Known.isNegative()) + return true; + + return isImpliedByDomCondition( + ICmpInst::ICMP_SLT, Op, Constant::getNullValue(Op->getType()), CxtI, DL); +} + /// CallInst simplification. This mostly only handles folding of intrinsic /// instructions. For normal calls, it allows visitCallBase to do the heavy /// lifting. -Instruction *InstCombiner::visitCallInst(CallInst &CI) { +Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) { // Don't try to simplify calls without uses. It will not do anything useful, // but will result in the following folds being skipped. if (!CI.use_empty()) @@ -1953,31 +784,84 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { } } - if (Instruction *I = SimplifyNVVMIntrinsic(II, *this)) - return I; - - auto SimplifyDemandedVectorEltsLow = [this](Value *Op, unsigned Width, - unsigned DemandedWidth) { - APInt UndefElts(Width, 0); - APInt DemandedElts = APInt::getLowBitsSet(Width, DemandedWidth); - return SimplifyDemandedVectorElts(Op, DemandedElts, UndefElts); - }; + if (II->isCommutative()) { + if (CallInst *NewCall = canonicalizeConstantArg0ToArg1(CI)) + return NewCall; + } Intrinsic::ID IID = II->getIntrinsicID(); switch (IID) { - default: break; case Intrinsic::objectsize: if (Value *V = lowerObjectSizeCall(II, DL, &TLI, /*MustSucceed=*/false)) return replaceInstUsesWith(CI, V); return nullptr; + case Intrinsic::abs: { + Value *IIOperand = II->getArgOperand(0); + bool IntMinIsPoison = cast(II->getArgOperand(1))->isOneValue(); + + // abs(-x) -> abs(x) + // TODO: Copy nsw if it was present on the neg? + Value *X; + if (match(IIOperand, m_Neg(m_Value(X)))) + return replaceOperand(*II, 0, X); + if (match(IIOperand, m_Select(m_Value(), m_Value(X), m_Neg(m_Deferred(X))))) + return replaceOperand(*II, 0, X); + if (match(IIOperand, m_Select(m_Value(), m_Neg(m_Value(X)), m_Deferred(X)))) + return replaceOperand(*II, 0, X); + + if (Optional Sign = getKnownSign(IIOperand, II, DL, &AC, &DT)) { + // abs(x) -> x if x >= 0 + if (!*Sign) + return replaceInstUsesWith(*II, IIOperand); + + // abs(x) -> -x if x < 0 + if (IntMinIsPoison) + return BinaryOperator::CreateNSWNeg(IIOperand); + return BinaryOperator::CreateNeg(IIOperand); + } + + // abs (sext X) --> zext (abs X*) + // Clear the IsIntMin (nsw) bit on the abs to allow narrowing. + if (match(IIOperand, m_OneUse(m_SExt(m_Value(X))))) { + Value *NarrowAbs = + Builder.CreateBinaryIntrinsic(Intrinsic::abs, X, Builder.getFalse()); + return CastInst::Create(Instruction::ZExt, NarrowAbs, II->getType()); + } + + break; + } + case Intrinsic::umax: + case Intrinsic::umin: { + Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1); + Value *X, *Y; + if (match(I0, m_ZExt(m_Value(X))) && match(I1, m_ZExt(m_Value(Y))) && + (I0->hasOneUse() || I1->hasOneUse()) && X->getType() == Y->getType()) { + Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, Y); + return CastInst::Create(Instruction::ZExt, NarrowMaxMin, II->getType()); + } + // If both operands of unsigned min/max are sign-extended, it is still ok + // to narrow the operation. + LLVM_FALLTHROUGH; + } + case Intrinsic::smax: + case Intrinsic::smin: { + Value *I0 = II->getArgOperand(0), *I1 = II->getArgOperand(1); + Value *X, *Y; + if (match(I0, m_SExt(m_Value(X))) && match(I1, m_SExt(m_Value(Y))) && + (I0->hasOneUse() || I1->hasOneUse()) && X->getType() == Y->getType()) { + Value *NarrowMaxMin = Builder.CreateBinaryIntrinsic(IID, X, Y); + return CastInst::Create(Instruction::SExt, NarrowMaxMin, II->getType()); + } + break; + } case Intrinsic::bswap: { Value *IIOperand = II->getArgOperand(0); Value *X = nullptr; // bswap(trunc(bswap(x))) -> trunc(lshr(x, c)) if (match(IIOperand, m_Trunc(m_BSwap(m_Value(X))))) { - unsigned C = X->getType()->getPrimitiveSizeInBits() - - IIOperand->getType()->getPrimitiveSizeInBits(); + unsigned C = X->getType()->getScalarSizeInBits() - + IIOperand->getType()->getScalarSizeInBits(); Value *CV = ConstantInt::get(X->getType(), C); Value *V = Builder.CreateLShr(X, CV); return new TruncInst(V, IIOperand->getType()); @@ -2002,15 +886,14 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { case Intrinsic::powi: if (ConstantInt *Power = dyn_cast(II->getArgOperand(1))) { // 0 and 1 are handled in instsimplify - // powi(x, -1) -> 1/x if (Power->isMinusOne()) - return BinaryOperator::CreateFDiv(ConstantFP::get(CI.getType(), 1.0), - II->getArgOperand(0)); + return BinaryOperator::CreateFDivFMF(ConstantFP::get(CI.getType(), 1.0), + II->getArgOperand(0), II); // powi(x, 2) -> x*x if (Power->equalsInt(2)) - return BinaryOperator::CreateFMul(II->getArgOperand(0), - II->getArgOperand(0)); + return BinaryOperator::CreateFMulFMF(II->getArgOperand(0), + II->getArgOperand(0), II); } break; @@ -2031,8 +914,8 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { Type *Ty = II->getType(); unsigned BitWidth = Ty->getScalarSizeInBits(); Constant *ShAmtC; - if (match(II->getArgOperand(2), m_Constant(ShAmtC)) && - !isa(ShAmtC) && !ShAmtC->containsConstantExpression()) { + if (match(II->getArgOperand(2), m_ImmConstant(ShAmtC)) && + !ShAmtC->containsConstantExpression()) { // Canonicalize a shift amount constant operand to modulo the bit-width. Constant *WidthC = ConstantInt::get(Ty, BitWidth); Constant *ModuloC = ConstantExpr::getURem(ShAmtC, WidthC); @@ -2092,8 +975,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { } case Intrinsic::uadd_with_overflow: case Intrinsic::sadd_with_overflow: { - if (Instruction *I = canonicalizeConstantArg0ToArg1(CI)) - return I; if (Instruction *I = foldIntrinsicWithOverflowCommon(II)) return I; @@ -2121,10 +1002,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { case Intrinsic::umul_with_overflow: case Intrinsic::smul_with_overflow: - if (Instruction *I = canonicalizeConstantArg0ToArg1(CI)) - return I; - LLVM_FALLTHROUGH; - case Intrinsic::usub_with_overflow: if (Instruction *I = foldIntrinsicWithOverflowCommon(II)) return I; @@ -2155,9 +1032,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { case Intrinsic::uadd_sat: case Intrinsic::sadd_sat: - if (Instruction *I = canonicalizeConstantArg0ToArg1(CI)) - return I; - LLVM_FALLTHROUGH; case Intrinsic::usub_sat: case Intrinsic::ssub_sat: { SaturatingInst *SI = cast(II); @@ -2238,8 +1112,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { case Intrinsic::maxnum: case Intrinsic::minimum: case Intrinsic::maximum: { - if (Instruction *I = canonicalizeConstantArg0ToArg1(CI)) - return I; Value *Arg0 = II->getArgOperand(0); Value *Arg1 = II->getArgOperand(1); Value *X, *Y; @@ -2348,9 +1220,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { LLVM_FALLTHROUGH; } case Intrinsic::fma: { - if (Instruction *I = canonicalizeConstantArg0ToArg1(CI)) - return I; - // fma fneg(x), fneg(y), z -> fma x, y, z Value *Src0 = II->getArgOperand(0); Value *Src1 = II->getArgOperand(1); @@ -2390,40 +1259,52 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { break; } case Intrinsic::copysign: { - if (SignBitMustBeZero(II->getArgOperand(1), &TLI)) { + Value *Mag = II->getArgOperand(0), *Sign = II->getArgOperand(1); + if (SignBitMustBeZero(Sign, &TLI)) { // If we know that the sign argument is positive, reduce to FABS: - // copysign X, Pos --> fabs X - Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, - II->getArgOperand(0), II); + // copysign Mag, +Sign --> fabs Mag + Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, Mag, II); return replaceInstUsesWith(*II, Fabs); } // TODO: There should be a ValueTracking sibling like SignBitMustBeOne. const APFloat *C; - if (match(II->getArgOperand(1), m_APFloat(C)) && C->isNegative()) { + if (match(Sign, m_APFloat(C)) && C->isNegative()) { // If we know that the sign argument is negative, reduce to FNABS: - // copysign X, Neg --> fneg (fabs X) - Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, - II->getArgOperand(0), II); + // copysign Mag, -Sign --> fneg (fabs Mag) + Value *Fabs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, Mag, II); return replaceInstUsesWith(*II, Builder.CreateFNegFMF(Fabs, II)); } // Propagate sign argument through nested calls: - // copysign X, (copysign ?, SignArg) --> copysign X, SignArg - Value *SignArg; - if (match(II->getArgOperand(1), - m_Intrinsic(m_Value(), m_Value(SignArg)))) - return replaceOperand(*II, 1, SignArg); + // copysign Mag, (copysign ?, X) --> copysign Mag, X + Value *X; + if (match(Sign, m_Intrinsic(m_Value(), m_Value(X)))) + return replaceOperand(*II, 1, X); + + // Peek through changes of magnitude's sign-bit. This call rewrites those: + // copysign (fabs X), Sign --> copysign X, Sign + // copysign (fneg X), Sign --> copysign X, Sign + if (match(Mag, m_FAbs(m_Value(X))) || match(Mag, m_FNeg(m_Value(X)))) + return replaceOperand(*II, 0, X); break; } case Intrinsic::fabs: { - Value *Cond; - Constant *LHS, *RHS; + Value *Cond, *TVal, *FVal; if (match(II->getArgOperand(0), - m_Select(m_Value(Cond), m_Constant(LHS), m_Constant(RHS)))) { - CallInst *Call0 = Builder.CreateCall(II->getCalledFunction(), {LHS}); - CallInst *Call1 = Builder.CreateCall(II->getCalledFunction(), {RHS}); - return SelectInst::Create(Cond, Call0, Call1); + m_Select(m_Value(Cond), m_Value(TVal), m_Value(FVal)))) { + // fabs (select Cond, TrueC, FalseC) --> select Cond, AbsT, AbsF + if (isa(TVal) && isa(FVal)) { + CallInst *AbsT = Builder.CreateCall(II->getCalledFunction(), {TVal}); + CallInst *AbsF = Builder.CreateCall(II->getCalledFunction(), {FVal}); + return SelectInst::Create(Cond, AbsT, AbsF); + } + // fabs (select Cond, -FVal, FVal) --> fabs FVal + if (match(TVal, m_FNeg(m_Specific(FVal)))) + return replaceOperand(*II, 0, FVal); + // fabs (select Cond, TVal, -TVal) --> fabs TVal + if (match(FVal, m_FNeg(m_Specific(TVal)))) + return replaceOperand(*II, 0, TVal); } LLVM_FALLTHROUGH; @@ -2459,936 +1340,10 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { if (match(II->getArgOperand(0), m_OneUse(m_FNeg(m_Value(X))))) { // sin(-x) --> -sin(x) Value *NewSin = Builder.CreateUnaryIntrinsic(Intrinsic::sin, X, II); - Instruction *FNeg = UnaryOperator::CreateFNeg(NewSin); - FNeg->copyFastMathFlags(II); - return FNeg; - } - break; - } - case Intrinsic::ppc_altivec_lvx: - case Intrinsic::ppc_altivec_lvxl: - // Turn PPC lvx -> load if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(0), Align(16), DL, II, &AC, - &DT) >= 16) { - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(0), - PointerType::getUnqual(II->getType())); - return new LoadInst(II->getType(), Ptr, "", false, Align(16)); - } - break; - case Intrinsic::ppc_vsx_lxvw4x: - case Intrinsic::ppc_vsx_lxvd2x: { - // Turn PPC VSX loads into normal loads. - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(0), - PointerType::getUnqual(II->getType())); - return new LoadInst(II->getType(), Ptr, Twine(""), false, Align(1)); - } - case Intrinsic::ppc_altivec_stvx: - case Intrinsic::ppc_altivec_stvxl: - // Turn stvx -> store if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(1), Align(16), DL, II, &AC, - &DT) >= 16) { - Type *OpPtrTy = - PointerType::getUnqual(II->getArgOperand(0)->getType()); - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(1), OpPtrTy); - return new StoreInst(II->getArgOperand(0), Ptr, false, Align(16)); - } - break; - case Intrinsic::ppc_vsx_stxvw4x: - case Intrinsic::ppc_vsx_stxvd2x: { - // Turn PPC VSX stores into normal stores. - Type *OpPtrTy = PointerType::getUnqual(II->getArgOperand(0)->getType()); - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(1), OpPtrTy); - return new StoreInst(II->getArgOperand(0), Ptr, false, Align(1)); - } - case Intrinsic::ppc_qpx_qvlfs: - // Turn PPC QPX qvlfs -> load if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(0), Align(16), DL, II, &AC, - &DT) >= 16) { - Type *VTy = - VectorType::get(Builder.getFloatTy(), - cast(II->getType())->getElementCount()); - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(0), - PointerType::getUnqual(VTy)); - Value *Load = Builder.CreateLoad(VTy, Ptr); - return new FPExtInst(Load, II->getType()); - } - break; - case Intrinsic::ppc_qpx_qvlfd: - // Turn PPC QPX qvlfd -> load if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(0), Align(32), DL, II, &AC, - &DT) >= 32) { - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(0), - PointerType::getUnqual(II->getType())); - return new LoadInst(II->getType(), Ptr, "", false, Align(32)); - } - break; - case Intrinsic::ppc_qpx_qvstfs: - // Turn PPC QPX qvstfs -> store if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(1), Align(16), DL, II, &AC, - &DT) >= 16) { - Type *VTy = VectorType::get( - Builder.getFloatTy(), - cast(II->getArgOperand(0)->getType())->getElementCount()); - Value *TOp = Builder.CreateFPTrunc(II->getArgOperand(0), VTy); - Type *OpPtrTy = PointerType::getUnqual(VTy); - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(1), OpPtrTy); - return new StoreInst(TOp, Ptr, false, Align(16)); - } - break; - case Intrinsic::ppc_qpx_qvstfd: - // Turn PPC QPX qvstfd -> store if the pointer is known aligned. - if (getOrEnforceKnownAlignment(II->getArgOperand(1), Align(32), DL, II, &AC, - &DT) >= 32) { - Type *OpPtrTy = - PointerType::getUnqual(II->getArgOperand(0)->getType()); - Value *Ptr = Builder.CreateBitCast(II->getArgOperand(1), OpPtrTy); - return new StoreInst(II->getArgOperand(0), Ptr, false, Align(32)); - } - break; - - case Intrinsic::x86_bmi_bextr_32: - case Intrinsic::x86_bmi_bextr_64: - case Intrinsic::x86_tbm_bextri_u32: - case Intrinsic::x86_tbm_bextri_u64: - // If the RHS is a constant we can try some simplifications. - if (auto *C = dyn_cast(II->getArgOperand(1))) { - uint64_t Shift = C->getZExtValue(); - uint64_t Length = (Shift >> 8) & 0xff; - Shift &= 0xff; - unsigned BitWidth = II->getType()->getIntegerBitWidth(); - // If the length is 0 or the shift is out of range, replace with zero. - if (Length == 0 || Shift >= BitWidth) - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), 0)); - // If the LHS is also a constant, we can completely constant fold this. - if (auto *InC = dyn_cast(II->getArgOperand(0))) { - uint64_t Result = InC->getZExtValue() >> Shift; - if (Length > BitWidth) - Length = BitWidth; - Result &= maskTrailingOnes(Length); - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Result)); - } - // TODO should we turn this into 'and' if shift is 0? Or 'shl' if we - // are only masking bits that a shift already cleared? - } - break; - - case Intrinsic::x86_bmi_bzhi_32: - case Intrinsic::x86_bmi_bzhi_64: - // If the RHS is a constant we can try some simplifications. - if (auto *C = dyn_cast(II->getArgOperand(1))) { - uint64_t Index = C->getZExtValue() & 0xff; - unsigned BitWidth = II->getType()->getIntegerBitWidth(); - if (Index >= BitWidth) - return replaceInstUsesWith(CI, II->getArgOperand(0)); - if (Index == 0) - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), 0)); - // If the LHS is also a constant, we can completely constant fold this. - if (auto *InC = dyn_cast(II->getArgOperand(0))) { - uint64_t Result = InC->getZExtValue(); - Result &= maskTrailingOnes(Index); - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Result)); - } - // TODO should we convert this to an AND if the RHS is constant? - } - break; - case Intrinsic::x86_bmi_pext_32: - case Intrinsic::x86_bmi_pext_64: - if (auto *MaskC = dyn_cast(II->getArgOperand(1))) { - if (MaskC->isNullValue()) - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), 0)); - if (MaskC->isAllOnesValue()) - return replaceInstUsesWith(CI, II->getArgOperand(0)); - - if (auto *SrcC = dyn_cast(II->getArgOperand(0))) { - uint64_t Src = SrcC->getZExtValue(); - uint64_t Mask = MaskC->getZExtValue(); - uint64_t Result = 0; - uint64_t BitToSet = 1; - - while (Mask) { - // Isolate lowest set bit. - uint64_t BitToTest = Mask & -Mask; - if (BitToTest & Src) - Result |= BitToSet; - - BitToSet <<= 1; - // Clear lowest set bit. - Mask &= Mask - 1; - } - - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Result)); - } - } - break; - case Intrinsic::x86_bmi_pdep_32: - case Intrinsic::x86_bmi_pdep_64: - if (auto *MaskC = dyn_cast(II->getArgOperand(1))) { - if (MaskC->isNullValue()) - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), 0)); - if (MaskC->isAllOnesValue()) - return replaceInstUsesWith(CI, II->getArgOperand(0)); - - if (auto *SrcC = dyn_cast(II->getArgOperand(0))) { - uint64_t Src = SrcC->getZExtValue(); - uint64_t Mask = MaskC->getZExtValue(); - uint64_t Result = 0; - uint64_t BitToTest = 1; - - while (Mask) { - // Isolate lowest set bit. - uint64_t BitToSet = Mask & -Mask; - if (BitToTest & Src) - Result |= BitToSet; - - BitToTest <<= 1; - // Clear lowest set bit; - Mask &= Mask - 1; - } - - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Result)); - } - } - break; - - case Intrinsic::x86_sse_cvtss2si: - case Intrinsic::x86_sse_cvtss2si64: - case Intrinsic::x86_sse_cvttss2si: - case Intrinsic::x86_sse_cvttss2si64: - case Intrinsic::x86_sse2_cvtsd2si: - case Intrinsic::x86_sse2_cvtsd2si64: - case Intrinsic::x86_sse2_cvttsd2si: - case Intrinsic::x86_sse2_cvttsd2si64: - case Intrinsic::x86_avx512_vcvtss2si32: - case Intrinsic::x86_avx512_vcvtss2si64: - case Intrinsic::x86_avx512_vcvtss2usi32: - case Intrinsic::x86_avx512_vcvtss2usi64: - case Intrinsic::x86_avx512_vcvtsd2si32: - case Intrinsic::x86_avx512_vcvtsd2si64: - case Intrinsic::x86_avx512_vcvtsd2usi32: - case Intrinsic::x86_avx512_vcvtsd2usi64: - case Intrinsic::x86_avx512_cvttss2si: - case Intrinsic::x86_avx512_cvttss2si64: - case Intrinsic::x86_avx512_cvttss2usi: - case Intrinsic::x86_avx512_cvttss2usi64: - case Intrinsic::x86_avx512_cvttsd2si: - case Intrinsic::x86_avx512_cvttsd2si64: - case Intrinsic::x86_avx512_cvttsd2usi: - case Intrinsic::x86_avx512_cvttsd2usi64: { - // These intrinsics only demand the 0th element of their input vectors. If - // we can simplify the input based on that, do so now. - Value *Arg = II->getArgOperand(0); - unsigned VWidth = cast(Arg->getType())->getNumElements(); - if (Value *V = SimplifyDemandedVectorEltsLow(Arg, VWidth, 1)) - return replaceOperand(*II, 0, V); - break; - } - - case Intrinsic::x86_mmx_pmovmskb: - case Intrinsic::x86_sse_movmsk_ps: - case Intrinsic::x86_sse2_movmsk_pd: - case Intrinsic::x86_sse2_pmovmskb_128: - case Intrinsic::x86_avx_movmsk_pd_256: - case Intrinsic::x86_avx_movmsk_ps_256: - case Intrinsic::x86_avx2_pmovmskb: - if (Value *V = simplifyX86movmsk(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_sse_comieq_ss: - case Intrinsic::x86_sse_comige_ss: - case Intrinsic::x86_sse_comigt_ss: - case Intrinsic::x86_sse_comile_ss: - case Intrinsic::x86_sse_comilt_ss: - case Intrinsic::x86_sse_comineq_ss: - case Intrinsic::x86_sse_ucomieq_ss: - case Intrinsic::x86_sse_ucomige_ss: - case Intrinsic::x86_sse_ucomigt_ss: - case Intrinsic::x86_sse_ucomile_ss: - case Intrinsic::x86_sse_ucomilt_ss: - case Intrinsic::x86_sse_ucomineq_ss: - case Intrinsic::x86_sse2_comieq_sd: - case Intrinsic::x86_sse2_comige_sd: - case Intrinsic::x86_sse2_comigt_sd: - case Intrinsic::x86_sse2_comile_sd: - case Intrinsic::x86_sse2_comilt_sd: - case Intrinsic::x86_sse2_comineq_sd: - case Intrinsic::x86_sse2_ucomieq_sd: - case Intrinsic::x86_sse2_ucomige_sd: - case Intrinsic::x86_sse2_ucomigt_sd: - case Intrinsic::x86_sse2_ucomile_sd: - case Intrinsic::x86_sse2_ucomilt_sd: - case Intrinsic::x86_sse2_ucomineq_sd: - case Intrinsic::x86_avx512_vcomi_ss: - case Intrinsic::x86_avx512_vcomi_sd: - case Intrinsic::x86_avx512_mask_cmp_ss: - case Intrinsic::x86_avx512_mask_cmp_sd: { - // These intrinsics only demand the 0th element of their input vectors. If - // we can simplify the input based on that, do so now. - bool MadeChange = false; - Value *Arg0 = II->getArgOperand(0); - Value *Arg1 = II->getArgOperand(1); - unsigned VWidth = cast(Arg0->getType())->getNumElements(); - if (Value *V = SimplifyDemandedVectorEltsLow(Arg0, VWidth, 1)) { - replaceOperand(*II, 0, V); - MadeChange = true; - } - if (Value *V = SimplifyDemandedVectorEltsLow(Arg1, VWidth, 1)) { - replaceOperand(*II, 1, V); - MadeChange = true; - } - if (MadeChange) - return II; - break; - } - case Intrinsic::x86_avx512_cmp_pd_128: - case Intrinsic::x86_avx512_cmp_pd_256: - case Intrinsic::x86_avx512_cmp_pd_512: - case Intrinsic::x86_avx512_cmp_ps_128: - case Intrinsic::x86_avx512_cmp_ps_256: - case Intrinsic::x86_avx512_cmp_ps_512: { - // Folding cmp(sub(a,b),0) -> cmp(a,b) and cmp(0,sub(a,b)) -> cmp(b,a) - Value *Arg0 = II->getArgOperand(0); - Value *Arg1 = II->getArgOperand(1); - bool Arg0IsZero = match(Arg0, m_PosZeroFP()); - if (Arg0IsZero) - std::swap(Arg0, Arg1); - Value *A, *B; - // This fold requires only the NINF(not +/- inf) since inf minus - // inf is nan. - // NSZ(No Signed Zeros) is not needed because zeros of any sign are - // equal for both compares. - // NNAN is not needed because nans compare the same for both compares. - // The compare intrinsic uses the above assumptions and therefore - // doesn't require additional flags. - if ((match(Arg0, m_OneUse(m_FSub(m_Value(A), m_Value(B)))) && - match(Arg1, m_PosZeroFP()) && isa(Arg0) && - cast(Arg0)->getFastMathFlags().noInfs())) { - if (Arg0IsZero) - std::swap(A, B); - replaceOperand(*II, 0, A); - replaceOperand(*II, 1, B); - return II; - } - break; - } - - case Intrinsic::x86_avx512_add_ps_512: - case Intrinsic::x86_avx512_div_ps_512: - case Intrinsic::x86_avx512_mul_ps_512: - case Intrinsic::x86_avx512_sub_ps_512: - case Intrinsic::x86_avx512_add_pd_512: - case Intrinsic::x86_avx512_div_pd_512: - case Intrinsic::x86_avx512_mul_pd_512: - case Intrinsic::x86_avx512_sub_pd_512: - // If the rounding mode is CUR_DIRECTION(4) we can turn these into regular - // IR operations. - if (auto *R = dyn_cast(II->getArgOperand(2))) { - if (R->getValue() == 4) { - Value *Arg0 = II->getArgOperand(0); - Value *Arg1 = II->getArgOperand(1); - - Value *V; - switch (IID) { - default: llvm_unreachable("Case stmts out of sync!"); - case Intrinsic::x86_avx512_add_ps_512: - case Intrinsic::x86_avx512_add_pd_512: - V = Builder.CreateFAdd(Arg0, Arg1); - break; - case Intrinsic::x86_avx512_sub_ps_512: - case Intrinsic::x86_avx512_sub_pd_512: - V = Builder.CreateFSub(Arg0, Arg1); - break; - case Intrinsic::x86_avx512_mul_ps_512: - case Intrinsic::x86_avx512_mul_pd_512: - V = Builder.CreateFMul(Arg0, Arg1); - break; - case Intrinsic::x86_avx512_div_ps_512: - case Intrinsic::x86_avx512_div_pd_512: - V = Builder.CreateFDiv(Arg0, Arg1); - break; - } - - return replaceInstUsesWith(*II, V); - } - } - break; - - case Intrinsic::x86_avx512_mask_add_ss_round: - case Intrinsic::x86_avx512_mask_div_ss_round: - case Intrinsic::x86_avx512_mask_mul_ss_round: - case Intrinsic::x86_avx512_mask_sub_ss_round: - case Intrinsic::x86_avx512_mask_add_sd_round: - case Intrinsic::x86_avx512_mask_div_sd_round: - case Intrinsic::x86_avx512_mask_mul_sd_round: - case Intrinsic::x86_avx512_mask_sub_sd_round: - // If the rounding mode is CUR_DIRECTION(4) we can turn these into regular - // IR operations. - if (auto *R = dyn_cast(II->getArgOperand(4))) { - if (R->getValue() == 4) { - // Extract the element as scalars. - Value *Arg0 = II->getArgOperand(0); - Value *Arg1 = II->getArgOperand(1); - Value *LHS = Builder.CreateExtractElement(Arg0, (uint64_t)0); - Value *RHS = Builder.CreateExtractElement(Arg1, (uint64_t)0); - - Value *V; - switch (IID) { - default: llvm_unreachable("Case stmts out of sync!"); - case Intrinsic::x86_avx512_mask_add_ss_round: - case Intrinsic::x86_avx512_mask_add_sd_round: - V = Builder.CreateFAdd(LHS, RHS); - break; - case Intrinsic::x86_avx512_mask_sub_ss_round: - case Intrinsic::x86_avx512_mask_sub_sd_round: - V = Builder.CreateFSub(LHS, RHS); - break; - case Intrinsic::x86_avx512_mask_mul_ss_round: - case Intrinsic::x86_avx512_mask_mul_sd_round: - V = Builder.CreateFMul(LHS, RHS); - break; - case Intrinsic::x86_avx512_mask_div_ss_round: - case Intrinsic::x86_avx512_mask_div_sd_round: - V = Builder.CreateFDiv(LHS, RHS); - break; - } - - // Handle the masking aspect of the intrinsic. - Value *Mask = II->getArgOperand(3); - auto *C = dyn_cast(Mask); - // We don't need a select if we know the mask bit is a 1. - if (!C || !C->getValue()[0]) { - // Cast the mask to an i1 vector and then extract the lowest element. - auto *MaskTy = FixedVectorType::get( - Builder.getInt1Ty(), - cast(Mask->getType())->getBitWidth()); - Mask = Builder.CreateBitCast(Mask, MaskTy); - Mask = Builder.CreateExtractElement(Mask, (uint64_t)0); - // Extract the lowest element from the passthru operand. - Value *Passthru = Builder.CreateExtractElement(II->getArgOperand(2), - (uint64_t)0); - V = Builder.CreateSelect(Mask, V, Passthru); - } - - // Insert the result back into the original argument 0. - V = Builder.CreateInsertElement(Arg0, V, (uint64_t)0); - - return replaceInstUsesWith(*II, V); - } - } - break; - - // Constant fold ashr( , Ci ). - // Constant fold lshr( , Ci ). - // Constant fold shl( , Ci ). - case Intrinsic::x86_sse2_psrai_d: - case Intrinsic::x86_sse2_psrai_w: - case Intrinsic::x86_avx2_psrai_d: - case Intrinsic::x86_avx2_psrai_w: - case Intrinsic::x86_avx512_psrai_q_128: - case Intrinsic::x86_avx512_psrai_q_256: - case Intrinsic::x86_avx512_psrai_d_512: - case Intrinsic::x86_avx512_psrai_q_512: - case Intrinsic::x86_avx512_psrai_w_512: - case Intrinsic::x86_sse2_psrli_d: - case Intrinsic::x86_sse2_psrli_q: - case Intrinsic::x86_sse2_psrli_w: - case Intrinsic::x86_avx2_psrli_d: - case Intrinsic::x86_avx2_psrli_q: - case Intrinsic::x86_avx2_psrli_w: - case Intrinsic::x86_avx512_psrli_d_512: - case Intrinsic::x86_avx512_psrli_q_512: - case Intrinsic::x86_avx512_psrli_w_512: - case Intrinsic::x86_sse2_pslli_d: - case Intrinsic::x86_sse2_pslli_q: - case Intrinsic::x86_sse2_pslli_w: - case Intrinsic::x86_avx2_pslli_d: - case Intrinsic::x86_avx2_pslli_q: - case Intrinsic::x86_avx2_pslli_w: - case Intrinsic::x86_avx512_pslli_d_512: - case Intrinsic::x86_avx512_pslli_q_512: - case Intrinsic::x86_avx512_pslli_w_512: - if (Value *V = simplifyX86immShift(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_sse2_psra_d: - case Intrinsic::x86_sse2_psra_w: - case Intrinsic::x86_avx2_psra_d: - case Intrinsic::x86_avx2_psra_w: - case Intrinsic::x86_avx512_psra_q_128: - case Intrinsic::x86_avx512_psra_q_256: - case Intrinsic::x86_avx512_psra_d_512: - case Intrinsic::x86_avx512_psra_q_512: - case Intrinsic::x86_avx512_psra_w_512: - case Intrinsic::x86_sse2_psrl_d: - case Intrinsic::x86_sse2_psrl_q: - case Intrinsic::x86_sse2_psrl_w: - case Intrinsic::x86_avx2_psrl_d: - case Intrinsic::x86_avx2_psrl_q: - case Intrinsic::x86_avx2_psrl_w: - case Intrinsic::x86_avx512_psrl_d_512: - case Intrinsic::x86_avx512_psrl_q_512: - case Intrinsic::x86_avx512_psrl_w_512: - case Intrinsic::x86_sse2_psll_d: - case Intrinsic::x86_sse2_psll_q: - case Intrinsic::x86_sse2_psll_w: - case Intrinsic::x86_avx2_psll_d: - case Intrinsic::x86_avx2_psll_q: - case Intrinsic::x86_avx2_psll_w: - case Intrinsic::x86_avx512_psll_d_512: - case Intrinsic::x86_avx512_psll_q_512: - case Intrinsic::x86_avx512_psll_w_512: { - if (Value *V = simplifyX86immShift(*II, Builder)) - return replaceInstUsesWith(*II, V); - - // SSE2/AVX2 uses only the first 64-bits of the 128-bit vector - // operand to compute the shift amount. - Value *Arg1 = II->getArgOperand(1); - assert(Arg1->getType()->getPrimitiveSizeInBits() == 128 && - "Unexpected packed shift size"); - unsigned VWidth = cast(Arg1->getType())->getNumElements(); - - if (Value *V = SimplifyDemandedVectorEltsLow(Arg1, VWidth, VWidth / 2)) - return replaceOperand(*II, 1, V); - break; - } - - case Intrinsic::x86_avx2_psllv_d: - case Intrinsic::x86_avx2_psllv_d_256: - case Intrinsic::x86_avx2_psllv_q: - case Intrinsic::x86_avx2_psllv_q_256: - case Intrinsic::x86_avx512_psllv_d_512: - case Intrinsic::x86_avx512_psllv_q_512: - case Intrinsic::x86_avx512_psllv_w_128: - case Intrinsic::x86_avx512_psllv_w_256: - case Intrinsic::x86_avx512_psllv_w_512: - case Intrinsic::x86_avx2_psrav_d: - case Intrinsic::x86_avx2_psrav_d_256: - case Intrinsic::x86_avx512_psrav_q_128: - case Intrinsic::x86_avx512_psrav_q_256: - case Intrinsic::x86_avx512_psrav_d_512: - case Intrinsic::x86_avx512_psrav_q_512: - case Intrinsic::x86_avx512_psrav_w_128: - case Intrinsic::x86_avx512_psrav_w_256: - case Intrinsic::x86_avx512_psrav_w_512: - case Intrinsic::x86_avx2_psrlv_d: - case Intrinsic::x86_avx2_psrlv_d_256: - case Intrinsic::x86_avx2_psrlv_q: - case Intrinsic::x86_avx2_psrlv_q_256: - case Intrinsic::x86_avx512_psrlv_d_512: - case Intrinsic::x86_avx512_psrlv_q_512: - case Intrinsic::x86_avx512_psrlv_w_128: - case Intrinsic::x86_avx512_psrlv_w_256: - case Intrinsic::x86_avx512_psrlv_w_512: - if (Value *V = simplifyX86varShift(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_sse2_packssdw_128: - case Intrinsic::x86_sse2_packsswb_128: - case Intrinsic::x86_avx2_packssdw: - case Intrinsic::x86_avx2_packsswb: - case Intrinsic::x86_avx512_packssdw_512: - case Intrinsic::x86_avx512_packsswb_512: - if (Value *V = simplifyX86pack(*II, Builder, true)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_sse2_packuswb_128: - case Intrinsic::x86_sse41_packusdw: - case Intrinsic::x86_avx2_packusdw: - case Intrinsic::x86_avx2_packuswb: - case Intrinsic::x86_avx512_packusdw_512: - case Intrinsic::x86_avx512_packuswb_512: - if (Value *V = simplifyX86pack(*II, Builder, false)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_pclmulqdq: - case Intrinsic::x86_pclmulqdq_256: - case Intrinsic::x86_pclmulqdq_512: { - if (auto *C = dyn_cast(II->getArgOperand(2))) { - unsigned Imm = C->getZExtValue(); - - bool MadeChange = false; - Value *Arg0 = II->getArgOperand(0); - Value *Arg1 = II->getArgOperand(1); - unsigned VWidth = cast(Arg0->getType())->getNumElements(); - - APInt UndefElts1(VWidth, 0); - APInt DemandedElts1 = APInt::getSplat(VWidth, - APInt(2, (Imm & 0x01) ? 2 : 1)); - if (Value *V = SimplifyDemandedVectorElts(Arg0, DemandedElts1, - UndefElts1)) { - replaceOperand(*II, 0, V); - MadeChange = true; - } - - APInt UndefElts2(VWidth, 0); - APInt DemandedElts2 = APInt::getSplat(VWidth, - APInt(2, (Imm & 0x10) ? 2 : 1)); - if (Value *V = SimplifyDemandedVectorElts(Arg1, DemandedElts2, - UndefElts2)) { - replaceOperand(*II, 1, V); - MadeChange = true; - } - - // If either input elements are undef, the result is zero. - if (DemandedElts1.isSubsetOf(UndefElts1) || - DemandedElts2.isSubsetOf(UndefElts2)) - return replaceInstUsesWith(*II, - ConstantAggregateZero::get(II->getType())); - - if (MadeChange) - return II; - } - break; - } - - case Intrinsic::x86_sse41_insertps: - if (Value *V = simplifyX86insertps(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_sse4a_extrq: { - Value *Op0 = II->getArgOperand(0); - Value *Op1 = II->getArgOperand(1); - unsigned VWidth0 = cast(Op0->getType())->getNumElements(); - unsigned VWidth1 = cast(Op1->getType())->getNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth0 == 2 && - VWidth1 == 16 && "Unexpected operand sizes"); - - // See if we're dealing with constant values. - Constant *C1 = dyn_cast(Op1); - ConstantInt *CILength = - C1 ? dyn_cast_or_null(C1->getAggregateElement((unsigned)0)) - : nullptr; - ConstantInt *CIIndex = - C1 ? dyn_cast_or_null(C1->getAggregateElement((unsigned)1)) - : nullptr; - - // Attempt to simplify to a constant, shuffle vector or EXTRQI call. - if (Value *V = simplifyX86extrq(*II, Op0, CILength, CIIndex, Builder)) - return replaceInstUsesWith(*II, V); - - // EXTRQ only uses the lowest 64-bits of the first 128-bit vector - // operands and the lowest 16-bits of the second. - bool MadeChange = false; - if (Value *V = SimplifyDemandedVectorEltsLow(Op0, VWidth0, 1)) { - replaceOperand(*II, 0, V); - MadeChange = true; - } - if (Value *V = SimplifyDemandedVectorEltsLow(Op1, VWidth1, 2)) { - replaceOperand(*II, 1, V); - MadeChange = true; - } - if (MadeChange) - return II; - break; - } - - case Intrinsic::x86_sse4a_extrqi: { - // EXTRQI: Extract Length bits starting from Index. Zero pad the remaining - // bits of the lower 64-bits. The upper 64-bits are undefined. - Value *Op0 = II->getArgOperand(0); - unsigned VWidth = cast(Op0->getType())->getNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && VWidth == 2 && - "Unexpected operand size"); - - // See if we're dealing with constant values. - ConstantInt *CILength = dyn_cast(II->getArgOperand(1)); - ConstantInt *CIIndex = dyn_cast(II->getArgOperand(2)); - - // Attempt to simplify to a constant or shuffle vector. - if (Value *V = simplifyX86extrq(*II, Op0, CILength, CIIndex, Builder)) - return replaceInstUsesWith(*II, V); - - // EXTRQI only uses the lowest 64-bits of the first 128-bit vector - // operand. - if (Value *V = SimplifyDemandedVectorEltsLow(Op0, VWidth, 1)) - return replaceOperand(*II, 0, V); - break; - } - - case Intrinsic::x86_sse4a_insertq: { - Value *Op0 = II->getArgOperand(0); - Value *Op1 = II->getArgOperand(1); - unsigned VWidth = cast(Op0->getType())->getNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth == 2 && - cast(Op1->getType())->getNumElements() == 2 && - "Unexpected operand size"); - - // See if we're dealing with constant values. - Constant *C1 = dyn_cast(Op1); - ConstantInt *CI11 = - C1 ? dyn_cast_or_null(C1->getAggregateElement((unsigned)1)) - : nullptr; - - // Attempt to simplify to a constant, shuffle vector or INSERTQI call. - if (CI11) { - const APInt &V11 = CI11->getValue(); - APInt Len = V11.zextOrTrunc(6); - APInt Idx = V11.lshr(8).zextOrTrunc(6); - if (Value *V = simplifyX86insertq(*II, Op0, Op1, Len, Idx, Builder)) - return replaceInstUsesWith(*II, V); - } - - // INSERTQ only uses the lowest 64-bits of the first 128-bit vector - // operand. - if (Value *V = SimplifyDemandedVectorEltsLow(Op0, VWidth, 1)) - return replaceOperand(*II, 0, V); - break; - } - - case Intrinsic::x86_sse4a_insertqi: { - // INSERTQI: Extract lowest Length bits from lower half of second source and - // insert over first source starting at Index bit. The upper 64-bits are - // undefined. - Value *Op0 = II->getArgOperand(0); - Value *Op1 = II->getArgOperand(1); - unsigned VWidth0 = cast(Op0->getType())->getNumElements(); - unsigned VWidth1 = cast(Op1->getType())->getNumElements(); - assert(Op0->getType()->getPrimitiveSizeInBits() == 128 && - Op1->getType()->getPrimitiveSizeInBits() == 128 && VWidth0 == 2 && - VWidth1 == 2 && "Unexpected operand sizes"); - - // See if we're dealing with constant values. - ConstantInt *CILength = dyn_cast(II->getArgOperand(2)); - ConstantInt *CIIndex = dyn_cast(II->getArgOperand(3)); - - // Attempt to simplify to a constant or shuffle vector. - if (CILength && CIIndex) { - APInt Len = CILength->getValue().zextOrTrunc(6); - APInt Idx = CIIndex->getValue().zextOrTrunc(6); - if (Value *V = simplifyX86insertq(*II, Op0, Op1, Len, Idx, Builder)) - return replaceInstUsesWith(*II, V); - } - - // INSERTQI only uses the lowest 64-bits of the first two 128-bit vector - // operands. - bool MadeChange = false; - if (Value *V = SimplifyDemandedVectorEltsLow(Op0, VWidth0, 1)) { - replaceOperand(*II, 0, V); - MadeChange = true; - } - if (Value *V = SimplifyDemandedVectorEltsLow(Op1, VWidth1, 1)) { - replaceOperand(*II, 1, V); - MadeChange = true; - } - if (MadeChange) - return II; - break; - } - - case Intrinsic::x86_sse41_pblendvb: - case Intrinsic::x86_sse41_blendvps: - case Intrinsic::x86_sse41_blendvpd: - case Intrinsic::x86_avx_blendv_ps_256: - case Intrinsic::x86_avx_blendv_pd_256: - case Intrinsic::x86_avx2_pblendvb: { - // fold (blend A, A, Mask) -> A - Value *Op0 = II->getArgOperand(0); - Value *Op1 = II->getArgOperand(1); - Value *Mask = II->getArgOperand(2); - if (Op0 == Op1) - return replaceInstUsesWith(CI, Op0); - - // Zero Mask - select 1st argument. - if (isa(Mask)) - return replaceInstUsesWith(CI, Op0); - - // Constant Mask - select 1st/2nd argument lane based on top bit of mask. - if (auto *ConstantMask = dyn_cast(Mask)) { - Constant *NewSelector = getNegativeIsTrueBoolVec(ConstantMask); - return SelectInst::Create(NewSelector, Op1, Op0, "blendv"); - } - - // Convert to a vector select if we can bypass casts and find a boolean - // vector condition value. - Value *BoolVec; - Mask = peekThroughBitcast(Mask); - if (match(Mask, m_SExt(m_Value(BoolVec))) && - BoolVec->getType()->isVectorTy() && - BoolVec->getType()->getScalarSizeInBits() == 1) { - assert(Mask->getType()->getPrimitiveSizeInBits() == - II->getType()->getPrimitiveSizeInBits() && - "Not expecting mask and operands with different sizes"); - - unsigned NumMaskElts = - cast(Mask->getType())->getNumElements(); - unsigned NumOperandElts = - cast(II->getType())->getNumElements(); - if (NumMaskElts == NumOperandElts) - return SelectInst::Create(BoolVec, Op1, Op0); - - // If the mask has less elements than the operands, each mask bit maps to - // multiple elements of the operands. Bitcast back and forth. - if (NumMaskElts < NumOperandElts) { - Value *CastOp0 = Builder.CreateBitCast(Op0, Mask->getType()); - Value *CastOp1 = Builder.CreateBitCast(Op1, Mask->getType()); - Value *Sel = Builder.CreateSelect(BoolVec, CastOp1, CastOp0); - return new BitCastInst(Sel, II->getType()); - } - } - - break; - } - - case Intrinsic::x86_ssse3_pshuf_b_128: - case Intrinsic::x86_avx2_pshuf_b: - case Intrinsic::x86_avx512_pshuf_b_512: - if (Value *V = simplifyX86pshufb(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_avx_vpermilvar_ps: - case Intrinsic::x86_avx_vpermilvar_ps_256: - case Intrinsic::x86_avx512_vpermilvar_ps_512: - case Intrinsic::x86_avx_vpermilvar_pd: - case Intrinsic::x86_avx_vpermilvar_pd_256: - case Intrinsic::x86_avx512_vpermilvar_pd_512: - if (Value *V = simplifyX86vpermilvar(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_avx2_permd: - case Intrinsic::x86_avx2_permps: - case Intrinsic::x86_avx512_permvar_df_256: - case Intrinsic::x86_avx512_permvar_df_512: - case Intrinsic::x86_avx512_permvar_di_256: - case Intrinsic::x86_avx512_permvar_di_512: - case Intrinsic::x86_avx512_permvar_hi_128: - case Intrinsic::x86_avx512_permvar_hi_256: - case Intrinsic::x86_avx512_permvar_hi_512: - case Intrinsic::x86_avx512_permvar_qi_128: - case Intrinsic::x86_avx512_permvar_qi_256: - case Intrinsic::x86_avx512_permvar_qi_512: - case Intrinsic::x86_avx512_permvar_sf_512: - case Intrinsic::x86_avx512_permvar_si_512: - if (Value *V = simplifyX86vpermv(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::x86_avx_maskload_ps: - case Intrinsic::x86_avx_maskload_pd: - case Intrinsic::x86_avx_maskload_ps_256: - case Intrinsic::x86_avx_maskload_pd_256: - case Intrinsic::x86_avx2_maskload_d: - case Intrinsic::x86_avx2_maskload_q: - case Intrinsic::x86_avx2_maskload_d_256: - case Intrinsic::x86_avx2_maskload_q_256: - if (Instruction *I = simplifyX86MaskedLoad(*II, *this)) - return I; - break; - - case Intrinsic::x86_sse2_maskmov_dqu: - case Intrinsic::x86_avx_maskstore_ps: - case Intrinsic::x86_avx_maskstore_pd: - case Intrinsic::x86_avx_maskstore_ps_256: - case Intrinsic::x86_avx_maskstore_pd_256: - case Intrinsic::x86_avx2_maskstore_d: - case Intrinsic::x86_avx2_maskstore_q: - case Intrinsic::x86_avx2_maskstore_d_256: - case Intrinsic::x86_avx2_maskstore_q_256: - if (simplifyX86MaskedStore(*II, *this)) - return nullptr; - break; - - case Intrinsic::x86_addcarry_32: - case Intrinsic::x86_addcarry_64: - if (Value *V = simplifyX86addcarry(*II, Builder)) - return replaceInstUsesWith(*II, V); - break; - - case Intrinsic::ppc_altivec_vperm: - // Turn vperm(V1,V2,mask) -> shuffle(V1,V2,mask) if mask is a constant. - // Note that ppc_altivec_vperm has a big-endian bias, so when creating - // a vectorshuffle for little endian, we must undo the transformation - // performed on vec_perm in altivec.h. That is, we must complement - // the permutation mask with respect to 31 and reverse the order of - // V1 and V2. - if (Constant *Mask = dyn_cast(II->getArgOperand(2))) { - assert(cast(Mask->getType())->getNumElements() == 16 && - "Bad type for intrinsic!"); - - // Check that all of the elements are integer constants or undefs. - bool AllEltsOk = true; - for (unsigned i = 0; i != 16; ++i) { - Constant *Elt = Mask->getAggregateElement(i); - if (!Elt || !(isa(Elt) || isa(Elt))) { - AllEltsOk = false; - break; - } - } - - if (AllEltsOk) { - // Cast the input vectors to byte vectors. - Value *Op0 = Builder.CreateBitCast(II->getArgOperand(0), - Mask->getType()); - Value *Op1 = Builder.CreateBitCast(II->getArgOperand(1), - Mask->getType()); - Value *Result = UndefValue::get(Op0->getType()); - - // Only extract each element once. - Value *ExtractedElts[32]; - memset(ExtractedElts, 0, sizeof(ExtractedElts)); - - for (unsigned i = 0; i != 16; ++i) { - if (isa(Mask->getAggregateElement(i))) - continue; - unsigned Idx = - cast(Mask->getAggregateElement(i))->getZExtValue(); - Idx &= 31; // Match the hardware behavior. - if (DL.isLittleEndian()) - Idx = 31 - Idx; - - if (!ExtractedElts[Idx]) { - Value *Op0ToUse = (DL.isLittleEndian()) ? Op1 : Op0; - Value *Op1ToUse = (DL.isLittleEndian()) ? Op0 : Op1; - ExtractedElts[Idx] = - Builder.CreateExtractElement(Idx < 16 ? Op0ToUse : Op1ToUse, - Builder.getInt32(Idx&15)); - } - - // Insert this value into the result vector. - Result = Builder.CreateInsertElement(Result, ExtractedElts[Idx], - Builder.getInt32(i)); - } - return CastInst::Create(Instruction::BitCast, Result, CI.getType()); - } - } - break; - - case Intrinsic::arm_neon_vld1: { - Align MemAlign = getKnownAlignment(II->getArgOperand(0), DL, II, &AC, &DT); - if (Value *V = simplifyNeonVld1(*II, MemAlign.value(), Builder)) - return replaceInstUsesWith(*II, V); - break; - } - - case Intrinsic::arm_neon_vld2: - case Intrinsic::arm_neon_vld3: - case Intrinsic::arm_neon_vld4: - case Intrinsic::arm_neon_vld2lane: - case Intrinsic::arm_neon_vld3lane: - case Intrinsic::arm_neon_vld4lane: - case Intrinsic::arm_neon_vst1: - case Intrinsic::arm_neon_vst2: - case Intrinsic::arm_neon_vst3: - case Intrinsic::arm_neon_vst4: - case Intrinsic::arm_neon_vst2lane: - case Intrinsic::arm_neon_vst3lane: - case Intrinsic::arm_neon_vst4lane: { - Align MemAlign = getKnownAlignment(II->getArgOperand(0), DL, II, &AC, &DT); - unsigned AlignArg = II->getNumArgOperands() - 1; - Value *AlignArgOp = II->getArgOperand(AlignArg); - MaybeAlign Align = cast(AlignArgOp)->getMaybeAlignValue(); - if (Align && *Align < MemAlign) - return replaceOperand(*II, AlignArg, - ConstantInt::get(Type::getInt32Ty(II->getContext()), - MemAlign.value(), false)); + Instruction *FNeg = UnaryOperator::CreateFNeg(NewSin); + FNeg->copyFastMathFlags(II); + return FNeg; + } break; } @@ -3453,690 +1408,6 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { } break; } - case Intrinsic::arm_mve_pred_i2v: { - Value *Arg = II->getArgOperand(0); - Value *ArgArg; - if (match(Arg, m_Intrinsic(m_Value(ArgArg))) && - II->getType() == ArgArg->getType()) - return replaceInstUsesWith(*II, ArgArg); - Constant *XorMask; - if (match(Arg, - m_Xor(m_Intrinsic(m_Value(ArgArg)), - m_Constant(XorMask))) && - II->getType() == ArgArg->getType()) { - if (auto *CI = dyn_cast(XorMask)) { - if (CI->getValue().trunc(16).isAllOnesValue()) { - auto TrueVector = Builder.CreateVectorSplat( - cast(II->getType())->getNumElements(), - Builder.getTrue()); - return BinaryOperator::Create(Instruction::Xor, ArgArg, TrueVector); - } - } - } - KnownBits ScalarKnown(32); - if (SimplifyDemandedBits(II, 0, APInt::getLowBitsSet(32, 16), - ScalarKnown, 0)) - return II; - break; - } - case Intrinsic::arm_mve_pred_v2i: { - Value *Arg = II->getArgOperand(0); - Value *ArgArg; - if (match(Arg, m_Intrinsic(m_Value(ArgArg)))) - return replaceInstUsesWith(*II, ArgArg); - if (!II->getMetadata(LLVMContext::MD_range)) { - Type *IntTy32 = Type::getInt32Ty(II->getContext()); - Metadata *M[] = { - ConstantAsMetadata::get(ConstantInt::get(IntTy32, 0)), - ConstantAsMetadata::get(ConstantInt::get(IntTy32, 0xFFFF)) - }; - II->setMetadata(LLVMContext::MD_range, MDNode::get(II->getContext(), M)); - return II; - } - break; - } - case Intrinsic::arm_mve_vadc: - case Intrinsic::arm_mve_vadc_predicated: { - unsigned CarryOp = - (II->getIntrinsicID() == Intrinsic::arm_mve_vadc_predicated) ? 3 : 2; - assert(II->getArgOperand(CarryOp)->getType()->getScalarSizeInBits() == 32 && - "Bad type for intrinsic!"); - - KnownBits CarryKnown(32); - if (SimplifyDemandedBits(II, CarryOp, APInt::getOneBitSet(32, 29), - CarryKnown)) - return II; - break; - } - case Intrinsic::amdgcn_rcp: { - Value *Src = II->getArgOperand(0); - - // TODO: Move to ConstantFolding/InstSimplify? - if (isa(Src)) { - Type *Ty = II->getType(); - auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics())); - return replaceInstUsesWith(CI, QNaN); - } - - if (II->isStrictFP()) - break; - - if (const ConstantFP *C = dyn_cast(Src)) { - const APFloat &ArgVal = C->getValueAPF(); - APFloat Val(ArgVal.getSemantics(), 1); - Val.divide(ArgVal, APFloat::rmNearestTiesToEven); - - // This is more precise than the instruction may give. - // - // TODO: The instruction always flushes denormal results (except for f16), - // should this also? - return replaceInstUsesWith(CI, ConstantFP::get(II->getContext(), Val)); - } - - break; - } - case Intrinsic::amdgcn_rsq: { - Value *Src = II->getArgOperand(0); - - // TODO: Move to ConstantFolding/InstSimplify? - if (isa(Src)) { - Type *Ty = II->getType(); - auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics())); - return replaceInstUsesWith(CI, QNaN); - } - - break; - } - case Intrinsic::amdgcn_frexp_mant: - case Intrinsic::amdgcn_frexp_exp: { - Value *Src = II->getArgOperand(0); - if (const ConstantFP *C = dyn_cast(Src)) { - int Exp; - APFloat Significand = frexp(C->getValueAPF(), Exp, - APFloat::rmNearestTiesToEven); - - if (IID == Intrinsic::amdgcn_frexp_mant) { - return replaceInstUsesWith(CI, ConstantFP::get(II->getContext(), - Significand)); - } - - // Match instruction special case behavior. - if (Exp == APFloat::IEK_NaN || Exp == APFloat::IEK_Inf) - Exp = 0; - - return replaceInstUsesWith(CI, ConstantInt::get(II->getType(), Exp)); - } - - if (isa(Src)) - return replaceInstUsesWith(CI, UndefValue::get(II->getType())); - - break; - } - case Intrinsic::amdgcn_class: { - enum { - S_NAN = 1 << 0, // Signaling NaN - Q_NAN = 1 << 1, // Quiet NaN - N_INFINITY = 1 << 2, // Negative infinity - N_NORMAL = 1 << 3, // Negative normal - N_SUBNORMAL = 1 << 4, // Negative subnormal - N_ZERO = 1 << 5, // Negative zero - P_ZERO = 1 << 6, // Positive zero - P_SUBNORMAL = 1 << 7, // Positive subnormal - P_NORMAL = 1 << 8, // Positive normal - P_INFINITY = 1 << 9 // Positive infinity - }; - - const uint32_t FullMask = S_NAN | Q_NAN | N_INFINITY | N_NORMAL | - N_SUBNORMAL | N_ZERO | P_ZERO | P_SUBNORMAL | P_NORMAL | P_INFINITY; - - Value *Src0 = II->getArgOperand(0); - Value *Src1 = II->getArgOperand(1); - const ConstantInt *CMask = dyn_cast(Src1); - if (!CMask) { - if (isa(Src0)) - return replaceInstUsesWith(*II, UndefValue::get(II->getType())); - - if (isa(Src1)) - return replaceInstUsesWith(*II, ConstantInt::get(II->getType(), false)); - break; - } - - uint32_t Mask = CMask->getZExtValue(); - - // If all tests are made, it doesn't matter what the value is. - if ((Mask & FullMask) == FullMask) - return replaceInstUsesWith(*II, ConstantInt::get(II->getType(), true)); - - if ((Mask & FullMask) == 0) - return replaceInstUsesWith(*II, ConstantInt::get(II->getType(), false)); - - if (Mask == (S_NAN | Q_NAN)) { - // Equivalent of isnan. Replace with standard fcmp. - Value *FCmp = Builder.CreateFCmpUNO(Src0, Src0); - FCmp->takeName(II); - return replaceInstUsesWith(*II, FCmp); - } - - if (Mask == (N_ZERO | P_ZERO)) { - // Equivalent of == 0. - Value *FCmp = Builder.CreateFCmpOEQ( - Src0, ConstantFP::get(Src0->getType(), 0.0)); - - FCmp->takeName(II); - return replaceInstUsesWith(*II, FCmp); - } - - // fp_class (nnan x), qnan|snan|other -> fp_class (nnan x), other - if (((Mask & S_NAN) || (Mask & Q_NAN)) && isKnownNeverNaN(Src0, &TLI)) - return replaceOperand(*II, 1, ConstantInt::get(Src1->getType(), - Mask & ~(S_NAN | Q_NAN))); - - const ConstantFP *CVal = dyn_cast(Src0); - if (!CVal) { - if (isa(Src0)) - return replaceInstUsesWith(*II, UndefValue::get(II->getType())); - - // Clamp mask to used bits - if ((Mask & FullMask) != Mask) { - CallInst *NewCall = Builder.CreateCall(II->getCalledFunction(), - { Src0, ConstantInt::get(Src1->getType(), Mask & FullMask) } - ); - - NewCall->takeName(II); - return replaceInstUsesWith(*II, NewCall); - } - - break; - } - - const APFloat &Val = CVal->getValueAPF(); - - bool Result = - ((Mask & S_NAN) && Val.isNaN() && Val.isSignaling()) || - ((Mask & Q_NAN) && Val.isNaN() && !Val.isSignaling()) || - ((Mask & N_INFINITY) && Val.isInfinity() && Val.isNegative()) || - ((Mask & N_NORMAL) && Val.isNormal() && Val.isNegative()) || - ((Mask & N_SUBNORMAL) && Val.isDenormal() && Val.isNegative()) || - ((Mask & N_ZERO) && Val.isZero() && Val.isNegative()) || - ((Mask & P_ZERO) && Val.isZero() && !Val.isNegative()) || - ((Mask & P_SUBNORMAL) && Val.isDenormal() && !Val.isNegative()) || - ((Mask & P_NORMAL) && Val.isNormal() && !Val.isNegative()) || - ((Mask & P_INFINITY) && Val.isInfinity() && !Val.isNegative()); - - return replaceInstUsesWith(*II, ConstantInt::get(II->getType(), Result)); - } - case Intrinsic::amdgcn_cvt_pkrtz: { - Value *Src0 = II->getArgOperand(0); - Value *Src1 = II->getArgOperand(1); - if (const ConstantFP *C0 = dyn_cast(Src0)) { - if (const ConstantFP *C1 = dyn_cast(Src1)) { - const fltSemantics &HalfSem - = II->getType()->getScalarType()->getFltSemantics(); - bool LosesInfo; - APFloat Val0 = C0->getValueAPF(); - APFloat Val1 = C1->getValueAPF(); - Val0.convert(HalfSem, APFloat::rmTowardZero, &LosesInfo); - Val1.convert(HalfSem, APFloat::rmTowardZero, &LosesInfo); - - Constant *Folded = ConstantVector::get({ - ConstantFP::get(II->getContext(), Val0), - ConstantFP::get(II->getContext(), Val1) }); - return replaceInstUsesWith(*II, Folded); - } - } - - if (isa(Src0) && isa(Src1)) - return replaceInstUsesWith(*II, UndefValue::get(II->getType())); - - break; - } - case Intrinsic::amdgcn_cvt_pknorm_i16: - case Intrinsic::amdgcn_cvt_pknorm_u16: - case Intrinsic::amdgcn_cvt_pk_i16: - case Intrinsic::amdgcn_cvt_pk_u16: { - Value *Src0 = II->getArgOperand(0); - Value *Src1 = II->getArgOperand(1); - - if (isa(Src0) && isa(Src1)) - return replaceInstUsesWith(*II, UndefValue::get(II->getType())); - - break; - } - case Intrinsic::amdgcn_ubfe: - case Intrinsic::amdgcn_sbfe: { - // Decompose simple cases into standard shifts. - Value *Src = II->getArgOperand(0); - if (isa(Src)) - return replaceInstUsesWith(*II, Src); - - unsigned Width; - Type *Ty = II->getType(); - unsigned IntSize = Ty->getIntegerBitWidth(); - - ConstantInt *CWidth = dyn_cast(II->getArgOperand(2)); - if (CWidth) { - Width = CWidth->getZExtValue(); - if ((Width & (IntSize - 1)) == 0) - return replaceInstUsesWith(*II, ConstantInt::getNullValue(Ty)); - - // Hardware ignores high bits, so remove those. - if (Width >= IntSize) - return replaceOperand(*II, 2, ConstantInt::get(CWidth->getType(), - Width & (IntSize - 1))); - } - - unsigned Offset; - ConstantInt *COffset = dyn_cast(II->getArgOperand(1)); - if (COffset) { - Offset = COffset->getZExtValue(); - if (Offset >= IntSize) - return replaceOperand(*II, 1, ConstantInt::get(COffset->getType(), - Offset & (IntSize - 1))); - } - - bool Signed = IID == Intrinsic::amdgcn_sbfe; - - if (!CWidth || !COffset) - break; - - // The case of Width == 0 is handled above, which makes this tranformation - // safe. If Width == 0, then the ashr and lshr instructions become poison - // value since the shift amount would be equal to the bit size. - assert(Width != 0); - - // TODO: This allows folding to undef when the hardware has specific - // behavior? - if (Offset + Width < IntSize) { - Value *Shl = Builder.CreateShl(Src, IntSize - Offset - Width); - Value *RightShift = Signed ? Builder.CreateAShr(Shl, IntSize - Width) - : Builder.CreateLShr(Shl, IntSize - Width); - RightShift->takeName(II); - return replaceInstUsesWith(*II, RightShift); - } - - Value *RightShift = Signed ? Builder.CreateAShr(Src, Offset) - : Builder.CreateLShr(Src, Offset); - - RightShift->takeName(II); - return replaceInstUsesWith(*II, RightShift); - } - case Intrinsic::amdgcn_exp: - case Intrinsic::amdgcn_exp_compr: { - ConstantInt *En = cast(II->getArgOperand(1)); - unsigned EnBits = En->getZExtValue(); - if (EnBits == 0xf) - break; // All inputs enabled. - - bool IsCompr = IID == Intrinsic::amdgcn_exp_compr; - bool Changed = false; - for (int I = 0; I < (IsCompr ? 2 : 4); ++I) { - if ((!IsCompr && (EnBits & (1 << I)) == 0) || - (IsCompr && ((EnBits & (0x3 << (2 * I))) == 0))) { - Value *Src = II->getArgOperand(I + 2); - if (!isa(Src)) { - replaceOperand(*II, I + 2, UndefValue::get(Src->getType())); - Changed = true; - } - } - } - - if (Changed) - return II; - - break; - } - case Intrinsic::amdgcn_fmed3: { - // Note this does not preserve proper sNaN behavior if IEEE-mode is enabled - // for the shader. - - Value *Src0 = II->getArgOperand(0); - Value *Src1 = II->getArgOperand(1); - Value *Src2 = II->getArgOperand(2); - - // Checking for NaN before canonicalization provides better fidelity when - // mapping other operations onto fmed3 since the order of operands is - // unchanged. - CallInst *NewCall = nullptr; - if (match(Src0, m_NaN()) || isa(Src0)) { - NewCall = Builder.CreateMinNum(Src1, Src2); - } else if (match(Src1, m_NaN()) || isa(Src1)) { - NewCall = Builder.CreateMinNum(Src0, Src2); - } else if (match(Src2, m_NaN()) || isa(Src2)) { - NewCall = Builder.CreateMaxNum(Src0, Src1); - } - - if (NewCall) { - NewCall->copyFastMathFlags(II); - NewCall->takeName(II); - return replaceInstUsesWith(*II, NewCall); - } - - bool Swap = false; - // Canonicalize constants to RHS operands. - // - // fmed3(c0, x, c1) -> fmed3(x, c0, c1) - if (isa(Src0) && !isa(Src1)) { - std::swap(Src0, Src1); - Swap = true; - } - - if (isa(Src1) && !isa(Src2)) { - std::swap(Src1, Src2); - Swap = true; - } - - if (isa(Src0) && !isa(Src1)) { - std::swap(Src0, Src1); - Swap = true; - } - - if (Swap) { - II->setArgOperand(0, Src0); - II->setArgOperand(1, Src1); - II->setArgOperand(2, Src2); - return II; - } - - if (const ConstantFP *C0 = dyn_cast(Src0)) { - if (const ConstantFP *C1 = dyn_cast(Src1)) { - if (const ConstantFP *C2 = dyn_cast(Src2)) { - APFloat Result = fmed3AMDGCN(C0->getValueAPF(), C1->getValueAPF(), - C2->getValueAPF()); - return replaceInstUsesWith(*II, - ConstantFP::get(Builder.getContext(), Result)); - } - } - } - - break; - } - case Intrinsic::amdgcn_icmp: - case Intrinsic::amdgcn_fcmp: { - const ConstantInt *CC = cast(II->getArgOperand(2)); - // Guard against invalid arguments. - int64_t CCVal = CC->getZExtValue(); - bool IsInteger = IID == Intrinsic::amdgcn_icmp; - if ((IsInteger && (CCVal < CmpInst::FIRST_ICMP_PREDICATE || - CCVal > CmpInst::LAST_ICMP_PREDICATE)) || - (!IsInteger && (CCVal < CmpInst::FIRST_FCMP_PREDICATE || - CCVal > CmpInst::LAST_FCMP_PREDICATE))) - break; - - Value *Src0 = II->getArgOperand(0); - Value *Src1 = II->getArgOperand(1); - - if (auto *CSrc0 = dyn_cast(Src0)) { - if (auto *CSrc1 = dyn_cast(Src1)) { - Constant *CCmp = ConstantExpr::getCompare(CCVal, CSrc0, CSrc1); - if (CCmp->isNullValue()) { - return replaceInstUsesWith( - *II, ConstantExpr::getSExt(CCmp, II->getType())); - } - - // The result of V_ICMP/V_FCMP assembly instructions (which this - // intrinsic exposes) is one bit per thread, masked with the EXEC - // register (which contains the bitmask of live threads). So a - // comparison that always returns true is the same as a read of the - // EXEC register. - Function *NewF = Intrinsic::getDeclaration( - II->getModule(), Intrinsic::read_register, II->getType()); - Metadata *MDArgs[] = {MDString::get(II->getContext(), "exec")}; - MDNode *MD = MDNode::get(II->getContext(), MDArgs); - Value *Args[] = {MetadataAsValue::get(II->getContext(), MD)}; - CallInst *NewCall = Builder.CreateCall(NewF, Args); - NewCall->addAttribute(AttributeList::FunctionIndex, - Attribute::Convergent); - NewCall->takeName(II); - return replaceInstUsesWith(*II, NewCall); - } - - // Canonicalize constants to RHS. - CmpInst::Predicate SwapPred - = CmpInst::getSwappedPredicate(static_cast(CCVal)); - II->setArgOperand(0, Src1); - II->setArgOperand(1, Src0); - II->setArgOperand(2, ConstantInt::get(CC->getType(), - static_cast(SwapPred))); - return II; - } - - if (CCVal != CmpInst::ICMP_EQ && CCVal != CmpInst::ICMP_NE) - break; - - // Canonicalize compare eq with true value to compare != 0 - // llvm.amdgcn.icmp(zext (i1 x), 1, eq) - // -> llvm.amdgcn.icmp(zext (i1 x), 0, ne) - // llvm.amdgcn.icmp(sext (i1 x), -1, eq) - // -> llvm.amdgcn.icmp(sext (i1 x), 0, ne) - Value *ExtSrc; - if (CCVal == CmpInst::ICMP_EQ && - ((match(Src1, m_One()) && match(Src0, m_ZExt(m_Value(ExtSrc)))) || - (match(Src1, m_AllOnes()) && match(Src0, m_SExt(m_Value(ExtSrc))))) && - ExtSrc->getType()->isIntegerTy(1)) { - replaceOperand(*II, 1, ConstantInt::getNullValue(Src1->getType())); - replaceOperand(*II, 2, ConstantInt::get(CC->getType(), CmpInst::ICMP_NE)); - return II; - } - - CmpInst::Predicate SrcPred; - Value *SrcLHS; - Value *SrcRHS; - - // Fold compare eq/ne with 0 from a compare result as the predicate to the - // intrinsic. The typical use is a wave vote function in the library, which - // will be fed from a user code condition compared with 0. Fold in the - // redundant compare. - - // llvm.amdgcn.icmp([sz]ext ([if]cmp pred a, b), 0, ne) - // -> llvm.amdgcn.[if]cmp(a, b, pred) - // - // llvm.amdgcn.icmp([sz]ext ([if]cmp pred a, b), 0, eq) - // -> llvm.amdgcn.[if]cmp(a, b, inv pred) - if (match(Src1, m_Zero()) && - match(Src0, - m_ZExtOrSExt(m_Cmp(SrcPred, m_Value(SrcLHS), m_Value(SrcRHS))))) { - if (CCVal == CmpInst::ICMP_EQ) - SrcPred = CmpInst::getInversePredicate(SrcPred); - - Intrinsic::ID NewIID = CmpInst::isFPPredicate(SrcPred) ? - Intrinsic::amdgcn_fcmp : Intrinsic::amdgcn_icmp; - - Type *Ty = SrcLHS->getType(); - if (auto *CmpType = dyn_cast(Ty)) { - // Promote to next legal integer type. - unsigned Width = CmpType->getBitWidth(); - unsigned NewWidth = Width; - - // Don't do anything for i1 comparisons. - if (Width == 1) - break; - - if (Width <= 16) - NewWidth = 16; - else if (Width <= 32) - NewWidth = 32; - else if (Width <= 64) - NewWidth = 64; - else if (Width > 64) - break; // Can't handle this. - - if (Width != NewWidth) { - IntegerType *CmpTy = Builder.getIntNTy(NewWidth); - if (CmpInst::isSigned(SrcPred)) { - SrcLHS = Builder.CreateSExt(SrcLHS, CmpTy); - SrcRHS = Builder.CreateSExt(SrcRHS, CmpTy); - } else { - SrcLHS = Builder.CreateZExt(SrcLHS, CmpTy); - SrcRHS = Builder.CreateZExt(SrcRHS, CmpTy); - } - } - } else if (!Ty->isFloatTy() && !Ty->isDoubleTy() && !Ty->isHalfTy()) - break; - - Function *NewF = - Intrinsic::getDeclaration(II->getModule(), NewIID, - { II->getType(), - SrcLHS->getType() }); - Value *Args[] = { SrcLHS, SrcRHS, - ConstantInt::get(CC->getType(), SrcPred) }; - CallInst *NewCall = Builder.CreateCall(NewF, Args); - NewCall->takeName(II); - return replaceInstUsesWith(*II, NewCall); - } - - break; - } - case Intrinsic::amdgcn_ballot: { - if (auto *Src = dyn_cast(II->getArgOperand(0))) { - if (Src->isZero()) { - // amdgcn.ballot(i1 0) is zero. - return replaceInstUsesWith(*II, Constant::getNullValue(II->getType())); - } - - if (Src->isOne()) { - // amdgcn.ballot(i1 1) is exec. - const char *RegName = "exec"; - if (II->getType()->isIntegerTy(32)) - RegName = "exec_lo"; - else if (!II->getType()->isIntegerTy(64)) - break; - - Function *NewF = Intrinsic::getDeclaration( - II->getModule(), Intrinsic::read_register, II->getType()); - Metadata *MDArgs[] = {MDString::get(II->getContext(), RegName)}; - MDNode *MD = MDNode::get(II->getContext(), MDArgs); - Value *Args[] = {MetadataAsValue::get(II->getContext(), MD)}; - CallInst *NewCall = Builder.CreateCall(NewF, Args); - NewCall->addAttribute(AttributeList::FunctionIndex, - Attribute::Convergent); - NewCall->takeName(II); - return replaceInstUsesWith(*II, NewCall); - } - } - break; - } - case Intrinsic::amdgcn_wqm_vote: { - // wqm_vote is identity when the argument is constant. - if (!isa(II->getArgOperand(0))) - break; - - return replaceInstUsesWith(*II, II->getArgOperand(0)); - } - case Intrinsic::amdgcn_kill: { - const ConstantInt *C = dyn_cast(II->getArgOperand(0)); - if (!C || !C->getZExtValue()) - break; - - // amdgcn.kill(i1 1) is a no-op - return eraseInstFromFunction(CI); - } - case Intrinsic::amdgcn_update_dpp: { - Value *Old = II->getArgOperand(0); - - auto BC = cast(II->getArgOperand(5)); - auto RM = cast(II->getArgOperand(3)); - auto BM = cast(II->getArgOperand(4)); - if (BC->isZeroValue() || - RM->getZExtValue() != 0xF || - BM->getZExtValue() != 0xF || - isa(Old)) - break; - - // If bound_ctrl = 1, row mask = bank mask = 0xf we can omit old value. - return replaceOperand(*II, 0, UndefValue::get(Old->getType())); - } - case Intrinsic::amdgcn_permlane16: - case Intrinsic::amdgcn_permlanex16: { - // Discard vdst_in if it's not going to be read. - Value *VDstIn = II->getArgOperand(0); - if (isa(VDstIn)) - break; - - ConstantInt *FetchInvalid = cast(II->getArgOperand(4)); - ConstantInt *BoundCtrl = cast(II->getArgOperand(5)); - if (!FetchInvalid->getZExtValue() && !BoundCtrl->getZExtValue()) - break; - - return replaceOperand(*II, 0, UndefValue::get(VDstIn->getType())); - } - case Intrinsic::amdgcn_readfirstlane: - case Intrinsic::amdgcn_readlane: { - // A constant value is trivially uniform. - if (Constant *C = dyn_cast(II->getArgOperand(0))) - return replaceInstUsesWith(*II, C); - - // The rest of these may not be safe if the exec may not be the same between - // the def and use. - Value *Src = II->getArgOperand(0); - Instruction *SrcInst = dyn_cast(Src); - if (SrcInst && SrcInst->getParent() != II->getParent()) - break; - - // readfirstlane (readfirstlane x) -> readfirstlane x - // readlane (readfirstlane x), y -> readfirstlane x - if (match(Src, m_Intrinsic())) - return replaceInstUsesWith(*II, Src); - - if (IID == Intrinsic::amdgcn_readfirstlane) { - // readfirstlane (readlane x, y) -> readlane x, y - if (match(Src, m_Intrinsic())) - return replaceInstUsesWith(*II, Src); - } else { - // readlane (readlane x, y), y -> readlane x, y - if (match(Src, m_Intrinsic( - m_Value(), m_Specific(II->getArgOperand(1))))) - return replaceInstUsesWith(*II, Src); - } - - break; - } - case Intrinsic::amdgcn_ldexp: { - // FIXME: This doesn't introduce new instructions and belongs in - // InstructionSimplify. - Type *Ty = II->getType(); - Value *Op0 = II->getArgOperand(0); - Value *Op1 = II->getArgOperand(1); - - // Folding undef to qnan is safe regardless of the FP mode. - if (isa(Op0)) { - auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics())); - return replaceInstUsesWith(*II, QNaN); - } - - const APFloat *C = nullptr; - match(Op0, m_APFloat(C)); - - // FIXME: Should flush denorms depending on FP mode, but that's ignored - // everywhere else. - // - // These cases should be safe, even with strictfp. - // ldexp(0.0, x) -> 0.0 - // ldexp(-0.0, x) -> -0.0 - // ldexp(inf, x) -> inf - // ldexp(-inf, x) -> -inf - if (C && (C->isZero() || C->isInfinity())) - return replaceInstUsesWith(*II, Op0); - - // With strictfp, be more careful about possibly needing to flush denormals - // or not, and snan behavior depends on ieee_mode. - if (II->isStrictFP()) - break; - - if (C && C->isNaN()) { - // FIXME: We just need to make the nan quiet here, but that's unavailable - // on APFloat, only IEEEfloat - auto *Quieted = ConstantFP::get( - Ty, scalbn(*C, 0, APFloat::rmNearestTiesToEven)); - return replaceInstUsesWith(*II, Quieted); - } - - // ldexp(x, 0) -> x - // ldexp(x, undef) -> x - if (isa(Op1) || match(Op1, m_ZeroInt())) - return replaceInstUsesWith(*II, Op0); - - break; - } case Intrinsic::hexagon_V6_vandvrt: case Intrinsic::hexagon_V6_vandvrt_128B: { // Simplify Q -> V -> Q conversion. @@ -4238,14 +1509,14 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { FunctionType *AssumeIntrinsicTy = II->getFunctionType(); Value *AssumeIntrinsic = II->getCalledOperand(); Value *A, *B; - if (match(IIOperand, m_And(m_Value(A), m_Value(B)))) { + if (match(IIOperand, m_LogicalAnd(m_Value(A), m_Value(B)))) { Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, A, OpBundles, II->getName()); Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, B, II->getName()); return eraseInstFromFunction(*II); } // assume(!(a || b)) -> assume(!a); assume(!b); - if (match(IIOperand, m_Not(m_Or(m_Value(A), m_Value(B))))) { + if (match(IIOperand, m_Not(m_LogicalOr(m_Value(A), m_Value(B))))) { Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, Builder.CreateNot(A), OpBundles, II->getName()); Builder.CreateCall(AssumeIntrinsicTy, AssumeIntrinsic, @@ -4282,59 +1553,104 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { AC.updateAffectedValues(II); break; } - case Intrinsic::experimental_gc_relocate: { - auto &GCR = *cast(II); - - // If we have two copies of the same pointer in the statepoint argument - // list, canonicalize to one. This may let us common gc.relocates. - if (GCR.getBasePtr() == GCR.getDerivedPtr() && - GCR.getBasePtrIndex() != GCR.getDerivedPtrIndex()) { - auto *OpIntTy = GCR.getOperand(2)->getType(); - return replaceOperand(*II, 2, - ConstantInt::get(OpIntTy, GCR.getBasePtrIndex())); - } + case Intrinsic::experimental_gc_statepoint: { + GCStatepointInst &GCSP = *cast(II); + SmallPtrSet LiveGcValues; + for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) { + GCRelocateInst &GCR = *const_cast(Reloc); - // Translate facts known about a pointer before relocating into - // facts about the relocate value, while being careful to - // preserve relocation semantics. - Value *DerivedPtr = GCR.getDerivedPtr(); + // Remove the relocation if unused. + if (GCR.use_empty()) { + eraseInstFromFunction(GCR); + continue; + } - // Remove the relocation if unused, note that this check is required - // to prevent the cases below from looping forever. - if (II->use_empty()) - return eraseInstFromFunction(*II); + Value *DerivedPtr = GCR.getDerivedPtr(); + Value *BasePtr = GCR.getBasePtr(); - // Undef is undef, even after relocation. - // TODO: provide a hook for this in GCStrategy. This is clearly legal for - // most practical collectors, but there was discussion in the review thread - // about whether it was legal for all possible collectors. - if (isa(DerivedPtr)) - // Use undef of gc_relocate's type to replace it. - return replaceInstUsesWith(*II, UndefValue::get(II->getType())); - - if (auto *PT = dyn_cast(II->getType())) { - // The relocation of null will be null for most any collector. - // TODO: provide a hook for this in GCStrategy. There might be some - // weird collector this property does not hold for. - if (isa(DerivedPtr)) - // Use null-pointer of gc_relocate's type to replace it. - return replaceInstUsesWith(*II, ConstantPointerNull::get(PT)); - - // isKnownNonNull -> nonnull attribute - if (!II->hasRetAttr(Attribute::NonNull) && - isKnownNonZero(DerivedPtr, DL, 0, &AC, II, &DT)) { - II->addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); - return II; + // Undef is undef, even after relocation. + if (isa(DerivedPtr) || isa(BasePtr)) { + replaceInstUsesWith(GCR, UndefValue::get(GCR.getType())); + eraseInstFromFunction(GCR); + continue; } - } - // TODO: bitcast(relocate(p)) -> relocate(bitcast(p)) - // Canonicalize on the type from the uses to the defs + if (auto *PT = dyn_cast(GCR.getType())) { + // The relocation of null will be null for most any collector. + // TODO: provide a hook for this in GCStrategy. There might be some + // weird collector this property does not hold for. + if (isa(DerivedPtr)) { + // Use null-pointer of gc_relocate's type to replace it. + replaceInstUsesWith(GCR, ConstantPointerNull::get(PT)); + eraseInstFromFunction(GCR); + continue; + } + + // isKnownNonNull -> nonnull attribute + if (!GCR.hasRetAttr(Attribute::NonNull) && + isKnownNonZero(DerivedPtr, DL, 0, &AC, II, &DT)) { + GCR.addAttribute(AttributeList::ReturnIndex, Attribute::NonNull); + // We discovered new fact, re-check users. + Worklist.pushUsersToWorkList(GCR); + } + } + + // If we have two copies of the same pointer in the statepoint argument + // list, canonicalize to one. This may let us common gc.relocates. + if (GCR.getBasePtr() == GCR.getDerivedPtr() && + GCR.getBasePtrIndex() != GCR.getDerivedPtrIndex()) { + auto *OpIntTy = GCR.getOperand(2)->getType(); + GCR.setOperand(2, ConstantInt::get(OpIntTy, GCR.getBasePtrIndex())); + } - // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...) + // TODO: bitcast(relocate(p)) -> relocate(bitcast(p)) + // Canonicalize on the type from the uses to the defs + + // TODO: relocate((gep p, C, C2, ...)) -> gep(relocate(p), C, C2, ...) + LiveGcValues.insert(BasePtr); + LiveGcValues.insert(DerivedPtr); + } + Optional Bundle = + GCSP.getOperandBundle(LLVMContext::OB_gc_live); + unsigned NumOfGCLives = LiveGcValues.size(); + if (!Bundle.hasValue() || NumOfGCLives == Bundle->Inputs.size()) + break; + // We can reduce the size of gc live bundle. + DenseMap Val2Idx; + std::vector NewLiveGc; + for (unsigned I = 0, E = Bundle->Inputs.size(); I < E; ++I) { + Value *V = Bundle->Inputs[I]; + if (Val2Idx.count(V)) + continue; + if (LiveGcValues.count(V)) { + Val2Idx[V] = NewLiveGc.size(); + NewLiveGc.push_back(V); + } else + Val2Idx[V] = NumOfGCLives; + } + // Update all gc.relocates + for (const GCRelocateInst *Reloc : GCSP.getGCRelocates()) { + GCRelocateInst &GCR = *const_cast(Reloc); + Value *BasePtr = GCR.getBasePtr(); + assert(Val2Idx.count(BasePtr) && Val2Idx[BasePtr] != NumOfGCLives && + "Missed live gc for base pointer"); + auto *OpIntTy1 = GCR.getOperand(1)->getType(); + GCR.setOperand(1, ConstantInt::get(OpIntTy1, Val2Idx[BasePtr])); + Value *DerivedPtr = GCR.getDerivedPtr(); + assert(Val2Idx.count(DerivedPtr) && Val2Idx[DerivedPtr] != NumOfGCLives && + "Missed live gc for derived pointer"); + auto *OpIntTy2 = GCR.getOperand(2)->getType(); + GCR.setOperand(2, ConstantInt::get(OpIntTy2, Val2Idx[DerivedPtr])); + } + // Create new statepoint instruction. + OperandBundleDef NewBundle("gc-live", NewLiveGc); + if (isa(II)) + return CallInst::CreateWithReplacedBundle(cast(II), NewBundle); + else + return InvokeInst::CreateWithReplacedBundle(cast(II), + NewBundle); break; } - case Intrinsic::experimental_guard: { // Is this guard followed by another guard? We scan forward over a small // fixed window of instructions to handle common cases with conditions @@ -4367,12 +1683,114 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { } break; } + case Intrinsic::experimental_vector_insert: { + Value *Vec = II->getArgOperand(0); + Value *SubVec = II->getArgOperand(1); + Value *Idx = II->getArgOperand(2); + auto *DstTy = dyn_cast(II->getType()); + auto *VecTy = dyn_cast(Vec->getType()); + auto *SubVecTy = dyn_cast(SubVec->getType()); + + // Only canonicalize if the destination vector, Vec, and SubVec are all + // fixed vectors. + if (DstTy && VecTy && SubVecTy) { + unsigned DstNumElts = DstTy->getNumElements(); + unsigned VecNumElts = VecTy->getNumElements(); + unsigned SubVecNumElts = SubVecTy->getNumElements(); + unsigned IdxN = cast(Idx)->getZExtValue(); + + // The result of this call is undefined if IdxN is not a constant multiple + // of the SubVec's minimum vector length OR the insertion overruns Vec. + if (IdxN % SubVecNumElts != 0 || IdxN + SubVecNumElts > VecNumElts) { + replaceInstUsesWith(CI, UndefValue::get(CI.getType())); + return eraseInstFromFunction(CI); + } + + // An insert that entirely overwrites Vec with SubVec is a nop. + if (VecNumElts == SubVecNumElts) { + replaceInstUsesWith(CI, SubVec); + return eraseInstFromFunction(CI); + } + + // Widen SubVec into a vector of the same width as Vec, since + // shufflevector requires the two input vectors to be the same width. + // Elements beyond the bounds of SubVec within the widened vector are + // undefined. + SmallVector WidenMask; + unsigned i; + for (i = 0; i != SubVecNumElts; ++i) + WidenMask.push_back(i); + for (; i != VecNumElts; ++i) + WidenMask.push_back(UndefMaskElem); + + Value *WidenShuffle = Builder.CreateShuffleVector(SubVec, WidenMask); + + SmallVector Mask; + for (unsigned i = 0; i != IdxN; ++i) + Mask.push_back(i); + for (unsigned i = DstNumElts; i != DstNumElts + SubVecNumElts; ++i) + Mask.push_back(i); + for (unsigned i = IdxN + SubVecNumElts; i != DstNumElts; ++i) + Mask.push_back(i); + + Value *Shuffle = Builder.CreateShuffleVector(Vec, WidenShuffle, Mask); + replaceInstUsesWith(CI, Shuffle); + return eraseInstFromFunction(CI); + } + break; + } + case Intrinsic::experimental_vector_extract: { + Value *Vec = II->getArgOperand(0); + Value *Idx = II->getArgOperand(1); + + auto *DstTy = dyn_cast(II->getType()); + auto *VecTy = dyn_cast(Vec->getType()); + + // Only canonicalize if the the destination vector and Vec are fixed + // vectors. + if (DstTy && VecTy) { + unsigned DstNumElts = DstTy->getNumElements(); + unsigned VecNumElts = VecTy->getNumElements(); + unsigned IdxN = cast(Idx)->getZExtValue(); + + // The result of this call is undefined if IdxN is not a constant multiple + // of the result type's minimum vector length OR the extraction overruns + // Vec. + if (IdxN % DstNumElts != 0 || IdxN + DstNumElts > VecNumElts) { + replaceInstUsesWith(CI, UndefValue::get(CI.getType())); + return eraseInstFromFunction(CI); + } + + // Extracting the entirety of Vec is a nop. + if (VecNumElts == DstNumElts) { + replaceInstUsesWith(CI, Vec); + return eraseInstFromFunction(CI); + } + + SmallVector Mask; + for (unsigned i = 0; i != DstNumElts; ++i) + Mask.push_back(IdxN + i); + + Value *Shuffle = + Builder.CreateShuffleVector(Vec, UndefValue::get(VecTy), Mask); + replaceInstUsesWith(CI, Shuffle); + return eraseInstFromFunction(CI); + } + break; + } + default: { + // Handle target specific intrinsics + Optional V = targetInstCombineIntrinsic(*II); + if (V.hasValue()) + return V.getValue(); + break; + } } return visitCallBase(*II); } // Fence instruction simplification -Instruction *InstCombiner::visitFenceInst(FenceInst &FI) { +Instruction *InstCombinerImpl::visitFenceInst(FenceInst &FI) { // Remove identical consecutive fences. Instruction *Next = FI.getNextNonDebugInstruction(); if (auto *NFI = dyn_cast(Next)) @@ -4382,12 +1800,12 @@ Instruction *InstCombiner::visitFenceInst(FenceInst &FI) { } // InvokeInst simplification -Instruction *InstCombiner::visitInvokeInst(InvokeInst &II) { +Instruction *InstCombinerImpl::visitInvokeInst(InvokeInst &II) { return visitCallBase(II); } // CallBrInst simplification -Instruction *InstCombiner::visitCallBrInst(CallBrInst &CBI) { +Instruction *InstCombinerImpl::visitCallBrInst(CallBrInst &CBI) { return visitCallBase(CBI); } @@ -4427,7 +1845,7 @@ static bool isSafeToEliminateVarargsCast(const CallBase &Call, return true; } -Instruction *InstCombiner::tryOptimizeCall(CallInst *CI) { +Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) { if (!CI->getCalledFunction()) return nullptr; auto InstCombineRAUW = [this](Instruction *From, Value *With) { @@ -4584,7 +2002,7 @@ static void annotateAnyAllocSite(CallBase &Call, const TargetLibraryInfo *TLI) { } /// Improvements for call, callbr and invoke instructions. -Instruction *InstCombiner::visitCallBase(CallBase &Call) { +Instruction *InstCombinerImpl::visitCallBase(CallBase &Call) { if (isAllocationFn(&Call, &TLI)) annotateAnyAllocSite(Call, &TLI); @@ -4640,7 +2058,7 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) { !CalleeF->isDeclaration()) { Instruction *OldCall = &Call; CreateNonTerminatorUnreachable(OldCall); - // If OldCall does not return void then replaceAllUsesWith undef. + // If OldCall does not return void then replaceInstUsesWith undef. // This allows ValueHandlers and custom metadata to adjust itself. if (!OldCall->getType()->isVoidTy()) replaceInstUsesWith(*OldCall, UndefValue::get(OldCall->getType())); @@ -4659,7 +2077,7 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) { if ((isa(Callee) && !NullPointerIsDefined(Call.getFunction())) || isa(Callee)) { - // If Call does not return void then replaceAllUsesWith undef. + // If Call does not return void then replaceInstUsesWith undef. // This allows ValueHandlers and custom metadata to adjust itself. if (!Call.getType()->isVoidTy()) replaceInstUsesWith(Call, UndefValue::get(Call.getType())); @@ -4735,7 +2153,7 @@ Instruction *InstCombiner::visitCallBase(CallBase &Call) { /// If the callee is a constexpr cast of a function, attempt to move the cast to /// the arguments of the call/callbr/invoke. -bool InstCombiner::transformConstExprCastCall(CallBase &Call) { +bool InstCombinerImpl::transformConstExprCastCall(CallBase &Call) { auto *Callee = dyn_cast(Call.getCalledOperand()->stripPointerCasts()); if (!Callee) @@ -4834,6 +2252,9 @@ bool InstCombiner::transformConstExprCastCall(CallBase &Call) { if (Call.isInAllocaArgument(i)) return false; // Cannot transform to and from inalloca. + if (CallerPAL.hasParamAttribute(i, Attribute::SwiftError)) + return false; + // If the parameter is passed as a byval argument, then we have to have a // sized type and the sized type has to have the same size as the old type. if (ParamTy != ActTy && CallerPAL.hasParamAttribute(i, Attribute::ByVal)) { @@ -5019,8 +2440,8 @@ bool InstCombiner::transformConstExprCastCall(CallBase &Call) { /// Turn a call to a function created by init_trampoline / adjust_trampoline /// intrinsic pair into a direct call to the underlying function. Instruction * -InstCombiner::transformCallThroughTrampoline(CallBase &Call, - IntrinsicInst &Tramp) { +InstCombinerImpl::transformCallThroughTrampoline(CallBase &Call, + IntrinsicInst &Tramp) { Value *Callee = Call.getCalledOperand(); Type *CalleeTy = Callee->getType(); FunctionType *FTy = Call.getFunctionType(); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp index 3639edb5df4d..0b53007bb6dc 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -14,10 +14,11 @@ #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/IR/DataLayout.h" #include "llvm/IR/DIBuilder.h" +#include "llvm/IR/DataLayout.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include using namespace llvm; using namespace PatternMatch; @@ -81,8 +82,8 @@ static Value *decomposeSimpleLinearExpr(Value *Val, unsigned &Scale, /// If we find a cast of an allocation instruction, try to eliminate the cast by /// moving the type information into the alloc. -Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, - AllocaInst &AI) { +Instruction *InstCombinerImpl::PromoteCastOfAllocation(BitCastInst &CI, + AllocaInst &AI) { PointerType *PTy = cast(CI.getType()); IRBuilderBase::InsertPointGuard Guard(Builder); @@ -93,6 +94,18 @@ Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, Type *CastElTy = PTy->getElementType(); if (!AllocElTy->isSized() || !CastElTy->isSized()) return nullptr; + // This optimisation does not work for cases where the cast type + // is scalable and the allocated type is not. This because we need to + // know how many times the casted type fits into the allocated type. + // For the opposite case where the allocated type is scalable and the + // cast type is not this leads to poor code quality due to the + // introduction of 'vscale' into the calculations. It seems better to + // bail out for this case too until we've done a proper cost-benefit + // analysis. + bool AllocIsScalable = isa(AllocElTy); + bool CastIsScalable = isa(CastElTy); + if (AllocIsScalable != CastIsScalable) return nullptr; + Align AllocElTyAlign = DL.getABITypeAlign(AllocElTy); Align CastElTyAlign = DL.getABITypeAlign(CastElTy); if (CastElTyAlign < AllocElTyAlign) return nullptr; @@ -102,14 +115,15 @@ Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, // same, we open the door to infinite loops of various kinds. if (!AI.hasOneUse() && CastElTyAlign == AllocElTyAlign) return nullptr; - uint64_t AllocElTySize = DL.getTypeAllocSize(AllocElTy); - uint64_t CastElTySize = DL.getTypeAllocSize(CastElTy); + // The alloc and cast types should be either both fixed or both scalable. + uint64_t AllocElTySize = DL.getTypeAllocSize(AllocElTy).getKnownMinSize(); + uint64_t CastElTySize = DL.getTypeAllocSize(CastElTy).getKnownMinSize(); if (CastElTySize == 0 || AllocElTySize == 0) return nullptr; // If the allocation has multiple uses, only promote it if we're not // shrinking the amount of memory being allocated. - uint64_t AllocElTyStoreSize = DL.getTypeStoreSize(AllocElTy); - uint64_t CastElTyStoreSize = DL.getTypeStoreSize(CastElTy); + uint64_t AllocElTyStoreSize = DL.getTypeStoreSize(AllocElTy).getKnownMinSize(); + uint64_t CastElTyStoreSize = DL.getTypeStoreSize(CastElTy).getKnownMinSize(); if (!AI.hasOneUse() && CastElTyStoreSize < AllocElTyStoreSize) return nullptr; // See if we can satisfy the modulus by pulling a scale out of the array @@ -124,6 +138,9 @@ Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, if ((AllocElTySize*ArraySizeScale) % CastElTySize != 0 || (AllocElTySize*ArrayOffset ) % CastElTySize != 0) return nullptr; + // We don't currently support arrays of scalable types. + assert(!AllocIsScalable || (ArrayOffset == 1 && ArraySizeScale == 0)); + unsigned Scale = (AllocElTySize*ArraySizeScale)/CastElTySize; Value *Amt = nullptr; if (Scale == 1) { @@ -160,8 +177,8 @@ Instruction *InstCombiner::PromoteCastOfAllocation(BitCastInst &CI, /// Given an expression that CanEvaluateTruncated or CanEvaluateSExtd returns /// true for, actually insert the code to evaluate the expression. -Value *InstCombiner::EvaluateInDifferentType(Value *V, Type *Ty, - bool isSigned) { +Value *InstCombinerImpl::EvaluateInDifferentType(Value *V, Type *Ty, + bool isSigned) { if (Constant *C = dyn_cast(V)) { C = ConstantExpr::getIntegerCast(C, Ty, isSigned /*Sext or ZExt*/); // If we got a constantexpr back, try to simplify it with DL info. @@ -229,8 +246,9 @@ Value *InstCombiner::EvaluateInDifferentType(Value *V, Type *Ty, return InsertNewInstWith(Res, *I); } -Instruction::CastOps InstCombiner::isEliminableCastPair(const CastInst *CI1, - const CastInst *CI2) { +Instruction::CastOps +InstCombinerImpl::isEliminableCastPair(const CastInst *CI1, + const CastInst *CI2) { Type *SrcTy = CI1->getSrcTy(); Type *MidTy = CI1->getDestTy(); Type *DstTy = CI2->getDestTy(); @@ -257,7 +275,7 @@ Instruction::CastOps InstCombiner::isEliminableCastPair(const CastInst *CI1, } /// Implement the transforms common to all CastInst visitors. -Instruction *InstCombiner::commonCastTransforms(CastInst &CI) { +Instruction *InstCombinerImpl::commonCastTransforms(CastInst &CI) { Value *Src = CI.getOperand(0); // Try to eliminate a cast of a cast. @@ -342,7 +360,7 @@ static bool canNotEvaluateInType(Value *V, Type *Ty) { /// /// This function works on both vectors and scalars. /// -static bool canEvaluateTruncated(Value *V, Type *Ty, InstCombiner &IC, +static bool canEvaluateTruncated(Value *V, Type *Ty, InstCombinerImpl &IC, Instruction *CxtI) { if (canAlwaysEvaluateInType(V, Ty)) return true; @@ -459,7 +477,8 @@ static bool canEvaluateTruncated(Value *V, Type *Ty, InstCombiner &IC, /// trunc (lshr (bitcast <4 x i32> %X to i128), 32) to i32 /// ---> /// extractelement <4 x i32> %X, 1 -static Instruction *foldVecTruncToExtElt(TruncInst &Trunc, InstCombiner &IC) { +static Instruction *foldVecTruncToExtElt(TruncInst &Trunc, + InstCombinerImpl &IC) { Value *TruncOp = Trunc.getOperand(0); Type *DestType = Trunc.getType(); if (!TruncOp->hasOneUse() || !isa(DestType)) @@ -496,9 +515,9 @@ static Instruction *foldVecTruncToExtElt(TruncInst &Trunc, InstCombiner &IC) { return ExtractElementInst::Create(VecInput, IC.Builder.getInt32(Elt)); } -/// Rotate left/right may occur in a wider type than necessary because of type -/// promotion rules. Try to narrow the inputs and convert to funnel shift. -Instruction *InstCombiner::narrowRotate(TruncInst &Trunc) { +/// Funnel/Rotate left/right may occur in a wider type than necessary because of +/// type promotion rules. Try to narrow the inputs and convert to funnel shift. +Instruction *InstCombinerImpl::narrowFunnelShift(TruncInst &Trunc) { assert((isa(Trunc.getSrcTy()) || shouldChangeType(Trunc.getSrcTy(), Trunc.getType())) && "Don't narrow to an illegal scalar type"); @@ -510,32 +529,43 @@ Instruction *InstCombiner::narrowRotate(TruncInst &Trunc) { if (!isPowerOf2_32(NarrowWidth)) return nullptr; - // First, find an or'd pair of opposite shifts with the same shifted operand: - // trunc (or (lshr ShVal, ShAmt0), (shl ShVal, ShAmt1)) - Value *Or0, *Or1; - if (!match(Trunc.getOperand(0), m_OneUse(m_Or(m_Value(Or0), m_Value(Or1))))) + // First, find an or'd pair of opposite shifts: + // trunc (or (lshr ShVal0, ShAmt0), (shl ShVal1, ShAmt1)) + BinaryOperator *Or0, *Or1; + if (!match(Trunc.getOperand(0), m_OneUse(m_Or(m_BinOp(Or0), m_BinOp(Or1))))) return nullptr; - Value *ShVal, *ShAmt0, *ShAmt1; - if (!match(Or0, m_OneUse(m_LogicalShift(m_Value(ShVal), m_Value(ShAmt0)))) || - !match(Or1, m_OneUse(m_LogicalShift(m_Specific(ShVal), m_Value(ShAmt1))))) + Value *ShVal0, *ShVal1, *ShAmt0, *ShAmt1; + if (!match(Or0, m_OneUse(m_LogicalShift(m_Value(ShVal0), m_Value(ShAmt0)))) || + !match(Or1, m_OneUse(m_LogicalShift(m_Value(ShVal1), m_Value(ShAmt1)))) || + Or0->getOpcode() == Or1->getOpcode()) return nullptr; - auto ShiftOpcode0 = cast(Or0)->getOpcode(); - auto ShiftOpcode1 = cast(Or1)->getOpcode(); - if (ShiftOpcode0 == ShiftOpcode1) - return nullptr; + // Canonicalize to or(shl(ShVal0, ShAmt0), lshr(ShVal1, ShAmt1)). + if (Or0->getOpcode() == BinaryOperator::LShr) { + std::swap(Or0, Or1); + std::swap(ShVal0, ShVal1); + std::swap(ShAmt0, ShAmt1); + } + assert(Or0->getOpcode() == BinaryOperator::Shl && + Or1->getOpcode() == BinaryOperator::LShr && + "Illegal or(shift,shift) pair"); - // Match the shift amount operands for a rotate pattern. This always matches - // a subtraction on the R operand. - auto matchShiftAmount = [](Value *L, Value *R, unsigned Width) -> Value * { + // Match the shift amount operands for a funnel/rotate pattern. This always + // matches a subtraction on the R operand. + auto matchShiftAmount = [&](Value *L, Value *R, unsigned Width) -> Value * { // The shift amounts may add up to the narrow bit width: - // (shl ShVal, L) | (lshr ShVal, Width - L) + // (shl ShVal0, L) | (lshr ShVal1, Width - L) if (match(R, m_OneUse(m_Sub(m_SpecificInt(Width), m_Specific(L))))) return L; + // The following patterns currently only work for rotation patterns. + // TODO: Add more general funnel-shift compatible patterns. + if (ShVal0 != ShVal1) + return nullptr; + // The shift amount may be masked with negation: - // (shl ShVal, (X & (Width - 1))) | (lshr ShVal, ((-X) & (Width - 1))) + // (shl ShVal0, (X & (Width - 1))) | (lshr ShVal1, ((-X) & (Width - 1))) Value *X; unsigned Mask = Width - 1; if (match(L, m_And(m_Value(X), m_SpecificInt(Mask))) && @@ -551,10 +581,10 @@ Instruction *InstCombiner::narrowRotate(TruncInst &Trunc) { }; Value *ShAmt = matchShiftAmount(ShAmt0, ShAmt1, NarrowWidth); - bool SubIsOnLHS = false; + bool IsFshl = true; // Sub on LSHR. if (!ShAmt) { ShAmt = matchShiftAmount(ShAmt1, ShAmt0, NarrowWidth); - SubIsOnLHS = true; + IsFshl = false; // Sub on SHL. } if (!ShAmt) return nullptr; @@ -563,26 +593,28 @@ Instruction *InstCombiner::narrowRotate(TruncInst &Trunc) { // will be a zext, but it could also be the result of an 'and' or 'shift'. unsigned WideWidth = Trunc.getSrcTy()->getScalarSizeInBits(); APInt HiBitMask = APInt::getHighBitsSet(WideWidth, WideWidth - NarrowWidth); - if (!MaskedValueIsZero(ShVal, HiBitMask, 0, &Trunc)) + if (!MaskedValueIsZero(ShVal0, HiBitMask, 0, &Trunc) || + !MaskedValueIsZero(ShVal1, HiBitMask, 0, &Trunc)) return nullptr; // We have an unnecessarily wide rotate! - // trunc (or (lshr ShVal, ShAmt), (shl ShVal, BitWidth - ShAmt)) + // trunc (or (lshr ShVal0, ShAmt), (shl ShVal1, BitWidth - ShAmt)) // Narrow the inputs and convert to funnel shift intrinsic: // llvm.fshl.i8(trunc(ShVal), trunc(ShVal), trunc(ShAmt)) Value *NarrowShAmt = Builder.CreateTrunc(ShAmt, DestTy); - Value *X = Builder.CreateTrunc(ShVal, DestTy); - bool IsFshl = (!SubIsOnLHS && ShiftOpcode0 == BinaryOperator::Shl) || - (SubIsOnLHS && ShiftOpcode1 == BinaryOperator::Shl); + Value *X, *Y; + X = Y = Builder.CreateTrunc(ShVal0, DestTy); + if (ShVal0 != ShVal1) + Y = Builder.CreateTrunc(ShVal1, DestTy); Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr; Function *F = Intrinsic::getDeclaration(Trunc.getModule(), IID, DestTy); - return IntrinsicInst::Create(F, { X, X, NarrowShAmt }); + return IntrinsicInst::Create(F, {X, Y, NarrowShAmt}); } /// Try to narrow the width of math or bitwise logic instructions by pulling a /// truncate ahead of binary operators. /// TODO: Transforms for truncated shifts should be moved into here. -Instruction *InstCombiner::narrowBinOp(TruncInst &Trunc) { +Instruction *InstCombinerImpl::narrowBinOp(TruncInst &Trunc) { Type *SrcTy = Trunc.getSrcTy(); Type *DestTy = Trunc.getType(); if (!isa(SrcTy) && !shouldChangeType(SrcTy, DestTy)) @@ -631,7 +663,7 @@ Instruction *InstCombiner::narrowBinOp(TruncInst &Trunc) { default: break; } - if (Instruction *NarrowOr = narrowRotate(Trunc)) + if (Instruction *NarrowOr = narrowFunnelShift(Trunc)) return NarrowOr; return nullptr; @@ -687,7 +719,7 @@ static Instruction *shrinkInsertElt(CastInst &Trunc, return nullptr; } -Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { +Instruction *InstCombinerImpl::visitTrunc(TruncInst &Trunc) { if (Instruction *Result = commonCastTransforms(Trunc)) return Result; @@ -695,7 +727,6 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { Type *DestTy = Trunc.getType(), *SrcTy = Src->getType(); unsigned DestWidth = DestTy->getScalarSizeInBits(); unsigned SrcWidth = SrcTy->getScalarSizeInBits(); - ConstantInt *Cst; // Attempt to truncate the entire input expression tree to the destination // type. Only do this if the dest type is a simple type, don't convert the @@ -782,56 +813,60 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { } } - // FIXME: Maybe combine the next two transforms to handle the no cast case - // more efficiently. Support vector types. Cleanup code by using m_OneUse. - - // Transform trunc(lshr (zext A), Cst) to eliminate one type conversion. - Value *A = nullptr; - if (Src->hasOneUse() && - match(Src, m_LShr(m_ZExt(m_Value(A)), m_ConstantInt(Cst)))) { - // We have three types to worry about here, the type of A, the source of - // the truncate (MidSize), and the destination of the truncate. We know that - // ASize < MidSize and MidSize > ResultSize, but don't know the relation - // between ASize and ResultSize. - unsigned ASize = A->getType()->getPrimitiveSizeInBits(); - - // If the shift amount is larger than the size of A, then the result is - // known to be zero because all the input bits got shifted out. - if (Cst->getZExtValue() >= ASize) - return replaceInstUsesWith(Trunc, Constant::getNullValue(DestTy)); - - // Since we're doing an lshr and a zero extend, and know that the shift - // amount is smaller than ASize, it is always safe to do the shift in A's - // type, then zero extend or truncate to the result. - Value *Shift = Builder.CreateLShr(A, Cst->getZExtValue()); - Shift->takeName(Src); - return CastInst::CreateIntegerCast(Shift, DestTy, false); - } - - const APInt *C; - if (match(Src, m_LShr(m_SExt(m_Value(A)), m_APInt(C)))) { + Value *A; + Constant *C; + if (match(Src, m_LShr(m_SExt(m_Value(A)), m_Constant(C)))) { unsigned AWidth = A->getType()->getScalarSizeInBits(); unsigned MaxShiftAmt = SrcWidth - std::max(DestWidth, AWidth); + auto *OldSh = cast(Src); + bool IsExact = OldSh->isExact(); // If the shift is small enough, all zero bits created by the shift are // removed by the trunc. - if (C->getZExtValue() <= MaxShiftAmt) { + if (match(C, m_SpecificInt_ICMP(ICmpInst::ICMP_ULE, + APInt(SrcWidth, MaxShiftAmt)))) { // trunc (lshr (sext A), C) --> ashr A, C if (A->getType() == DestTy) { - unsigned ShAmt = std::min((unsigned)C->getZExtValue(), DestWidth - 1); - return BinaryOperator::CreateAShr(A, ConstantInt::get(DestTy, ShAmt)); + Constant *MaxAmt = ConstantInt::get(SrcTy, DestWidth - 1, false); + Constant *ShAmt = ConstantExpr::getUMin(C, MaxAmt); + ShAmt = ConstantExpr::getTrunc(ShAmt, A->getType()); + ShAmt = Constant::mergeUndefsWith(ShAmt, C); + return IsExact ? BinaryOperator::CreateExactAShr(A, ShAmt) + : BinaryOperator::CreateAShr(A, ShAmt); } // The types are mismatched, so create a cast after shifting: // trunc (lshr (sext A), C) --> sext/trunc (ashr A, C) if (Src->hasOneUse()) { - unsigned ShAmt = std::min((unsigned)C->getZExtValue(), AWidth - 1); - Value *Shift = Builder.CreateAShr(A, ShAmt); + Constant *MaxAmt = ConstantInt::get(SrcTy, AWidth - 1, false); + Constant *ShAmt = ConstantExpr::getUMin(C, MaxAmt); + ShAmt = ConstantExpr::getTrunc(ShAmt, A->getType()); + Value *Shift = Builder.CreateAShr(A, ShAmt, "", IsExact); return CastInst::CreateIntegerCast(Shift, DestTy, true); } } // TODO: Mask high bits with 'and'. } + // trunc (*shr (trunc A), C) --> trunc(*shr A, C) + if (match(Src, m_OneUse(m_Shr(m_Trunc(m_Value(A)), m_Constant(C))))) { + unsigned MaxShiftAmt = SrcWidth - DestWidth; + + // If the shift is small enough, all zero/sign bits created by the shift are + // removed by the trunc. + if (match(C, m_SpecificInt_ICMP(ICmpInst::ICMP_ULE, + APInt(SrcWidth, MaxShiftAmt)))) { + auto *OldShift = cast(Src); + bool IsExact = OldShift->isExact(); + auto *ShAmt = ConstantExpr::getIntegerCast(C, A->getType(), true); + ShAmt = Constant::mergeUndefsWith(ShAmt, C); + Value *Shift = + OldShift->getOpcode() == Instruction::AShr + ? Builder.CreateAShr(A, ShAmt, OldShift->getName(), IsExact) + : Builder.CreateLShr(A, ShAmt, OldShift->getName(), IsExact); + return CastInst::CreateTruncOrBitCast(Shift, DestTy); + } + } + if (Instruction *I = narrowBinOp(Trunc)) return I; @@ -841,20 +876,19 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { if (Instruction *I = shrinkInsertElt(Trunc, Builder)) return I; - if (Src->hasOneUse() && isa(SrcTy) && - shouldChangeType(SrcTy, DestTy)) { + if (Src->hasOneUse() && + (isa(SrcTy) || shouldChangeType(SrcTy, DestTy))) { // Transform "trunc (shl X, cst)" -> "shl (trunc X), cst" so long as the // dest type is native and cst < dest size. - if (match(Src, m_Shl(m_Value(A), m_ConstantInt(Cst))) && + if (match(Src, m_Shl(m_Value(A), m_Constant(C))) && !match(A, m_Shr(m_Value(), m_Constant()))) { // Skip shifts of shift by constants. It undoes a combine in // FoldShiftByConstant and is the extend in reg pattern. - if (Cst->getValue().ult(DestWidth)) { + APInt Threshold = APInt(C->getType()->getScalarSizeInBits(), DestWidth); + if (match(C, m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, Threshold))) { Value *NewTrunc = Builder.CreateTrunc(A, DestTy, A->getName() + ".tr"); - - return BinaryOperator::Create( - Instruction::Shl, NewTrunc, - ConstantInt::get(DestTy, Cst->getValue().trunc(DestWidth))); + return BinaryOperator::Create(Instruction::Shl, NewTrunc, + ConstantExpr::getTrunc(C, DestTy)); } } } @@ -871,21 +905,23 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { // ---> // extractelement <8 x i32> (bitcast <4 x i64> %X to <8 x i32>), i32 0 Value *VecOp; + ConstantInt *Cst; if (match(Src, m_OneUse(m_ExtractElt(m_Value(VecOp), m_ConstantInt(Cst))))) { auto *VecOpTy = cast(VecOp->getType()); - unsigned VecNumElts = VecOpTy->getNumElements(); + auto VecElts = VecOpTy->getElementCount(); // A badly fit destination size would result in an invalid cast. if (SrcWidth % DestWidth == 0) { uint64_t TruncRatio = SrcWidth / DestWidth; - uint64_t BitCastNumElts = VecNumElts * TruncRatio; + uint64_t BitCastNumElts = VecElts.getKnownMinValue() * TruncRatio; uint64_t VecOpIdx = Cst->getZExtValue(); uint64_t NewIdx = DL.isBigEndian() ? (VecOpIdx + 1) * TruncRatio - 1 : VecOpIdx * TruncRatio; assert(BitCastNumElts <= std::numeric_limits::max() && "overflow 32-bits"); - auto *BitCastTo = FixedVectorType::get(DestTy, BitCastNumElts); + auto *BitCastTo = + VectorType::get(DestTy, BitCastNumElts, VecElts.isScalable()); Value *BitCast = Builder.CreateBitCast(VecOp, BitCastTo); return ExtractElementInst::Create(BitCast, Builder.getInt32(NewIdx)); } @@ -894,8 +930,8 @@ Instruction *InstCombiner::visitTrunc(TruncInst &Trunc) { return nullptr; } -Instruction *InstCombiner::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext, - bool DoTransform) { +Instruction *InstCombinerImpl::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext, + bool DoTransform) { // If we are just checking for a icmp eq of a single bit and zext'ing it // to an integer, then shift the bit to the appropriate place and then // cast to integer to avoid the comparison. @@ -1031,7 +1067,7 @@ Instruction *InstCombiner::transformZExtICmp(ICmpInst *Cmp, ZExtInst &Zext, /// /// This function works on both vectors and scalars. static bool canEvaluateZExtd(Value *V, Type *Ty, unsigned &BitsToClear, - InstCombiner &IC, Instruction *CxtI) { + InstCombinerImpl &IC, Instruction *CxtI) { BitsToClear = 0; if (canAlwaysEvaluateInType(V, Ty)) return true; @@ -1136,7 +1172,7 @@ static bool canEvaluateZExtd(Value *V, Type *Ty, unsigned &BitsToClear, } } -Instruction *InstCombiner::visitZExt(ZExtInst &CI) { +Instruction *InstCombinerImpl::visitZExt(ZExtInst &CI) { // If this zero extend is only used by a truncate, let the truncate be // eliminated before we try to optimize this zext. if (CI.hasOneUse() && isa(CI.user_back())) @@ -1274,7 +1310,8 @@ Instruction *InstCombiner::visitZExt(ZExtInst &CI) { } /// Transform (sext icmp) to bitwise / integer operations to eliminate the icmp. -Instruction *InstCombiner::transformSExtICmp(ICmpInst *ICI, Instruction &CI) { +Instruction *InstCombinerImpl::transformSExtICmp(ICmpInst *ICI, + Instruction &CI) { Value *Op0 = ICI->getOperand(0), *Op1 = ICI->getOperand(1); ICmpInst::Predicate Pred = ICI->getPredicate(); @@ -1410,7 +1447,7 @@ static bool canEvaluateSExtd(Value *V, Type *Ty) { return false; } -Instruction *InstCombiner::visitSExt(SExtInst &CI) { +Instruction *InstCombinerImpl::visitSExt(SExtInst &CI) { // If this sign extend is only used by a truncate, let the truncate be // eliminated before we try to optimize this sext. if (CI.hasOneUse() && isa(CI.user_back())) @@ -1473,31 +1510,33 @@ Instruction *InstCombiner::visitSExt(SExtInst &CI) { // for a truncate. If the source and dest are the same type, eliminate the // trunc and extend and just do shifts. For example, turn: // %a = trunc i32 %i to i8 - // %b = shl i8 %a, 6 - // %c = ashr i8 %b, 6 + // %b = shl i8 %a, C + // %c = ashr i8 %b, C // %d = sext i8 %c to i32 // into: - // %a = shl i32 %i, 30 - // %d = ashr i32 %a, 30 + // %a = shl i32 %i, 32-(8-C) + // %d = ashr i32 %a, 32-(8-C) Value *A = nullptr; // TODO: Eventually this could be subsumed by EvaluateInDifferentType. Constant *BA = nullptr, *CA = nullptr; if (match(Src, m_AShr(m_Shl(m_Trunc(m_Value(A)), m_Constant(BA)), m_Constant(CA))) && - BA == CA && A->getType() == CI.getType()) { - unsigned MidSize = Src->getType()->getScalarSizeInBits(); - unsigned SrcDstSize = CI.getType()->getScalarSizeInBits(); - Constant *SizeDiff = ConstantInt::get(CA->getType(), SrcDstSize - MidSize); - Constant *ShAmt = ConstantExpr::getAdd(CA, SizeDiff); - Constant *ShAmtExt = ConstantExpr::getSExt(ShAmt, CI.getType()); - A = Builder.CreateShl(A, ShAmtExt, CI.getName()); - return BinaryOperator::CreateAShr(A, ShAmtExt); + BA->isElementWiseEqual(CA) && A->getType() == DestTy) { + Constant *WideCurrShAmt = ConstantExpr::getSExt(CA, DestTy); + Constant *NumLowbitsLeft = ConstantExpr::getSub( + ConstantInt::get(DestTy, SrcTy->getScalarSizeInBits()), WideCurrShAmt); + Constant *NewShAmt = ConstantExpr::getSub( + ConstantInt::get(DestTy, DestTy->getScalarSizeInBits()), + NumLowbitsLeft); + NewShAmt = + Constant::mergeUndefsWith(Constant::mergeUndefsWith(NewShAmt, BA), CA); + A = Builder.CreateShl(A, NewShAmt, CI.getName()); + return BinaryOperator::CreateAShr(A, NewShAmt); } return nullptr; } - /// Return a Constant* for the specified floating-point constant if it fits /// in the specified FP type without changing its value. static bool fitsInFPType(ConstantFP *CFP, const fltSemantics &Sem) { @@ -1535,7 +1574,7 @@ static Type *shrinkFPConstantVector(Value *V) { Type *MinType = nullptr; - unsigned NumElts = CVVTy->getNumElements(); + unsigned NumElts = cast(CVVTy)->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) { auto *CFP = dyn_cast_or_null(CV->getAggregateElement(i)); if (!CFP) @@ -1616,7 +1655,7 @@ static bool isKnownExactCastIntToFP(CastInst &I) { return false; } -Instruction *InstCombiner::visitFPTrunc(FPTruncInst &FPT) { +Instruction *InstCombinerImpl::visitFPTrunc(FPTruncInst &FPT) { if (Instruction *I = commonCastTransforms(FPT)) return I; @@ -1800,7 +1839,7 @@ Instruction *InstCombiner::visitFPTrunc(FPTruncInst &FPT) { return nullptr; } -Instruction *InstCombiner::visitFPExt(CastInst &FPExt) { +Instruction *InstCombinerImpl::visitFPExt(CastInst &FPExt) { // If the source operand is a cast from integer to FP and known exact, then // cast the integer operand directly to the destination type. Type *Ty = FPExt.getType(); @@ -1818,7 +1857,7 @@ Instruction *InstCombiner::visitFPExt(CastInst &FPExt) { /// This is safe if the intermediate type has enough bits in its mantissa to /// accurately represent all values of X. For example, this won't work with /// i64 -> float -> i64. -Instruction *InstCombiner::foldItoFPtoI(CastInst &FI) { +Instruction *InstCombinerImpl::foldItoFPtoI(CastInst &FI) { if (!isa(FI.getOperand(0)) && !isa(FI.getOperand(0))) return nullptr; @@ -1858,29 +1897,29 @@ Instruction *InstCombiner::foldItoFPtoI(CastInst &FI) { return replaceInstUsesWith(FI, X); } -Instruction *InstCombiner::visitFPToUI(FPToUIInst &FI) { +Instruction *InstCombinerImpl::visitFPToUI(FPToUIInst &FI) { if (Instruction *I = foldItoFPtoI(FI)) return I; return commonCastTransforms(FI); } -Instruction *InstCombiner::visitFPToSI(FPToSIInst &FI) { +Instruction *InstCombinerImpl::visitFPToSI(FPToSIInst &FI) { if (Instruction *I = foldItoFPtoI(FI)) return I; return commonCastTransforms(FI); } -Instruction *InstCombiner::visitUIToFP(CastInst &CI) { +Instruction *InstCombinerImpl::visitUIToFP(CastInst &CI) { return commonCastTransforms(CI); } -Instruction *InstCombiner::visitSIToFP(CastInst &CI) { +Instruction *InstCombinerImpl::visitSIToFP(CastInst &CI) { return commonCastTransforms(CI); } -Instruction *InstCombiner::visitIntToPtr(IntToPtrInst &CI) { +Instruction *InstCombinerImpl::visitIntToPtr(IntToPtrInst &CI) { // If the source integer type is not the intptr_t type for this target, do a // trunc or zext to the intptr_t type, then inttoptr of it. This allows the // cast to be exposed to other transforms. @@ -1903,7 +1942,7 @@ Instruction *InstCombiner::visitIntToPtr(IntToPtrInst &CI) { } /// Implement the transforms for cast of pointer (bitcast/ptrtoint) -Instruction *InstCombiner::commonPointerCastTransforms(CastInst &CI) { +Instruction *InstCombinerImpl::commonPointerCastTransforms(CastInst &CI) { Value *Src = CI.getOperand(0); if (GetElementPtrInst *GEP = dyn_cast(Src)) { @@ -1925,26 +1964,37 @@ Instruction *InstCombiner::commonPointerCastTransforms(CastInst &CI) { return commonCastTransforms(CI); } -Instruction *InstCombiner::visitPtrToInt(PtrToIntInst &CI) { +Instruction *InstCombinerImpl::visitPtrToInt(PtrToIntInst &CI) { // If the destination integer type is not the intptr_t type for this target, // do a ptrtoint to intptr_t then do a trunc or zext. This allows the cast // to be exposed to other transforms. - + Value *SrcOp = CI.getPointerOperand(); Type *Ty = CI.getType(); unsigned AS = CI.getPointerAddressSpace(); + unsigned TySize = Ty->getScalarSizeInBits(); + unsigned PtrSize = DL.getPointerSizeInBits(AS); + if (TySize != PtrSize) { + Type *IntPtrTy = DL.getIntPtrType(CI.getContext(), AS); + // Handle vectors of pointers. + if (auto *VecTy = dyn_cast(Ty)) + IntPtrTy = VectorType::get(IntPtrTy, VecTy->getElementCount()); - if (Ty->getScalarSizeInBits() == DL.getPointerSizeInBits(AS)) - return commonPointerCastTransforms(CI); + Value *P = Builder.CreatePtrToInt(SrcOp, IntPtrTy); + return CastInst::CreateIntegerCast(P, Ty, /*isSigned=*/false); + } - Type *PtrTy = DL.getIntPtrType(CI.getContext(), AS); - if (auto *VTy = dyn_cast(Ty)) { - // Handle vectors of pointers. - // FIXME: what should happen for scalable vectors? - PtrTy = FixedVectorType::get(PtrTy, VTy->getNumElements()); + Value *Vec, *Scalar, *Index; + if (match(SrcOp, m_OneUse(m_InsertElt(m_IntToPtr(m_Value(Vec)), + m_Value(Scalar), m_Value(Index)))) && + Vec->getType() == Ty) { + assert(Vec->getType()->getScalarSizeInBits() == PtrSize && "Wrong type"); + // Convert the scalar to int followed by insert to eliminate one cast: + // p2i (ins (i2p Vec), Scalar, Index --> ins Vec, (p2i Scalar), Index + Value *NewCast = Builder.CreatePtrToInt(Scalar, Ty->getScalarType()); + return InsertElementInst::Create(Vec, NewCast, Index); } - Value *P = Builder.CreatePtrToInt(CI.getOperand(0), PtrTy); - return CastInst::CreateIntegerCast(P, Ty, /*isSigned=*/false); + return commonPointerCastTransforms(CI); } /// This input value (which is known to have vector type) is being zero extended @@ -1963,9 +2013,9 @@ Instruction *InstCombiner::visitPtrToInt(PtrToIntInst &CI) { /// Try to replace it with a shuffle (and vector/vector bitcast) if possible. /// /// The source and destination vector types may have different element types. -static Instruction *optimizeVectorResizeWithIntegerBitCasts(Value *InVal, - VectorType *DestTy, - InstCombiner &IC) { +static Instruction * +optimizeVectorResizeWithIntegerBitCasts(Value *InVal, VectorType *DestTy, + InstCombinerImpl &IC) { // We can only do this optimization if the output is a multiple of the input // element size, or the input is a multiple of the output element size. // Convert the input type to have the same element type as the output. @@ -1981,13 +2031,14 @@ static Instruction *optimizeVectorResizeWithIntegerBitCasts(Value *InVal, return nullptr; SrcTy = - FixedVectorType::get(DestTy->getElementType(), SrcTy->getNumElements()); + FixedVectorType::get(DestTy->getElementType(), + cast(SrcTy)->getNumElements()); InVal = IC.Builder.CreateBitCast(InVal, SrcTy); } bool IsBigEndian = IC.getDataLayout().isBigEndian(); - unsigned SrcElts = SrcTy->getNumElements(); - unsigned DestElts = DestTy->getNumElements(); + unsigned SrcElts = cast(SrcTy)->getNumElements(); + unsigned DestElts = cast(DestTy)->getNumElements(); assert(SrcElts != DestElts && "Element counts should be different."); @@ -2165,8 +2216,8 @@ static bool collectInsertionElements(Value *V, unsigned Shift, /// /// Into two insertelements that do "buildvector{%inc, %inc5}". static Value *optimizeIntegerToVectorInsertions(BitCastInst &CI, - InstCombiner &IC) { - VectorType *DestVecTy = cast(CI.getType()); + InstCombinerImpl &IC) { + auto *DestVecTy = cast(CI.getType()); Value *IntInput = CI.getOperand(0); SmallVector Elements(DestVecTy->getNumElements()); @@ -2194,7 +2245,7 @@ static Value *optimizeIntegerToVectorInsertions(BitCastInst &CI, /// vectors better than bitcasts of scalars because vector registers are /// usually not type-specific like scalar integer or scalar floating-point. static Instruction *canonicalizeBitCastExtElt(BitCastInst &BitCast, - InstCombiner &IC) { + InstCombinerImpl &IC) { // TODO: Create and use a pattern matcher for ExtractElementInst. auto *ExtElt = dyn_cast(BitCast.getOperand(0)); if (!ExtElt || !ExtElt->hasOneUse()) @@ -2206,8 +2257,7 @@ static Instruction *canonicalizeBitCastExtElt(BitCastInst &BitCast, if (!VectorType::isValidElementType(DestType)) return nullptr; - unsigned NumElts = ExtElt->getVectorOperandType()->getNumElements(); - auto *NewVecType = FixedVectorType::get(DestType, NumElts); + auto *NewVecType = VectorType::get(DestType, ExtElt->getVectorOperandType()); auto *NewBC = IC.Builder.CreateBitCast(ExtElt->getVectorOperand(), NewVecType, "bc"); return ExtractElementInst::Create(NewBC, ExtElt->getIndexOperand()); @@ -2270,12 +2320,11 @@ static Instruction *foldBitCastSelect(BitCastInst &BitCast, // A vector select must maintain the same number of elements in its operands. Type *CondTy = Cond->getType(); Type *DestTy = BitCast.getType(); - if (auto *CondVTy = dyn_cast(CondTy)) { - if (!DestTy->isVectorTy()) + if (auto *CondVTy = dyn_cast(CondTy)) + if (!DestTy->isVectorTy() || + CondVTy->getElementCount() != + cast(DestTy)->getElementCount()) return nullptr; - if (cast(DestTy)->getNumElements() != CondVTy->getNumElements()) - return nullptr; - } // FIXME: This transform is restricted from changing the select between // scalars and vectors to avoid backend problems caused by creating @@ -2320,7 +2369,8 @@ static bool hasStoreUsersOnly(CastInst &CI) { /// /// All the related PHI nodes can be replaced by new PHI nodes with type A. /// The uses of \p CI can be changed to the new PHI node corresponding to \p PN. -Instruction *InstCombiner::optimizeBitCastFromPhi(CastInst &CI, PHINode *PN) { +Instruction *InstCombinerImpl::optimizeBitCastFromPhi(CastInst &CI, + PHINode *PN) { // BitCast used by Store can be handled in InstCombineLoadStoreAlloca.cpp. if (hasStoreUsersOnly(CI)) return nullptr; @@ -2450,10 +2500,7 @@ Instruction *InstCombiner::optimizeBitCastFromPhi(CastInst &CI, PHINode *PN) { Instruction *RetVal = nullptr; for (auto *OldPN : OldPhiNodes) { PHINode *NewPN = NewPNodes[OldPN]; - for (auto It = OldPN->user_begin(), End = OldPN->user_end(); It != End; ) { - User *V = *It; - // We may remove this user, advance to avoid iterator invalidation. - ++It; + for (User *V : make_early_inc_range(OldPN->users())) { if (auto *SI = dyn_cast(V)) { assert(SI->isSimple() && SI->getOperand(0) == OldPN); Builder.SetInsertPoint(SI); @@ -2473,7 +2520,7 @@ Instruction *InstCombiner::optimizeBitCastFromPhi(CastInst &CI, PHINode *PN) { if (BCI == &CI) RetVal = I; } else if (auto *PHI = dyn_cast(V)) { - assert(OldPhiNodes.count(PHI) > 0); + assert(OldPhiNodes.contains(PHI)); (void) PHI; } else { llvm_unreachable("all uses should be handled"); @@ -2484,7 +2531,7 @@ Instruction *InstCombiner::optimizeBitCastFromPhi(CastInst &CI, PHINode *PN) { return RetVal; } -Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { +Instruction *InstCombinerImpl::visitBitCast(BitCastInst &CI) { // If the operands are integer typed then apply the integer transforms, // otherwise just apply the common ones. Value *Src = CI.getOperand(0); @@ -2608,12 +2655,11 @@ Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { // a bitcast to a vector with the same # elts. Value *ShufOp0 = Shuf->getOperand(0); Value *ShufOp1 = Shuf->getOperand(1); - unsigned NumShufElts = Shuf->getType()->getNumElements(); - unsigned NumSrcVecElts = - cast(ShufOp0->getType())->getNumElements(); + auto ShufElts = cast(Shuf->getType())->getElementCount(); + auto SrcVecElts = cast(ShufOp0->getType())->getElementCount(); if (Shuf->hasOneUse() && DestTy->isVectorTy() && - cast(DestTy)->getNumElements() == NumShufElts && - NumShufElts == NumSrcVecElts) { + cast(DestTy)->getElementCount() == ShufElts && + ShufElts == SrcVecElts) { BitCastInst *Tmp; // If either of the operands is a cast from CI.getType(), then // evaluating the shuffle in the casted destination's type will allow @@ -2636,8 +2682,9 @@ Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { // TODO: We should match the related pattern for bitreverse. if (DestTy->isIntegerTy() && DL.isLegalInteger(DestTy->getScalarSizeInBits()) && - SrcTy->getScalarSizeInBits() == 8 && NumShufElts % 2 == 0 && - Shuf->hasOneUse() && Shuf->isReverse()) { + SrcTy->getScalarSizeInBits() == 8 && + ShufElts.getKnownMinValue() % 2 == 0 && Shuf->hasOneUse() && + Shuf->isReverse()) { assert(ShufOp0->getType() == SrcTy && "Unexpected shuffle mask"); assert(isa(ShufOp1) && "Unexpected shuffle op"); Function *Bswap = @@ -2666,7 +2713,7 @@ Instruction *InstCombiner::visitBitCast(BitCastInst &CI) { return commonCastTransforms(CI); } -Instruction *InstCombiner::visitAddrSpaceCast(AddrSpaceCastInst &CI) { +Instruction *InstCombinerImpl::visitAddrSpaceCast(AddrSpaceCastInst &CI) { // If the destination pointer element type is not the same as the source's // first do a bitcast to the destination type, and then the addrspacecast. // This allows the cast to be exposed to other transforms. @@ -2677,11 +2724,9 @@ Instruction *InstCombiner::visitAddrSpaceCast(AddrSpaceCastInst &CI) { Type *DestElemTy = DestTy->getElementType(); if (SrcTy->getElementType() != DestElemTy) { Type *MidTy = PointerType::get(DestElemTy, SrcTy->getAddressSpace()); - if (VectorType *VT = dyn_cast(CI.getType())) { - // Handle vectors of pointers. - // FIXME: what should happen for scalable vectors? - MidTy = FixedVectorType::get(MidTy, VT->getNumElements()); - } + // Handle vectors of pointers. + if (VectorType *VT = dyn_cast(CI.getType())) + MidTy = VectorType::get(MidTy, VT->getElementCount()); Value *NewBitCast = Builder.CreateBitCast(Src, MidTy); return new AddrSpaceCastInst(NewBitCast, CI.getType()); diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index f1233b62445d..cd9a036179b6 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -24,6 +24,7 @@ #include "llvm/IR/PatternMatch.h" #include "llvm/Support/Debug.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" using namespace llvm; using namespace PatternMatch; @@ -95,45 +96,6 @@ static bool isSignTest(ICmpInst::Predicate &Pred, const APInt &C) { return false; } -/// Given a signed integer type and a set of known zero and one bits, compute -/// the maximum and minimum values that could have the specified known zero and -/// known one bits, returning them in Min/Max. -/// TODO: Move to method on KnownBits struct? -static void computeSignedMinMaxValuesFromKnownBits(const KnownBits &Known, - APInt &Min, APInt &Max) { - assert(Known.getBitWidth() == Min.getBitWidth() && - Known.getBitWidth() == Max.getBitWidth() && - "KnownZero, KnownOne and Min, Max must have equal bitwidth."); - APInt UnknownBits = ~(Known.Zero|Known.One); - - // The minimum value is when all unknown bits are zeros, EXCEPT for the sign - // bit if it is unknown. - Min = Known.One; - Max = Known.One|UnknownBits; - - if (UnknownBits.isNegative()) { // Sign bit is unknown - Min.setSignBit(); - Max.clearSignBit(); - } -} - -/// Given an unsigned integer type and a set of known zero and one bits, compute -/// the maximum and minimum values that could have the specified known zero and -/// known one bits, returning them in Min/Max. -/// TODO: Move to method on KnownBits struct? -static void computeUnsignedMinMaxValuesFromKnownBits(const KnownBits &Known, - APInt &Min, APInt &Max) { - assert(Known.getBitWidth() == Min.getBitWidth() && - Known.getBitWidth() == Max.getBitWidth() && - "Ty, KnownZero, KnownOne and Min, Max must have equal bitwidth."); - APInt UnknownBits = ~(Known.Zero|Known.One); - - // The minimum value is when the unknown bits are all zeros. - Min = Known.One; - // The maximum value is when the unknown bits are all ones. - Max = Known.One|UnknownBits; -} - /// This is called when we see this pattern: /// cmp pred (load (gep GV, ...)), cmpcst /// where GV is a global variable with a constant initializer. Try to simplify @@ -142,10 +104,10 @@ static void computeUnsignedMinMaxValuesFromKnownBits(const KnownBits &Known, /// /// If AndCst is non-null, then the loaded value is masked with that constant /// before doing the comparison. This handles cases like "A[i]&4 == 0". -Instruction *InstCombiner::foldCmpLoadFromIndexedGlobal(GetElementPtrInst *GEP, - GlobalVariable *GV, - CmpInst &ICI, - ConstantInt *AndCst) { +Instruction * +InstCombinerImpl::foldCmpLoadFromIndexedGlobal(GetElementPtrInst *GEP, + GlobalVariable *GV, CmpInst &ICI, + ConstantInt *AndCst) { Constant *Init = GV->getInitializer(); if (!isa(Init) && !isa(Init)) return nullptr; @@ -313,7 +275,7 @@ Instruction *InstCombiner::foldCmpLoadFromIndexedGlobal(GetElementPtrInst *GEP, if (!GEP->isInBounds()) { Type *IntPtrTy = DL.getIntPtrType(GEP->getType()); unsigned PtrSize = IntPtrTy->getIntegerBitWidth(); - if (Idx->getType()->getPrimitiveSizeInBits() > PtrSize) + if (Idx->getType()->getPrimitiveSizeInBits().getFixedSize() > PtrSize) Idx = Builder.CreateTrunc(Idx, IntPtrTy); } @@ -422,7 +384,7 @@ Instruction *InstCombiner::foldCmpLoadFromIndexedGlobal(GetElementPtrInst *GEP, /// /// If we can't emit an optimized form for this expression, this returns null. /// -static Value *evaluateGEPOffsetExpression(User *GEP, InstCombiner &IC, +static Value *evaluateGEPOffsetExpression(User *GEP, InstCombinerImpl &IC, const DataLayout &DL) { gep_type_iterator GTI = gep_type_begin(GEP); @@ -486,7 +448,8 @@ static Value *evaluateGEPOffsetExpression(User *GEP, InstCombiner &IC, // Cast to intptrty in case a truncation occurs. If an extension is needed, // we don't need to bother extending: the extension won't affect where the // computation crosses zero. - if (VariableIdx->getType()->getPrimitiveSizeInBits() > IntPtrWidth) { + if (VariableIdx->getType()->getPrimitiveSizeInBits().getFixedSize() > + IntPtrWidth) { VariableIdx = IC.Builder.CreateTrunc(VariableIdx, IntPtrTy); } return VariableIdx; @@ -539,7 +502,7 @@ static bool canRewriteGEPAsOffset(Value *Start, Value *Base, Value *V = WorkList.back(); - if (Explored.count(V) != 0) { + if (Explored.contains(V)) { WorkList.pop_back(); continue; } @@ -551,7 +514,7 @@ static bool canRewriteGEPAsOffset(Value *Start, Value *Base, return false; if (isa(V) || isa(V)) { - auto *CI = dyn_cast(V); + auto *CI = cast(V); if (!CI->isNoopCast(DL)) return false; @@ -841,9 +804,9 @@ static Instruction *transformToIndexedCompare(GEPOperator *GEPLHS, Value *RHS, /// Fold comparisons between a GEP instruction and something else. At this point /// we know that the GEP is on the LHS of the comparison. -Instruction *InstCombiner::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, - ICmpInst::Predicate Cond, - Instruction &I) { +Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, + ICmpInst::Predicate Cond, + Instruction &I) { // Don't transform signed compares of GEPs into index compares. Even if the // GEP is inbounds, the final add of the base pointer can have signed overflow // and would change the result of the icmp. @@ -897,8 +860,8 @@ Instruction *InstCombiner::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, // For vectors, we apply the same reasoning on a per-lane basis. auto *Base = GEPLHS->getPointerOperand(); if (GEPLHS->getType()->isVectorTy() && Base->getType()->isPointerTy()) { - int NumElts = cast(GEPLHS->getType())->getNumElements(); - Base = Builder.CreateVectorSplat(NumElts, Base); + auto EC = cast(GEPLHS->getType())->getElementCount(); + Base = Builder.CreateVectorSplat(EC, Base); } return new ICmpInst(Cond, Base, ConstantExpr::getPointerBitCastOrAddrSpaceCast( @@ -941,8 +904,8 @@ Instruction *InstCombiner::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, Type *LHSIndexTy = LOffset->getType(); Type *RHSIndexTy = ROffset->getType(); if (LHSIndexTy != RHSIndexTy) { - if (LHSIndexTy->getPrimitiveSizeInBits() < - RHSIndexTy->getPrimitiveSizeInBits()) { + if (LHSIndexTy->getPrimitiveSizeInBits().getFixedSize() < + RHSIndexTy->getPrimitiveSizeInBits().getFixedSize()) { ROffset = Builder.CreateTrunc(ROffset, LHSIndexTy); } else LOffset = Builder.CreateTrunc(LOffset, RHSIndexTy); @@ -1021,9 +984,9 @@ Instruction *InstCombiner::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, return transformToIndexedCompare(GEPLHS, RHS, Cond, DL); } -Instruction *InstCombiner::foldAllocaCmp(ICmpInst &ICI, - const AllocaInst *Alloca, - const Value *Other) { +Instruction *InstCombinerImpl::foldAllocaCmp(ICmpInst &ICI, + const AllocaInst *Alloca, + const Value *Other) { assert(ICI.isEquality() && "Cannot fold non-equality comparison."); // It would be tempting to fold away comparisons between allocas and any @@ -1099,8 +1062,8 @@ Instruction *InstCombiner::foldAllocaCmp(ICmpInst &ICI, } /// Fold "icmp pred (X+C), X". -Instruction *InstCombiner::foldICmpAddOpConst(Value *X, const APInt &C, - ICmpInst::Predicate Pred) { +Instruction *InstCombinerImpl::foldICmpAddOpConst(Value *X, const APInt &C, + ICmpInst::Predicate Pred) { // From this point on, we know that (X+C <= X) --> (X+C < X) because C != 0, // so the values can never be equal. Similarly for all other "or equals" // operators. @@ -1149,9 +1112,9 @@ Instruction *InstCombiner::foldICmpAddOpConst(Value *X, const APInt &C, /// Handle "(icmp eq/ne (ashr/lshr AP2, A), AP1)" -> /// (icmp eq/ne A, Log2(AP2/AP1)) -> /// (icmp eq/ne A, Log2(AP2) - Log2(AP1)). -Instruction *InstCombiner::foldICmpShrConstConst(ICmpInst &I, Value *A, - const APInt &AP1, - const APInt &AP2) { +Instruction *InstCombinerImpl::foldICmpShrConstConst(ICmpInst &I, Value *A, + const APInt &AP1, + const APInt &AP2) { assert(I.isEquality() && "Cannot fold icmp gt/lt"); auto getICmp = [&I](CmpInst::Predicate Pred, Value *LHS, Value *RHS) { @@ -1208,9 +1171,9 @@ Instruction *InstCombiner::foldICmpShrConstConst(ICmpInst &I, Value *A, /// Handle "(icmp eq/ne (shl AP2, A), AP1)" -> /// (icmp eq/ne A, TrailingZeros(AP1) - TrailingZeros(AP2)). -Instruction *InstCombiner::foldICmpShlConstConst(ICmpInst &I, Value *A, - const APInt &AP1, - const APInt &AP2) { +Instruction *InstCombinerImpl::foldICmpShlConstConst(ICmpInst &I, Value *A, + const APInt &AP1, + const APInt &AP2) { assert(I.isEquality() && "Cannot fold icmp gt/lt"); auto getICmp = [&I](CmpInst::Predicate Pred, Value *LHS, Value *RHS) { @@ -1254,7 +1217,7 @@ Instruction *InstCombiner::foldICmpShlConstConst(ICmpInst &I, Value *A, /// static Instruction *processUGT_ADDCST_ADD(ICmpInst &I, Value *A, Value *B, ConstantInt *CI2, ConstantInt *CI1, - InstCombiner &IC) { + InstCombinerImpl &IC) { // The transformation we're trying to do here is to transform this into an // llvm.sadd.with.overflow. To do this, we have to replace the original add // with a narrower add, and discard the add-with-constant that is part of the @@ -1340,7 +1303,7 @@ static Instruction *processUGT_ADDCST_ADD(ICmpInst &I, Value *A, Value *B, /// icmp eq/ne (urem/srem %x, %y), 0 /// iff %y is a power-of-two, we can replace this with a bit test: /// icmp eq/ne (and %x, (add %y, -1)), 0 -Instruction *InstCombiner::foldIRemByPowerOfTwoToBitTest(ICmpInst &I) { +Instruction *InstCombinerImpl::foldIRemByPowerOfTwoToBitTest(ICmpInst &I) { // This fold is only valid for equality predicates. if (!I.isEquality()) return nullptr; @@ -1359,7 +1322,7 @@ Instruction *InstCombiner::foldIRemByPowerOfTwoToBitTest(ICmpInst &I) { /// Fold equality-comparison between zero and any (maybe truncated) right-shift /// by one-less-than-bitwidth into a sign test on the original value. -Instruction *InstCombiner::foldSignBitTest(ICmpInst &I) { +Instruction *InstCombinerImpl::foldSignBitTest(ICmpInst &I) { Instruction *Val; ICmpInst::Predicate Pred; if (!I.isEquality() || !match(&I, m_ICmp(Pred, m_Instruction(Val), m_Zero()))) @@ -1390,7 +1353,7 @@ Instruction *InstCombiner::foldSignBitTest(ICmpInst &I) { } // Handle icmp pred X, 0 -Instruction *InstCombiner::foldICmpWithZero(ICmpInst &Cmp) { +Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) { CmpInst::Predicate Pred = Cmp.getPredicate(); if (!match(Cmp.getOperand(1), m_Zero())) return nullptr; @@ -1431,7 +1394,7 @@ Instruction *InstCombiner::foldICmpWithZero(ICmpInst &Cmp) { /// should be moved to some other helper and extended as noted below (it is also /// possible that code has been made unnecessary - do we canonicalize IR to /// overflow/saturating intrinsics or not?). -Instruction *InstCombiner::foldICmpWithConstant(ICmpInst &Cmp) { +Instruction *InstCombinerImpl::foldICmpWithConstant(ICmpInst &Cmp) { // Match the following pattern, which is a common idiom when writing // overflow-safe integer arithmetic functions. The source performs an addition // in wider type and explicitly checks for overflow using comparisons against @@ -1477,7 +1440,7 @@ Instruction *InstCombiner::foldICmpWithConstant(ICmpInst &Cmp) { } /// Canonicalize icmp instructions based on dominating conditions. -Instruction *InstCombiner::foldICmpWithDominatingICmp(ICmpInst &Cmp) { +Instruction *InstCombinerImpl::foldICmpWithDominatingICmp(ICmpInst &Cmp) { // This is a cheap/incomplete check for dominance - just match a single // predecessor with a conditional branch. BasicBlock *CmpBB = Cmp.getParent(); @@ -1547,9 +1510,9 @@ Instruction *InstCombiner::foldICmpWithDominatingICmp(ICmpInst &Cmp) { } /// Fold icmp (trunc X, Y), C. -Instruction *InstCombiner::foldICmpTruncConstant(ICmpInst &Cmp, - TruncInst *Trunc, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpTruncConstant(ICmpInst &Cmp, + TruncInst *Trunc, + const APInt &C) { ICmpInst::Predicate Pred = Cmp.getPredicate(); Value *X = Trunc->getOperand(0); if (C.isOneValue() && C.getBitWidth() > 1) { @@ -1580,9 +1543,9 @@ Instruction *InstCombiner::foldICmpTruncConstant(ICmpInst &Cmp, } /// Fold icmp (xor X, Y), C. -Instruction *InstCombiner::foldICmpXorConstant(ICmpInst &Cmp, - BinaryOperator *Xor, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpXorConstant(ICmpInst &Cmp, + BinaryOperator *Xor, + const APInt &C) { Value *X = Xor->getOperand(0); Value *Y = Xor->getOperand(1); const APInt *XorC; @@ -1612,15 +1575,13 @@ Instruction *InstCombiner::foldICmpXorConstant(ICmpInst &Cmp, if (Xor->hasOneUse()) { // (icmp u/s (xor X SignMask), C) -> (icmp s/u X, (xor C SignMask)) if (!Cmp.isEquality() && XorC->isSignMask()) { - Pred = Cmp.isSigned() ? Cmp.getUnsignedPredicate() - : Cmp.getSignedPredicate(); + Pred = Cmp.getFlippedSignednessPredicate(); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), C ^ *XorC)); } // (icmp u/s (xor X ~SignMask), C) -> (icmp s/u X, (xor C ~SignMask)) if (!Cmp.isEquality() && XorC->isMaxSignedValue()) { - Pred = Cmp.isSigned() ? Cmp.getUnsignedPredicate() - : Cmp.getSignedPredicate(); + Pred = Cmp.getFlippedSignednessPredicate(); Pred = Cmp.getSwappedPredicate(Pred); return new ICmpInst(Pred, X, ConstantInt::get(X->getType(), C ^ *XorC)); } @@ -1649,8 +1610,10 @@ Instruction *InstCombiner::foldICmpXorConstant(ICmpInst &Cmp, } /// Fold icmp (and (sh X, Y), C2), C1. -Instruction *InstCombiner::foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And, - const APInt &C1, const APInt &C2) { +Instruction *InstCombinerImpl::foldICmpAndShift(ICmpInst &Cmp, + BinaryOperator *And, + const APInt &C1, + const APInt &C2) { BinaryOperator *Shift = dyn_cast(And->getOperand(0)); if (!Shift || !Shift->isShift()) return nullptr; @@ -1733,9 +1696,9 @@ Instruction *InstCombiner::foldICmpAndShift(ICmpInst &Cmp, BinaryOperator *And, } /// Fold icmp (and X, C2), C1. -Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, - BinaryOperator *And, - const APInt &C1) { +Instruction *InstCombinerImpl::foldICmpAndConstConst(ICmpInst &Cmp, + BinaryOperator *And, + const APInt &C1) { bool isICMP_NE = Cmp.getPredicate() == ICmpInst::ICMP_NE; // For vectors: icmp ne (and X, 1), 0 --> trunc X to N x i1 @@ -1841,9 +1804,9 @@ Instruction *InstCombiner::foldICmpAndConstConst(ICmpInst &Cmp, } /// Fold icmp (and X, Y), C. -Instruction *InstCombiner::foldICmpAndConstant(ICmpInst &Cmp, - BinaryOperator *And, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpAndConstant(ICmpInst &Cmp, + BinaryOperator *And, + const APInt &C) { if (Instruction *I = foldICmpAndConstConst(Cmp, And, C)) return I; @@ -1883,7 +1846,7 @@ Instruction *InstCombiner::foldICmpAndConstant(ICmpInst &Cmp, if (ExactLogBase2 != -1 && DL.isLegalInteger(ExactLogBase2 + 1)) { Type *NTy = IntegerType::get(Cmp.getContext(), ExactLogBase2 + 1); if (auto *AndVTy = dyn_cast(And->getType())) - NTy = FixedVectorType::get(NTy, AndVTy->getNumElements()); + NTy = VectorType::get(NTy, AndVTy->getElementCount()); Value *Trunc = Builder.CreateTrunc(X, NTy); auto NewPred = Cmp.getPredicate() == CmpInst::ICMP_EQ ? CmpInst::ICMP_SGE : CmpInst::ICMP_SLT; @@ -1895,8 +1858,9 @@ Instruction *InstCombiner::foldICmpAndConstant(ICmpInst &Cmp, } /// Fold icmp (or X, Y), C. -Instruction *InstCombiner::foldICmpOrConstant(ICmpInst &Cmp, BinaryOperator *Or, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpOrConstant(ICmpInst &Cmp, + BinaryOperator *Or, + const APInt &C) { ICmpInst::Predicate Pred = Cmp.getPredicate(); if (C.isOneValue()) { // icmp slt signum(V) 1 --> icmp slt V, 1 @@ -1960,9 +1924,9 @@ Instruction *InstCombiner::foldICmpOrConstant(ICmpInst &Cmp, BinaryOperator *Or, } /// Fold icmp (mul X, Y), C. -Instruction *InstCombiner::foldICmpMulConstant(ICmpInst &Cmp, - BinaryOperator *Mul, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp, + BinaryOperator *Mul, + const APInt &C) { const APInt *MulC; if (!match(Mul->getOperand(1), m_APInt(MulC))) return nullptr; @@ -1977,6 +1941,21 @@ Instruction *InstCombiner::foldICmpMulConstant(ICmpInst &Cmp, Constant::getNullValue(Mul->getType())); } + // If the multiply does not wrap, try to divide the compare constant by the + // multiplication factor. + if (Cmp.isEquality() && !MulC->isNullValue()) { + // (mul nsw X, MulC) == C --> X == C /s MulC + if (Mul->hasNoSignedWrap() && C.srem(*MulC).isNullValue()) { + Constant *NewC = ConstantInt::get(Mul->getType(), C.sdiv(*MulC)); + return new ICmpInst(Pred, Mul->getOperand(0), NewC); + } + // (mul nuw X, MulC) == C --> X == C /u MulC + if (Mul->hasNoUnsignedWrap() && C.urem(*MulC).isNullValue()) { + Constant *NewC = ConstantInt::get(Mul->getType(), C.udiv(*MulC)); + return new ICmpInst(Pred, Mul->getOperand(0), NewC); + } + } + return nullptr; } @@ -2043,9 +2022,9 @@ static Instruction *foldICmpShlOne(ICmpInst &Cmp, Instruction *Shl, } /// Fold icmp (shl X, Y), C. -Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp, - BinaryOperator *Shl, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp, + BinaryOperator *Shl, + const APInt &C) { const APInt *ShiftVal; if (Cmp.isEquality() && match(Shl->getOperand(0), m_APInt(ShiftVal))) return foldICmpShlConstConst(Cmp, Shl->getOperand(1), C, *ShiftVal); @@ -2173,7 +2152,7 @@ Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp, DL.isLegalInteger(TypeBits - Amt)) { Type *TruncTy = IntegerType::get(Cmp.getContext(), TypeBits - Amt); if (auto *ShVTy = dyn_cast(ShType)) - TruncTy = FixedVectorType::get(TruncTy, ShVTy->getNumElements()); + TruncTy = VectorType::get(TruncTy, ShVTy->getElementCount()); Constant *NewC = ConstantInt::get(TruncTy, C.ashr(*ShiftAmt).trunc(TypeBits - Amt)); return new ICmpInst(Pred, Builder.CreateTrunc(X, TruncTy), NewC); @@ -2183,9 +2162,9 @@ Instruction *InstCombiner::foldICmpShlConstant(ICmpInst &Cmp, } /// Fold icmp ({al}shr X, Y), C. -Instruction *InstCombiner::foldICmpShrConstant(ICmpInst &Cmp, - BinaryOperator *Shr, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpShrConstant(ICmpInst &Cmp, + BinaryOperator *Shr, + const APInt &C) { // An exact shr only shifts out zero bits, so: // icmp eq/ne (shr X, Y), 0 --> icmp eq/ne X, 0 Value *X = Shr->getOperand(0); @@ -2231,6 +2210,21 @@ Instruction *InstCombiner::foldICmpShrConstant(ICmpInst &Cmp, (ShiftedC + 1).ashr(ShAmtVal) == (C + 1)) return new ICmpInst(Pred, X, ConstantInt::get(ShrTy, ShiftedC)); } + + // If the compare constant has significant bits above the lowest sign-bit, + // then convert an unsigned cmp to a test of the sign-bit: + // (ashr X, ShiftC) u> C --> X s< 0 + // (ashr X, ShiftC) u< C --> X s> -1 + if (C.getBitWidth() > 2 && C.getNumSignBits() <= ShAmtVal) { + if (Pred == CmpInst::ICMP_UGT) { + return new ICmpInst(CmpInst::ICMP_SLT, X, + ConstantInt::getNullValue(ShrTy)); + } + if (Pred == CmpInst::ICMP_ULT) { + return new ICmpInst(CmpInst::ICMP_SGT, X, + ConstantInt::getAllOnesValue(ShrTy)); + } + } } else { if (Pred == CmpInst::ICMP_ULT || (Pred == CmpInst::ICMP_UGT && IsExact)) { // icmp ult (lshr X, ShAmtC), C --> icmp ult X, (C << ShAmtC) @@ -2276,9 +2270,9 @@ Instruction *InstCombiner::foldICmpShrConstant(ICmpInst &Cmp, return nullptr; } -Instruction *InstCombiner::foldICmpSRemConstant(ICmpInst &Cmp, - BinaryOperator *SRem, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp, + BinaryOperator *SRem, + const APInt &C) { // Match an 'is positive' or 'is negative' comparison of remainder by a // constant power-of-2 value: // (X % pow2C) sgt/slt 0 @@ -2315,9 +2309,9 @@ Instruction *InstCombiner::foldICmpSRemConstant(ICmpInst &Cmp, } /// Fold icmp (udiv X, Y), C. -Instruction *InstCombiner::foldICmpUDivConstant(ICmpInst &Cmp, - BinaryOperator *UDiv, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp, + BinaryOperator *UDiv, + const APInt &C) { const APInt *C2; if (!match(UDiv->getOperand(0), m_APInt(C2))) return nullptr; @@ -2344,9 +2338,9 @@ Instruction *InstCombiner::foldICmpUDivConstant(ICmpInst &Cmp, } /// Fold icmp ({su}div X, Y), C. -Instruction *InstCombiner::foldICmpDivConstant(ICmpInst &Cmp, - BinaryOperator *Div, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp, + BinaryOperator *Div, + const APInt &C) { // Fold: icmp pred ([us]div X, C2), C -> range test // Fold this div into the comparison, producing a range check. // Determine, based on the divide type, what the range is being @@ -2514,9 +2508,9 @@ Instruction *InstCombiner::foldICmpDivConstant(ICmpInst &Cmp, } /// Fold icmp (sub X, Y), C. -Instruction *InstCombiner::foldICmpSubConstant(ICmpInst &Cmp, - BinaryOperator *Sub, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpSubConstant(ICmpInst &Cmp, + BinaryOperator *Sub, + const APInt &C) { Value *X = Sub->getOperand(0), *Y = Sub->getOperand(1); ICmpInst::Predicate Pred = Cmp.getPredicate(); const APInt *C2; @@ -2576,9 +2570,9 @@ Instruction *InstCombiner::foldICmpSubConstant(ICmpInst &Cmp, } /// Fold icmp (add X, Y), C. -Instruction *InstCombiner::foldICmpAddConstant(ICmpInst &Cmp, - BinaryOperator *Add, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp, + BinaryOperator *Add, + const APInt &C) { Value *Y = Add->getOperand(1); const APInt *C2; if (Cmp.isEquality() || !match(Y, m_APInt(C2))) @@ -2642,10 +2636,10 @@ Instruction *InstCombiner::foldICmpAddConstant(ICmpInst &Cmp, return nullptr; } -bool InstCombiner::matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, - Value *&RHS, ConstantInt *&Less, - ConstantInt *&Equal, - ConstantInt *&Greater) { +bool InstCombinerImpl::matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, + Value *&RHS, ConstantInt *&Less, + ConstantInt *&Equal, + ConstantInt *&Greater) { // TODO: Generalize this to work with other comparison idioms or ensure // they get canonicalized into this form. @@ -2682,7 +2676,8 @@ bool InstCombiner::matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, if (PredB == ICmpInst::ICMP_SGT && isa(RHS2)) { // x sgt C-1 <--> x sge C <--> not(x slt C) auto FlippedStrictness = - getFlippedStrictnessPredicateAndConstant(PredB, cast(RHS2)); + InstCombiner::getFlippedStrictnessPredicateAndConstant( + PredB, cast(RHS2)); if (!FlippedStrictness) return false; assert(FlippedStrictness->first == ICmpInst::ICMP_SGE && "Sanity check"); @@ -2694,9 +2689,9 @@ bool InstCombiner::matchThreeWayIntCompare(SelectInst *SI, Value *&LHS, return PredB == ICmpInst::ICMP_SLT && RHS == RHS2; } -Instruction *InstCombiner::foldICmpSelectConstant(ICmpInst &Cmp, - SelectInst *Select, - ConstantInt *C) { +Instruction *InstCombinerImpl::foldICmpSelectConstant(ICmpInst &Cmp, + SelectInst *Select, + ConstantInt *C) { assert(C && "Cmp RHS should be a constant int!"); // If we're testing a constant value against the result of a three way @@ -2794,7 +2789,7 @@ static Instruction *foldICmpBitCast(ICmpInst &Cmp, const APInt *C; bool TrueIfSigned; if (match(Op1, m_APInt(C)) && Bitcast->hasOneUse() && - isSignBitCheck(Pred, *C, TrueIfSigned)) { + InstCombiner::isSignBitCheck(Pred, *C, TrueIfSigned)) { if (match(BCSrcOp, m_FPExt(m_Value(X))) || match(BCSrcOp, m_FPTrunc(m_Value(X)))) { // (bitcast (fpext/fptrunc X)) to iX) < 0 --> (bitcast X to iY) < 0 @@ -2806,7 +2801,7 @@ static Instruction *foldICmpBitCast(ICmpInst &Cmp, Type *NewType = Builder.getIntNTy(XType->getScalarSizeInBits()); if (auto *XVTy = dyn_cast(XType)) - NewType = FixedVectorType::get(NewType, XVTy->getNumElements()); + NewType = VectorType::get(NewType, XVTy->getElementCount()); Value *NewBitcast = Builder.CreateBitCast(X, NewType); if (TrueIfSigned) return new ICmpInst(ICmpInst::ICMP_SLT, NewBitcast, @@ -2870,7 +2865,7 @@ static Instruction *foldICmpBitCast(ICmpInst &Cmp, /// Try to fold integer comparisons with a constant operand: icmp Pred X, C /// where X is some kind of instruction. -Instruction *InstCombiner::foldICmpInstWithConstant(ICmpInst &Cmp) { +Instruction *InstCombinerImpl::foldICmpInstWithConstant(ICmpInst &Cmp) { const APInt *C; if (!match(Cmp.getOperand(1), m_APInt(C))) return nullptr; @@ -2955,9 +2950,8 @@ Instruction *InstCombiner::foldICmpInstWithConstant(ICmpInst &Cmp) { /// Fold an icmp equality instruction with binary operator LHS and constant RHS: /// icmp eq/ne BO, C. -Instruction *InstCombiner::foldICmpBinOpEqualityWithConstant(ICmpInst &Cmp, - BinaryOperator *BO, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant( + ICmpInst &Cmp, BinaryOperator *BO, const APInt &C) { // TODO: Some of these folds could work with arbitrary constants, but this // function is limited to scalar and vector splat constants. if (!Cmp.isEquality()) @@ -3047,17 +3041,6 @@ Instruction *InstCombiner::foldICmpBinOpEqualityWithConstant(ICmpInst &Cmp, } break; } - case Instruction::Mul: - if (C.isNullValue() && BO->hasNoSignedWrap()) { - const APInt *BOC; - if (match(BOp1, m_APInt(BOC)) && !BOC->isNullValue()) { - // The trivial case (mul X, 0) is handled by InstSimplify. - // General case : (mul X, C) != 0 iff X != 0 - // (mul X, C) == 0 iff X == 0 - return new ICmpInst(Pred, BOp0, Constant::getNullValue(RHS->getType())); - } - } - break; case Instruction::UDiv: if (C.isNullValue()) { // (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A) @@ -3072,12 +3055,19 @@ Instruction *InstCombiner::foldICmpBinOpEqualityWithConstant(ICmpInst &Cmp, } /// Fold an equality icmp with LLVM intrinsic and constant operand. -Instruction *InstCombiner::foldICmpEqIntrinsicWithConstant(ICmpInst &Cmp, - IntrinsicInst *II, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpEqIntrinsicWithConstant( + ICmpInst &Cmp, IntrinsicInst *II, const APInt &C) { Type *Ty = II->getType(); unsigned BitWidth = C.getBitWidth(); switch (II->getIntrinsicID()) { + case Intrinsic::abs: + // abs(A) == 0 -> A == 0 + // abs(A) == INT_MIN -> A == INT_MIN + if (C.isNullValue() || C.isMinSignedValue()) + return new ICmpInst(Cmp.getPredicate(), II->getArgOperand(0), + ConstantInt::get(Ty, C)); + break; + case Intrinsic::bswap: // bswap(A) == C -> A == bswap(C) return new ICmpInst(Cmp.getPredicate(), II->getArgOperand(0), @@ -3145,18 +3135,31 @@ Instruction *InstCombiner::foldICmpEqIntrinsicWithConstant(ICmpInst &Cmp, } /// Fold an icmp with LLVM intrinsic and constant operand: icmp Pred II, C. -Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, - IntrinsicInst *II, - const APInt &C) { +Instruction *InstCombinerImpl::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, + IntrinsicInst *II, + const APInt &C) { if (Cmp.isEquality()) return foldICmpEqIntrinsicWithConstant(Cmp, II, C); Type *Ty = II->getType(); unsigned BitWidth = C.getBitWidth(); + ICmpInst::Predicate Pred = Cmp.getPredicate(); switch (II->getIntrinsicID()) { + case Intrinsic::ctpop: { + // (ctpop X > BitWidth - 1) --> X == -1 + Value *X = II->getArgOperand(0); + if (C == BitWidth - 1 && Pred == ICmpInst::ICMP_UGT) + return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, X, + ConstantInt::getAllOnesValue(Ty)); + // (ctpop X < BitWidth) --> X != -1 + if (C == BitWidth && Pred == ICmpInst::ICMP_ULT) + return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, X, + ConstantInt::getAllOnesValue(Ty)); + break; + } case Intrinsic::ctlz: { // ctlz(0bXXXXXXXX) > 3 -> 0bXXXXXXXX < 0b00010000 - if (Cmp.getPredicate() == ICmpInst::ICMP_UGT && C.ult(BitWidth)) { + if (Pred == ICmpInst::ICMP_UGT && C.ult(BitWidth)) { unsigned Num = C.getLimitedValue(); APInt Limit = APInt::getOneBitSet(BitWidth, BitWidth - Num - 1); return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_ULT, @@ -3164,8 +3167,7 @@ Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, } // ctlz(0bXXXXXXXX) < 3 -> 0bXXXXXXXX > 0b00011111 - if (Cmp.getPredicate() == ICmpInst::ICMP_ULT && - C.uge(1) && C.ule(BitWidth)) { + if (Pred == ICmpInst::ICMP_ULT && C.uge(1) && C.ule(BitWidth)) { unsigned Num = C.getLimitedValue(); APInt Limit = APInt::getLowBitsSet(BitWidth, BitWidth - Num); return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_UGT, @@ -3179,7 +3181,7 @@ Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, return nullptr; // cttz(0bXXXXXXXX) > 3 -> 0bXXXXXXXX & 0b00001111 == 0 - if (Cmp.getPredicate() == ICmpInst::ICMP_UGT && C.ult(BitWidth)) { + if (Pred == ICmpInst::ICMP_UGT && C.ult(BitWidth)) { APInt Mask = APInt::getLowBitsSet(BitWidth, C.getLimitedValue() + 1); return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_EQ, Builder.CreateAnd(II->getArgOperand(0), Mask), @@ -3187,8 +3189,7 @@ Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, } // cttz(0bXXXXXXXX) < 3 -> 0bXXXXXXXX & 0b00000111 != 0 - if (Cmp.getPredicate() == ICmpInst::ICMP_ULT && - C.uge(1) && C.ule(BitWidth)) { + if (Pred == ICmpInst::ICMP_ULT && C.uge(1) && C.ule(BitWidth)) { APInt Mask = APInt::getLowBitsSet(BitWidth, C.getLimitedValue()); return CmpInst::Create(Instruction::ICmp, ICmpInst::ICMP_NE, Builder.CreateAnd(II->getArgOperand(0), Mask), @@ -3204,7 +3205,7 @@ Instruction *InstCombiner::foldICmpIntrinsicWithConstant(ICmpInst &Cmp, } /// Handle icmp with constant (but not simple integer constant) RHS. -Instruction *InstCombiner::foldICmpInstWithConstantNotInt(ICmpInst &I) { +Instruction *InstCombinerImpl::foldICmpInstWithConstantNotInt(ICmpInst &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Constant *RHSC = dyn_cast(Op1); Instruction *LHSI = dyn_cast(Op0); @@ -3383,8 +3384,8 @@ static Value *foldICmpWithLowBitMaskedVal(ICmpInst &I, // those elements by copying an existing, defined, and safe scalar constant. Type *OpTy = M->getType(); auto *VecC = dyn_cast(M); - if (OpTy->isVectorTy() && VecC && VecC->containsUndefElement()) { - auto *OpVTy = cast(OpTy); + auto *OpVTy = dyn_cast(OpTy); + if (OpVTy && VecC && VecC->containsUndefOrPoisonElement()) { Constant *SafeReplacementConstant = nullptr; for (unsigned i = 0, e = OpVTy->getNumElements(); i != e; ++i) { if (!isa(VecC->getAggregateElement(i))) { @@ -3650,7 +3651,7 @@ foldShiftIntoShiftInAnotherHandOfAndInICmp(ICmpInst &I, const SimplifyQuery SQ, /// @llvm.umul.with.overflow(x, y) plus extraction of overflow bit /// Note that the comparison is commutative, while inverted (u>=, ==) predicate /// will mean that we are looking for the opposite answer. -Value *InstCombiner::foldUnsignedMultiplicationOverflowCheck(ICmpInst &I) { +Value *InstCombinerImpl::foldUnsignedMultiplicationOverflowCheck(ICmpInst &I) { ICmpInst::Predicate Pred; Value *X, *Y; Instruction *Mul; @@ -3712,11 +3713,28 @@ Value *InstCombiner::foldUnsignedMultiplicationOverflowCheck(ICmpInst &I) { return Res; } +static Instruction *foldICmpXNegX(ICmpInst &I) { + CmpInst::Predicate Pred; + Value *X; + if (!match(&I, m_c_ICmp(Pred, m_NSWNeg(m_Value(X)), m_Deferred(X)))) + return nullptr; + + if (ICmpInst::isSigned(Pred)) + Pred = ICmpInst::getSwappedPredicate(Pred); + else if (ICmpInst::isUnsigned(Pred)) + Pred = ICmpInst::getSignedPredicate(Pred); + // else for equality-comparisons just keep the predicate. + + return ICmpInst::Create(Instruction::ICmp, Pred, X, + Constant::getNullValue(X->getType()), I.getName()); +} + /// Try to fold icmp (binop), X or icmp X, (binop). /// TODO: A large part of this logic is duplicated in InstSimplify's /// simplifyICmpWithBinOp(). We should be able to share that and avoid the code /// duplication. -Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I, const SimplifyQuery &SQ) { +Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I, + const SimplifyQuery &SQ) { const SimplifyQuery Q = SQ.getWithInstruction(&I); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); @@ -3726,6 +3744,9 @@ Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I, const SimplifyQuery &SQ) { if (!BO0 && !BO1) return nullptr; + if (Instruction *NewICmp = foldICmpXNegX(I)) + return NewICmp; + const CmpInst::Predicate Pred = I.getPredicate(); Value *X; @@ -3946,6 +3967,19 @@ Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I, const SimplifyQuery &SQ) { ConstantExpr::getNeg(RHSC)); } + { + // Try to remove shared constant multiplier from equality comparison: + // X * C == Y * C (with no overflowing/aliasing) --> X == Y + Value *X, *Y; + const APInt *C; + if (match(Op0, m_Mul(m_Value(X), m_APInt(C))) && *C != 0 && + match(Op1, m_Mul(m_Value(Y), m_SpecificInt(*C))) && I.isEquality()) + if (!C->countTrailingZeros() || + (BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap()) || + (BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap())) + return new ICmpInst(Pred, X, Y); + } + BinaryOperator *SRem = nullptr; // icmp (srem X, Y), Y if (BO0 && BO0->getOpcode() == Instruction::SRem && Op1 == BO0->getOperand(1)) @@ -3990,15 +4024,13 @@ Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I, const SimplifyQuery &SQ) { if (match(BO0->getOperand(1), m_APInt(C))) { // icmp u/s (a ^ signmask), (b ^ signmask) --> icmp s/u a, b if (C->isSignMask()) { - ICmpInst::Predicate NewPred = - I.isSigned() ? I.getUnsignedPredicate() : I.getSignedPredicate(); + ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate(); return new ICmpInst(NewPred, BO0->getOperand(0), BO1->getOperand(0)); } // icmp u/s (a ^ maxsignval), (b ^ maxsignval) --> icmp s/u' a, b if (BO0->getOpcode() == Instruction::Xor && C->isMaxSignedValue()) { - ICmpInst::Predicate NewPred = - I.isSigned() ? I.getUnsignedPredicate() : I.getSignedPredicate(); + ICmpInst::Predicate NewPred = I.getFlippedSignednessPredicate(); NewPred = I.getSwappedPredicate(NewPred); return new ICmpInst(NewPred, BO0->getOperand(0), BO1->getOperand(0)); } @@ -4022,10 +4054,6 @@ Instruction *InstCombiner::foldICmpBinOp(ICmpInst &I, const SimplifyQuery &SQ) { Value *And2 = Builder.CreateAnd(BO1->getOperand(0), Mask); return new ICmpInst(Pred, And1, And2); } - // If there are no trailing zeros in the multiplier, just eliminate - // the multiplies (no masking is needed): - // icmp eq/ne (X * C), (Y * C) --> icmp eq/ne X, Y - return new ICmpInst(Pred, BO0->getOperand(0), BO1->getOperand(0)); } break; } @@ -4170,7 +4198,7 @@ static Instruction *foldICmpWithMinMax(ICmpInst &Cmp) { return nullptr; } -Instruction *InstCombiner::foldICmpEquality(ICmpInst &I) { +Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) { if (!I.isEquality()) return nullptr; @@ -4438,7 +4466,7 @@ static Instruction *foldICmpWithZextOrSext(ICmpInst &ICmp, } /// Handle icmp (cast x), (cast or constant). -Instruction *InstCombiner::foldICmpWithCastOp(ICmpInst &ICmp) { +Instruction *InstCombinerImpl::foldICmpWithCastOp(ICmpInst &ICmp) { auto *CastOp0 = dyn_cast(ICmp.getOperand(0)); if (!CastOp0) return nullptr; @@ -4493,9 +4521,10 @@ static bool isNeutralValue(Instruction::BinaryOps BinaryOp, Value *RHS) { } } -OverflowResult InstCombiner::computeOverflow( - Instruction::BinaryOps BinaryOp, bool IsSigned, - Value *LHS, Value *RHS, Instruction *CxtI) const { +OverflowResult +InstCombinerImpl::computeOverflow(Instruction::BinaryOps BinaryOp, + bool IsSigned, Value *LHS, Value *RHS, + Instruction *CxtI) const { switch (BinaryOp) { default: llvm_unreachable("Unsupported binary op"); @@ -4517,9 +4546,11 @@ OverflowResult InstCombiner::computeOverflow( } } -bool InstCombiner::OptimizeOverflowCheck( - Instruction::BinaryOps BinaryOp, bool IsSigned, Value *LHS, Value *RHS, - Instruction &OrigI, Value *&Result, Constant *&Overflow) { +bool InstCombinerImpl::OptimizeOverflowCheck(Instruction::BinaryOps BinaryOp, + bool IsSigned, Value *LHS, + Value *RHS, Instruction &OrigI, + Value *&Result, + Constant *&Overflow) { if (OrigI.isCommutative() && isa(LHS) && !isa(RHS)) std::swap(LHS, RHS); @@ -4529,9 +4560,13 @@ bool InstCombiner::OptimizeOverflowCheck( // compare. Builder.SetInsertPoint(&OrigI); + Type *OverflowTy = Type::getInt1Ty(LHS->getContext()); + if (auto *LHSTy = dyn_cast(LHS->getType())) + OverflowTy = VectorType::get(OverflowTy, LHSTy->getElementCount()); + if (isNeutralValue(BinaryOp, RHS)) { Result = LHS; - Overflow = Builder.getFalse(); + Overflow = ConstantInt::getFalse(OverflowTy); return true; } @@ -4542,12 +4577,12 @@ bool InstCombiner::OptimizeOverflowCheck( case OverflowResult::AlwaysOverflowsHigh: Result = Builder.CreateBinOp(BinaryOp, LHS, RHS); Result->takeName(&OrigI); - Overflow = Builder.getTrue(); + Overflow = ConstantInt::getTrue(OverflowTy); return true; case OverflowResult::NeverOverflows: Result = Builder.CreateBinOp(BinaryOp, LHS, RHS); Result->takeName(&OrigI); - Overflow = Builder.getFalse(); + Overflow = ConstantInt::getFalse(OverflowTy); if (auto *Inst = dyn_cast(Result)) { if (IsSigned) Inst->setHasNoSignedWrap(); @@ -4575,7 +4610,8 @@ bool InstCombiner::OptimizeOverflowCheck( /// \returns Instruction which must replace the compare instruction, NULL if no /// replacement required. static Instruction *processUMulZExtIdiom(ICmpInst &I, Value *MulVal, - Value *OtherVal, InstCombiner &IC) { + Value *OtherVal, + InstCombinerImpl &IC) { // Don't bother doing this transformation for pointers, don't do it for // vectors. if (!isa(MulVal->getType())) @@ -4723,15 +4759,14 @@ static Instruction *processUMulZExtIdiom(ICmpInst &I, Value *MulVal, Function *F = Intrinsic::getDeclaration( I.getModule(), Intrinsic::umul_with_overflow, MulType); CallInst *Call = Builder.CreateCall(F, {MulA, MulB}, "umul"); - IC.Worklist.push(MulInstr); + IC.addToWorklist(MulInstr); // If there are uses of mul result other than the comparison, we know that // they are truncation or binary AND. Change them to use result of // mul.with.overflow and adjust properly mask/size. if (MulVal->hasNUsesOrMore(2)) { Value *Mul = Builder.CreateExtractValue(Call, 0, "umul.value"); - for (auto UI = MulVal->user_begin(), UE = MulVal->user_end(); UI != UE;) { - User *U = *UI++; + for (User *U : make_early_inc_range(MulVal->users())) { if (U == &I || U == OtherVal) continue; if (TruncInst *TI = dyn_cast(U)) { @@ -4750,11 +4785,11 @@ static Instruction *processUMulZExtIdiom(ICmpInst &I, Value *MulVal, } else { llvm_unreachable("Unexpected Binary operation"); } - IC.Worklist.push(cast(U)); + IC.addToWorklist(cast(U)); } } if (isa(OtherVal)) - IC.Worklist.push(cast(OtherVal)); + IC.addToWorklist(cast(OtherVal)); // The original icmp gets replaced with the overflow value, maybe inverted // depending on predicate. @@ -4799,7 +4834,7 @@ static APInt getDemandedBitsLHSMask(ICmpInst &I, unsigned BitWidth) { // If this is a normal comparison, it demands all bits. If it is a sign bit // comparison, it only demands the sign bit. bool UnusedBit; - if (isSignBitCheck(I.getPredicate(), *RHS, UnusedBit)) + if (InstCombiner::isSignBitCheck(I.getPredicate(), *RHS, UnusedBit)) return APInt::getSignMask(BitWidth); switch (I.getPredicate()) { @@ -4856,9 +4891,9 @@ static bool swapMayExposeCSEOpportunities(const Value *Op0, const Value *Op1) { /// \return true when \p UI is the only use of \p DI in the parent block /// and all other uses of \p DI are in blocks dominated by \p DB. /// -bool InstCombiner::dominatesAllUses(const Instruction *DI, - const Instruction *UI, - const BasicBlock *DB) const { +bool InstCombinerImpl::dominatesAllUses(const Instruction *DI, + const Instruction *UI, + const BasicBlock *DB) const { assert(DI && UI && "Instruction not defined\n"); // Ignore incomplete definitions. if (!DI->getParent()) @@ -4931,9 +4966,9 @@ static bool isChainSelectCmpBranch(const SelectInst *SI) { /// major restriction since a NE compare should be 'normalized' to an equal /// compare, which usually happens in the combiner and test case /// select-cmp-br.ll checks for it. -bool InstCombiner::replacedSelectWithOperand(SelectInst *SI, - const ICmpInst *Icmp, - const unsigned SIOpd) { +bool InstCombinerImpl::replacedSelectWithOperand(SelectInst *SI, + const ICmpInst *Icmp, + const unsigned SIOpd) { assert((SIOpd == 1 || SIOpd == 2) && "Invalid select operand!"); if (isChainSelectCmpBranch(SI) && Icmp->getPredicate() == ICmpInst::ICMP_EQ) { BasicBlock *Succ = SI->getParent()->getTerminator()->getSuccessor(1); @@ -4959,7 +4994,7 @@ bool InstCombiner::replacedSelectWithOperand(SelectInst *SI, /// Try to fold the comparison based on range information we can get by checking /// whether bits are known to be zero or one in the inputs. -Instruction *InstCombiner::foldICmpUsingKnownBits(ICmpInst &I) { +Instruction *InstCombinerImpl::foldICmpUsingKnownBits(ICmpInst &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Type *Ty = Op0->getType(); ICmpInst::Predicate Pred = I.getPredicate(); @@ -4990,11 +5025,15 @@ Instruction *InstCombiner::foldICmpUsingKnownBits(ICmpInst &I) { APInt Op0Min(BitWidth, 0), Op0Max(BitWidth, 0); APInt Op1Min(BitWidth, 0), Op1Max(BitWidth, 0); if (I.isSigned()) { - computeSignedMinMaxValuesFromKnownBits(Op0Known, Op0Min, Op0Max); - computeSignedMinMaxValuesFromKnownBits(Op1Known, Op1Min, Op1Max); + Op0Min = Op0Known.getSignedMinValue(); + Op0Max = Op0Known.getSignedMaxValue(); + Op1Min = Op1Known.getSignedMinValue(); + Op1Max = Op1Known.getSignedMaxValue(); } else { - computeUnsignedMinMaxValuesFromKnownBits(Op0Known, Op0Min, Op0Max); - computeUnsignedMinMaxValuesFromKnownBits(Op1Known, Op1Min, Op1Max); + Op0Min = Op0Known.getMinValue(); + Op0Max = Op0Known.getMaxValue(); + Op1Min = Op1Known.getMinValue(); + Op1Max = Op1Known.getMaxValue(); } // If Min and Max are known to be the same, then SimplifyDemandedBits figured @@ -5012,11 +5051,9 @@ Instruction *InstCombiner::foldICmpUsingKnownBits(ICmpInst &I) { llvm_unreachable("Unknown icmp opcode!"); case ICmpInst::ICMP_EQ: case ICmpInst::ICMP_NE: { - if (Op0Max.ult(Op1Min) || Op0Min.ugt(Op1Max)) { - return Pred == CmpInst::ICMP_EQ - ? replaceInstUsesWith(I, ConstantInt::getFalse(I.getType())) - : replaceInstUsesWith(I, ConstantInt::getTrue(I.getType())); - } + if (Op0Max.ult(Op1Min) || Op0Min.ugt(Op1Max)) + return replaceInstUsesWith( + I, ConstantInt::getBool(I.getType(), Pred == CmpInst::ICMP_NE)); // If all bits are known zero except for one, then we know at most one bit // is set. If the comparison is against zero, then this is a check to see if @@ -5186,8 +5223,8 @@ Instruction *InstCombiner::foldICmpUsingKnownBits(ICmpInst &I) { } llvm::Optional> -llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, - Constant *C) { +InstCombiner::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, + Constant *C) { assert(ICmpInst::isRelational(Pred) && ICmpInst::isIntPredicate(Pred) && "Only for relational integer predicates."); @@ -5209,8 +5246,8 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, // Bail out if the constant can't be safely incremented/decremented. if (!ConstantIsOk(CI)) return llvm::None; - } else if (auto *VTy = dyn_cast(Type)) { - unsigned NumElts = VTy->getNumElements(); + } else if (auto *FVTy = dyn_cast(Type)) { + unsigned NumElts = FVTy->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) { Constant *Elt = C->getAggregateElement(i); if (!Elt) @@ -5236,7 +5273,8 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, // It may not be safe to change a compare predicate in the presence of // undefined elements, so replace those elements with the first safe constant // that we found. - if (C->containsUndefElement()) { + // TODO: in case of poison, it is safe; let's replace undefs only. + if (C->containsUndefOrPoisonElement()) { assert(SafeReplacementConstant && "Replacement constant not set"); C = Constant::replaceUndefsWith(C, SafeReplacementConstant); } @@ -5256,7 +5294,7 @@ llvm::getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, static ICmpInst *canonicalizeCmpWithConstant(ICmpInst &I) { ICmpInst::Predicate Pred = I.getPredicate(); if (ICmpInst::isEquality(Pred) || !ICmpInst::isIntPredicate(Pred) || - isCanonicalPredicate(Pred)) + InstCombiner::isCanonicalPredicate(Pred)) return nullptr; Value *Op0 = I.getOperand(0); @@ -5265,7 +5303,8 @@ static ICmpInst *canonicalizeCmpWithConstant(ICmpInst &I) { if (!Op1C) return nullptr; - auto FlippedStrictness = getFlippedStrictnessPredicateAndConstant(Pred, Op1C); + auto FlippedStrictness = + InstCombiner::getFlippedStrictnessPredicateAndConstant(Pred, Op1C); if (!FlippedStrictness) return nullptr; @@ -5274,14 +5313,14 @@ static ICmpInst *canonicalizeCmpWithConstant(ICmpInst &I) { /// If we have a comparison with a non-canonical predicate, if we can update /// all the users, invert the predicate and adjust all the users. -static CmpInst *canonicalizeICmpPredicate(CmpInst &I) { +CmpInst *InstCombinerImpl::canonicalizeICmpPredicate(CmpInst &I) { // Is the predicate already canonical? CmpInst::Predicate Pred = I.getPredicate(); - if (isCanonicalPredicate(Pred)) + if (InstCombiner::isCanonicalPredicate(Pred)) return nullptr; // Can all users be adjusted to predicate inversion? - if (!canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr)) + if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr)) return nullptr; // Ok, we can canonicalize comparison! @@ -5289,26 +5328,8 @@ static CmpInst *canonicalizeICmpPredicate(CmpInst &I) { I.setPredicate(CmpInst::getInversePredicate(Pred)); I.setName(I.getName() + ".not"); - // And now let's adjust every user. - for (User *U : I.users()) { - switch (cast(U)->getOpcode()) { - case Instruction::Select: { - auto *SI = cast(U); - SI->swapValues(); - SI->swapProfMetadata(); - break; - } - case Instruction::Br: - cast(U)->swapSuccessors(); // swaps prof metadata too - break; - case Instruction::Xor: - U->replaceAllUsesWith(&I); - break; - default: - llvm_unreachable("Got unexpected user - out of sync with " - "canFreelyInvertAllUsersOf() ?"); - } - } + // And, adapt users. + freelyInvertAllUsersOf(&I); return &I; } @@ -5510,7 +5531,7 @@ static Instruction *foldICmpOfUAddOv(ICmpInst &I) { return ExtractValueInst::Create(UAddOv, 1); } -Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { +Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) { bool Changed = false; const SimplifyQuery Q = SQ.getWithInstruction(&I); Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); @@ -5634,10 +5655,10 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { // Try to optimize equality comparisons against alloca-based pointers. if (Op0->getType()->isPointerTy() && I.isEquality()) { assert(Op1->getType()->isPointerTy() && "Comparing pointer with non-pointer?"); - if (auto *Alloca = dyn_cast(GetUnderlyingObject(Op0, DL))) + if (auto *Alloca = dyn_cast(getUnderlyingObject(Op0))) if (Instruction *New = foldAllocaCmp(I, Alloca, Op1)) return New; - if (auto *Alloca = dyn_cast(GetUnderlyingObject(Op1, DL))) + if (auto *Alloca = dyn_cast(getUnderlyingObject(Op1))) if (Instruction *New = foldAllocaCmp(I, Alloca, Op0)) return New; } @@ -5748,8 +5769,9 @@ Instruction *InstCombiner::visitICmpInst(ICmpInst &I) { } /// Fold fcmp ([us]itofp x, cst) if possible. -Instruction *InstCombiner::foldFCmpIntToFPConst(FCmpInst &I, Instruction *LHSI, - Constant *RHSC) { +Instruction *InstCombinerImpl::foldFCmpIntToFPConst(FCmpInst &I, + Instruction *LHSI, + Constant *RHSC) { if (!isa(RHSC)) return nullptr; const APFloat &RHS = cast(RHSC)->getValueAPF(); @@ -6034,9 +6056,9 @@ static Instruction *foldFCmpReciprocalAndZero(FCmpInst &I, Instruction *LHSI, } /// Optimize fabs(X) compared with zero. -static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombiner &IC) { +static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombinerImpl &IC) { Value *X; - if (!match(I.getOperand(0), m_Intrinsic(m_Value(X))) || + if (!match(I.getOperand(0), m_FAbs(m_Value(X))) || !match(I.getOperand(1), m_PosZeroFP())) return nullptr; @@ -6096,7 +6118,7 @@ static Instruction *foldFabsWithFcmpZero(FCmpInst &I, InstCombiner &IC) { } } -Instruction *InstCombiner::visitFCmpInst(FCmpInst &I) { +Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) { bool Changed = false; /// Orders the operands of the compare so that they are listed from most diff --git a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h index f918dc7198ca..79e9d5c46c70 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ b/llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -15,40 +15,32 @@ #ifndef LLVM_LIB_TRANSFORMS_INSTCOMBINE_INSTCOMBINEINTERNAL_H #define LLVM_LIB_TRANSFORMS_INSTCOMBINE_INSTCOMBINEINTERNAL_H -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/TargetFolder.h" #include "llvm/Analysis/ValueTracking.h" -#include "llvm/IR/Argument.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstVisitor.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/Intrinsics.h" #include "llvm/IR/PatternMatch.h" -#include "llvm/IR/Use.h" -#include "llvm/IR/Value.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/KnownBits.h" -#include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/Local.h" #include -#include #define DEBUG_TYPE "instcombine" using namespace llvm::PatternMatch; +// As a default, let's assume that we want to be aggressive, +// and attempt to traverse with no limits in attempt to sink negation. +static constexpr unsigned NegatorDefaultMaxDepth = ~0U; + +// Let's guesstimate that most often we will end up visiting/producing +// fairly small number of new instructions. +static constexpr unsigned NegatorMaxNodesSSO = 16; + namespace llvm { class AAResults; @@ -65,305 +57,26 @@ class ProfileSummaryInfo; class TargetLibraryInfo; class User; -/// Assign a complexity or rank value to LLVM Values. This is used to reduce -/// the amount of pattern matching needed for compares and commutative -/// instructions. For example, if we have: -/// icmp ugt X, Constant -/// or -/// xor (add X, Constant), cast Z -/// -/// We do not have to consider the commuted variants of these patterns because -/// canonicalization based on complexity guarantees the above ordering. -/// -/// This routine maps IR values to various complexity ranks: -/// 0 -> undef -/// 1 -> Constants -/// 2 -> Other non-instructions -/// 3 -> Arguments -/// 4 -> Cast and (f)neg/not instructions -/// 5 -> Other instructions -static inline unsigned getComplexity(Value *V) { - if (isa(V)) { - if (isa(V) || match(V, m_Neg(m_Value())) || - match(V, m_Not(m_Value())) || match(V, m_FNeg(m_Value()))) - return 4; - return 5; - } - if (isa(V)) - return 3; - return isa(V) ? (isa(V) ? 0 : 1) : 2; -} - -/// Predicate canonicalization reduces the number of patterns that need to be -/// matched by other transforms. For example, we may swap the operands of a -/// conditional branch or select to create a compare with a canonical (inverted) -/// predicate which is then more likely to be matched with other values. -static inline bool isCanonicalPredicate(CmpInst::Predicate Pred) { - switch (Pred) { - case CmpInst::ICMP_NE: - case CmpInst::ICMP_ULE: - case CmpInst::ICMP_SLE: - case CmpInst::ICMP_UGE: - case CmpInst::ICMP_SGE: - // TODO: There are 16 FCMP predicates. Should others be (not) canonical? - case CmpInst::FCMP_ONE: - case CmpInst::FCMP_OLE: - case CmpInst::FCMP_OGE: - return false; - default: - return true; - } -} - -/// Given an exploded icmp instruction, return true if the comparison only -/// checks the sign bit. If it only checks the sign bit, set TrueIfSigned if the -/// result of the comparison is true when the input value is signed. -inline bool isSignBitCheck(ICmpInst::Predicate Pred, const APInt &RHS, - bool &TrueIfSigned) { - switch (Pred) { - case ICmpInst::ICMP_SLT: // True if LHS s< 0 - TrueIfSigned = true; - return RHS.isNullValue(); - case ICmpInst::ICMP_SLE: // True if LHS s<= -1 - TrueIfSigned = true; - return RHS.isAllOnesValue(); - case ICmpInst::ICMP_SGT: // True if LHS s> -1 - TrueIfSigned = false; - return RHS.isAllOnesValue(); - case ICmpInst::ICMP_SGE: // True if LHS s>= 0 - TrueIfSigned = false; - return RHS.isNullValue(); - case ICmpInst::ICMP_UGT: - // True if LHS u> RHS and RHS == sign-bit-mask - 1 - TrueIfSigned = true; - return RHS.isMaxSignedValue(); - case ICmpInst::ICMP_UGE: - // True if LHS u>= RHS and RHS == sign-bit-mask (2^7, 2^15, 2^31, etc) - TrueIfSigned = true; - return RHS.isMinSignedValue(); - case ICmpInst::ICMP_ULT: - // True if LHS u< RHS and RHS == sign-bit-mask (2^7, 2^15, 2^31, etc) - TrueIfSigned = false; - return RHS.isMinSignedValue(); - case ICmpInst::ICMP_ULE: - // True if LHS u<= RHS and RHS == sign-bit-mask - 1 - TrueIfSigned = false; - return RHS.isMaxSignedValue(); - default: - return false; - } -} - -llvm::Optional> -getFlippedStrictnessPredicateAndConstant(CmpInst::Predicate Pred, Constant *C); - -/// Return the source operand of a potentially bitcasted value while optionally -/// checking if it has one use. If there is no bitcast or the one use check is -/// not met, return the input value itself. -static inline Value *peekThroughBitcast(Value *V, bool OneUseOnly = false) { - if (auto *BitCast = dyn_cast(V)) - if (!OneUseOnly || BitCast->hasOneUse()) - return BitCast->getOperand(0); - - // V is not a bitcast or V has more than one use and OneUseOnly is true. - return V; -} - -/// Add one to a Constant -static inline Constant *AddOne(Constant *C) { - return ConstantExpr::getAdd(C, ConstantInt::get(C->getType(), 1)); -} - -/// Subtract one from a Constant -static inline Constant *SubOne(Constant *C) { - return ConstantExpr::getSub(C, ConstantInt::get(C->getType(), 1)); -} - -/// Return true if the specified value is free to invert (apply ~ to). -/// This happens in cases where the ~ can be eliminated. If WillInvertAllUses -/// is true, work under the assumption that the caller intends to remove all -/// uses of V and only keep uses of ~V. -/// -/// See also: canFreelyInvertAllUsersOf() -static inline bool isFreeToInvert(Value *V, bool WillInvertAllUses) { - // ~(~(X)) -> X. - if (match(V, m_Not(m_Value()))) - return true; - - // Constants can be considered to be not'ed values. - if (match(V, m_AnyIntegralConstant())) - return true; - - // Compares can be inverted if all of their uses are being modified to use the - // ~V. - if (isa(V)) - return WillInvertAllUses; - - // If `V` is of the form `A + Constant` then `-1 - V` can be folded into `(-1 - // - Constant) - A` if we are willing to invert all of the uses. - if (BinaryOperator *BO = dyn_cast(V)) - if (BO->getOpcode() == Instruction::Add || - BO->getOpcode() == Instruction::Sub) - if (isa(BO->getOperand(0)) || isa(BO->getOperand(1))) - return WillInvertAllUses; - - // Selects with invertible operands are freely invertible - if (match(V, m_Select(m_Value(), m_Not(m_Value()), m_Not(m_Value())))) - return WillInvertAllUses; - - return false; -} - -/// Given i1 V, can every user of V be freely adapted if V is changed to !V ? -/// InstCombine's canonicalizeICmpPredicate() must be kept in sync with this fn. -/// -/// See also: isFreeToInvert() -static inline bool canFreelyInvertAllUsersOf(Value *V, Value *IgnoredUser) { - // Look at every user of V. - for (Use &U : V->uses()) { - if (U.getUser() == IgnoredUser) - continue; // Don't consider this user. - - auto *I = cast(U.getUser()); - switch (I->getOpcode()) { - case Instruction::Select: - if (U.getOperandNo() != 0) // Only if the value is used as select cond. - return false; - break; - case Instruction::Br: - assert(U.getOperandNo() == 0 && "Must be branching on that value."); - break; // Free to invert by swapping true/false values/destinations. - case Instruction::Xor: // Can invert 'xor' if it's a 'not', by ignoring it. - if (!match(I, m_Not(m_Value()))) - return false; // Not a 'not'. - break; - default: - return false; // Don't know, likely not freely invertible. - } - // So far all users were free to invert... - } - return true; // Can freely invert all users! -} - -/// Some binary operators require special handling to avoid poison and undefined -/// behavior. If a constant vector has undef elements, replace those undefs with -/// identity constants if possible because those are always safe to execute. -/// If no identity constant exists, replace undef with some other safe constant. -static inline Constant *getSafeVectorConstantForBinop( - BinaryOperator::BinaryOps Opcode, Constant *In, bool IsRHSConstant) { - auto *InVTy = dyn_cast(In->getType()); - assert(InVTy && "Not expecting scalars here"); - - Type *EltTy = InVTy->getElementType(); - auto *SafeC = ConstantExpr::getBinOpIdentity(Opcode, EltTy, IsRHSConstant); - if (!SafeC) { - // TODO: Should this be available as a constant utility function? It is - // similar to getBinOpAbsorber(). - if (IsRHSConstant) { - switch (Opcode) { - case Instruction::SRem: // X % 1 = 0 - case Instruction::URem: // X %u 1 = 0 - SafeC = ConstantInt::get(EltTy, 1); - break; - case Instruction::FRem: // X % 1.0 (doesn't simplify, but it is safe) - SafeC = ConstantFP::get(EltTy, 1.0); - break; - default: - llvm_unreachable("Only rem opcodes have no identity constant for RHS"); - } - } else { - switch (Opcode) { - case Instruction::Shl: // 0 << X = 0 - case Instruction::LShr: // 0 >>u X = 0 - case Instruction::AShr: // 0 >> X = 0 - case Instruction::SDiv: // 0 / X = 0 - case Instruction::UDiv: // 0 /u X = 0 - case Instruction::SRem: // 0 % X = 0 - case Instruction::URem: // 0 %u X = 0 - case Instruction::Sub: // 0 - X (doesn't simplify, but it is safe) - case Instruction::FSub: // 0.0 - X (doesn't simplify, but it is safe) - case Instruction::FDiv: // 0.0 / X (doesn't simplify, but it is safe) - case Instruction::FRem: // 0.0 % X = 0 - SafeC = Constant::getNullValue(EltTy); - break; - default: - llvm_unreachable("Expected to find identity constant for opcode"); - } - } - } - assert(SafeC && "Must have safe constant for binop"); - unsigned NumElts = InVTy->getNumElements(); - SmallVector Out(NumElts); - for (unsigned i = 0; i != NumElts; ++i) { - Constant *C = In->getAggregateElement(i); - Out[i] = isa(C) ? SafeC : C; - } - return ConstantVector::get(Out); -} - -/// The core instruction combiner logic. -/// -/// This class provides both the logic to recursively visit instructions and -/// combine them. -class LLVM_LIBRARY_VISIBILITY InstCombiner - : public InstVisitor { - // FIXME: These members shouldn't be public. +class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final + : public InstCombiner, + public InstVisitor { public: - /// A worklist of the instructions that need to be simplified. - InstCombineWorklist &Worklist; - - /// An IRBuilder that automatically inserts new instructions into the - /// worklist. - using BuilderTy = IRBuilder; - BuilderTy &Builder; - -private: - // Mode in which we are running the combiner. - const bool MinimizeSize; - - AAResults *AA; - - // Required analyses. - AssumptionCache &AC; - TargetLibraryInfo &TLI; - DominatorTree &DT; - const DataLayout &DL; - const SimplifyQuery SQ; - OptimizationRemarkEmitter &ORE; - BlockFrequencyInfo *BFI; - ProfileSummaryInfo *PSI; + InstCombinerImpl(InstCombineWorklist &Worklist, BuilderTy &Builder, + bool MinimizeSize, AAResults *AA, AssumptionCache &AC, + TargetLibraryInfo &TLI, TargetTransformInfo &TTI, + DominatorTree &DT, OptimizationRemarkEmitter &ORE, + BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, + const DataLayout &DL, LoopInfo *LI) + : InstCombiner(Worklist, Builder, MinimizeSize, AA, AC, TLI, TTI, DT, ORE, + BFI, PSI, DL, LI) {} - // Optional analyses. When non-null, these can both be used to do better - // combining and will be updated to reflect any changes. - LoopInfo *LI; - - bool MadeIRChange = false; - -public: - InstCombiner(InstCombineWorklist &Worklist, BuilderTy &Builder, - bool MinimizeSize, AAResults *AA, - AssumptionCache &AC, TargetLibraryInfo &TLI, DominatorTree &DT, - OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI, - ProfileSummaryInfo *PSI, const DataLayout &DL, LoopInfo *LI) - : Worklist(Worklist), Builder(Builder), MinimizeSize(MinimizeSize), - AA(AA), AC(AC), TLI(TLI), DT(DT), - DL(DL), SQ(DL, &TLI, &DT, &AC), ORE(ORE), BFI(BFI), PSI(PSI), LI(LI) {} + virtual ~InstCombinerImpl() {} /// Run the combiner over the entire worklist until it is empty. /// /// \returns true if the IR is changed. bool run(); - AssumptionCache &getAssumptionCache() const { return AC; } - - const DataLayout &getDataLayout() const { return DL; } - - DominatorTree &getDominatorTree() const { return DT; } - - LoopInfo *getLoopInfo() const { return LI; } - - TargetLibraryInfo &getTargetLibraryInfo() const { return TLI; } - // Visitation implementation - Implement instruction combining for different // instruction types. The semantics are as follows: // Return Value: @@ -384,9 +97,7 @@ public: Instruction *visitSRem(BinaryOperator &I); Instruction *visitFRem(BinaryOperator &I); bool simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I); - Instruction *commonRemTransforms(BinaryOperator &I); Instruction *commonIRemTransforms(BinaryOperator &I); - Instruction *commonDivTransforms(BinaryOperator &I); Instruction *commonIDivTransforms(BinaryOperator &I); Instruction *visitUDiv(BinaryOperator &I); Instruction *visitSDiv(BinaryOperator &I); @@ -394,6 +105,7 @@ public: Value *simplifyRangeCheck(ICmpInst *Cmp0, ICmpInst *Cmp1, bool Inverted); Instruction *visitAnd(BinaryOperator &I); Instruction *visitOr(BinaryOperator &I); + bool sinkNotIntoOtherHandOfAndOrOr(BinaryOperator &I); Instruction *visitXor(BinaryOperator &I); Instruction *visitShl(BinaryOperator &I); Value *reassociateShiftAmtsOfTwoSameDirectionShifts( @@ -407,6 +119,7 @@ public: Instruction *visitLShr(BinaryOperator &I); Instruction *commonShiftTransforms(BinaryOperator &I); Instruction *visitFCmpInst(FCmpInst &I); + CmpInst *canonicalizeICmpPredicate(CmpInst &I); Instruction *visitICmpInst(ICmpInst &I); Instruction *FoldShiftByConstant(Value *Op0, Constant *Op1, BinaryOperator &I); @@ -445,6 +158,9 @@ public: Instruction *visitFenceInst(FenceInst &FI); Instruction *visitSwitchInst(SwitchInst &SI); Instruction *visitReturnInst(ReturnInst &RI); + Instruction *visitUnreachableInst(UnreachableInst &I); + Instruction * + foldAggregateConstructionIntoAggregateReuse(InsertValueInst &OrigIVI); Instruction *visitInsertValueInst(InsertValueInst &IV); Instruction *visitInsertElementInst(InsertElementInst &IE); Instruction *visitExtractElementInst(ExtractElementInst &EI); @@ -467,11 +183,6 @@ public: bool replacedSelectWithOperand(SelectInst *SI, const ICmpInst *Icmp, const unsigned SIOpd); - /// Try to replace instruction \p I with value \p V which are pointers - /// in different address space. - /// \return true if successful. - bool replacePointer(Instruction &I, Value *V); - LoadInst *combineLoadToNewType(LoadInst &LI, Type *NewTy, const Twine &Suffix = ""); @@ -609,10 +320,12 @@ private: Instruction *narrowBinOp(TruncInst &Trunc); Instruction *narrowMaskedBinOp(BinaryOperator &And); Instruction *narrowMathIfNoOverflow(BinaryOperator &I); - Instruction *narrowRotate(TruncInst &Trunc); + Instruction *narrowFunnelShift(TruncInst &Trunc); Instruction *optimizeBitCastFromPhi(CastInst &CI, PHINode *PN); Instruction *matchSAddSubSat(SelectInst &MinMax1); + void freelyInvertAllUsersOf(Value *V); + /// Determine if a pair of casts can be replaced by a single cast. /// /// \param CI1 The first of a pair of casts. @@ -653,7 +366,7 @@ public: "New instruction already inserted into a basic block!"); BasicBlock *BB = Old.getParent(); BB->getInstList().insert(Old.getIterator(), New); // Insert inst - Worklist.push(New); + Worklist.add(New); return New; } @@ -685,6 +398,7 @@ public: << " with " << *V << '\n'); I.replaceAllUsesWith(V); + MadeIRChange = true; return &I; } @@ -726,7 +440,7 @@ public: /// When dealing with an instruction that has side effects or produces a void /// value, we can't rely on DCE to delete the instruction. Instead, visit /// methods should return the value returned by this function. - Instruction *eraseInstFromFunction(Instruction &I) { + Instruction *eraseInstFromFunction(Instruction &I) override { LLVM_DEBUG(dbgs() << "IC: ERASE " << I << '\n'); assert(I.use_empty() && "Cannot erase instruction that is used!"); salvageDebugInfo(I); @@ -808,10 +522,6 @@ public: Instruction::BinaryOps BinaryOp, bool IsSigned, Value *LHS, Value *RHS, Instruction *CxtI) const; - /// Maximum size of array considered when transforming. - uint64_t MaxArraySizeForCombine = 0; - -private: /// Performs a few simplifications for operators which are associative /// or commutative. bool SimplifyAssociativeOrCommutative(BinaryOperator &I); @@ -857,7 +567,7 @@ private: unsigned Depth, Instruction *CxtI); bool SimplifyDemandedBits(Instruction *I, unsigned Op, const APInt &DemandedMask, KnownBits &Known, - unsigned Depth = 0); + unsigned Depth = 0) override; /// Helper routine of SimplifyDemandedUseBits. It computes KnownZero/KnownOne /// bits. It also tries to handle simplifications that can be done based on @@ -877,13 +587,10 @@ private: /// demanded bits. bool SimplifyDemandedInstructionBits(Instruction &Inst); - Value *simplifyAMDGCNMemoryIntrinsicDemanded(IntrinsicInst *II, - APInt DemandedElts, - int DmaskIdx = -1); - - Value *SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, - APInt &UndefElts, unsigned Depth = 0, - bool AllowMultipleUsers = false); + virtual Value * + SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, APInt &UndefElts, + unsigned Depth = 0, + bool AllowMultipleUsers = false) override; /// Canonicalize the position of binops relative to shufflevector. Instruction *foldVectorBinop(BinaryOperator &Inst); @@ -907,16 +614,18 @@ private: /// Try to rotate an operation below a PHI node, using PHI nodes for /// its operands. - Instruction *FoldPHIArgOpIntoPHI(PHINode &PN); - Instruction *FoldPHIArgBinOpIntoPHI(PHINode &PN); - Instruction *FoldPHIArgGEPIntoPHI(PHINode &PN); - Instruction *FoldPHIArgLoadIntoPHI(PHINode &PN); - Instruction *FoldPHIArgZextsIntoPHI(PHINode &PN); + Instruction *foldPHIArgOpIntoPHI(PHINode &PN); + Instruction *foldPHIArgBinOpIntoPHI(PHINode &PN); + Instruction *foldPHIArgInsertValueInstructionIntoPHI(PHINode &PN); + Instruction *foldPHIArgExtractValueInstructionIntoPHI(PHINode &PN); + Instruction *foldPHIArgGEPIntoPHI(PHINode &PN); + Instruction *foldPHIArgLoadIntoPHI(PHINode &PN); + Instruction *foldPHIArgZextsIntoPHI(PHINode &PN); /// If an integer typed PHI has only one use which is an IntToPtr operation, /// replace the PHI with an existing pointer typed PHI if it exists. Otherwise /// insert a new pointer typed PHI and replace the original one. - Instruction *FoldIntegerTypedPHI(PHINode &PN); + Instruction *foldIntegerTypedPHI(PHINode &PN); /// Helper function for FoldPHIArgXIntoPHI() to set debug location for the /// folded operation. @@ -999,18 +708,18 @@ private: Value *A, Value *B, Instruction &Outer, SelectPatternFlavor SPF2, Value *C); Instruction *foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI); - - Instruction *OptAndOp(BinaryOperator *Op, ConstantInt *OpRHS, - ConstantInt *AndRHS, BinaryOperator &TheAnd); + Instruction *foldSelectValueEquivalence(SelectInst &SI, ICmpInst &ICI); Value *insertRangeTest(Value *V, const APInt &Lo, const APInt &Hi, bool isSigned, bool Inside); Instruction *PromoteCastOfAllocation(BitCastInst &CI, AllocaInst &AI); bool mergeStoreIntoSuccessor(StoreInst &SI); - /// Given an 'or' instruction, check to see if it is part of a bswap idiom. - /// If so, return the equivalent bswap intrinsic. - Instruction *matchBSwap(BinaryOperator &Or); + /// Given an 'or' instruction, check to see if it is part of a + /// bswap/bitreverse idiom. If so, return the equivalent bswap/bitreverse + /// intrinsic. + Instruction *matchBSwapOrBitReverse(BinaryOperator &Or, bool MatchBSwaps, + bool MatchBitReversals); Instruction *SimplifyAnyMemTransfer(AnyMemTransferInst *MI); Instruction *SimplifyAnyMemSet(AnyMemSetInst *MI); @@ -1023,18 +732,6 @@ private: Value *Descale(Value *Val, APInt Scale, bool &NoSignedWrap); }; -namespace { - -// As a default, let's assume that we want to be aggressive, -// and attempt to traverse with no limits in attempt to sink negation. -static constexpr unsigned NegatorDefaultMaxDepth = ~0U; - -// Let's guesstimate that most often we will end up visiting/producing -// fairly small number of new instructions. -static constexpr unsigned NegatorMaxNodesSSO = 16; - -} // namespace - class Negator final { /// Top-to-bottom, def-to-use negated instruction tree we produced. SmallVector NewInstructions; @@ -1061,6 +758,8 @@ class Negator final { using Result = std::pair /*NewInstructions*/, Value * /*NegatedRoot*/>; + std::array getSortedOperandsOfBinOp(Instruction *I); + LLVM_NODISCARD Value *visitImpl(Value *V, unsigned Depth); LLVM_NODISCARD Value *negate(Value *V, unsigned Depth); @@ -1078,7 +777,7 @@ public: /// Attempt to negate \p Root. Retuns nullptr if negation can't be performed, /// otherwise returns negated value. LLVM_NODISCARD static Value *Negate(bool LHSIsZero, Value *Root, - InstCombiner &IC); + InstCombinerImpl &IC); }; } // end namespace llvm diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index dad2f23120bd..c7b5f6f78069 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -23,6 +23,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" using namespace llvm; @@ -166,7 +167,8 @@ static bool isDereferenceableForAllocaSize(const Value *V, const AllocaInst *AI, APInt(64, AllocaSize), DL); } -static Instruction *simplifyAllocaArraySize(InstCombiner &IC, AllocaInst &AI) { +static Instruction *simplifyAllocaArraySize(InstCombinerImpl &IC, + AllocaInst &AI) { // Check for array size of 1 (scalar allocation). if (!AI.isArrayAllocation()) { // i32 1 is the canonical array size for scalar allocations. @@ -234,47 +236,45 @@ namespace { // instruction. class PointerReplacer { public: - PointerReplacer(InstCombiner &IC) : IC(IC) {} + PointerReplacer(InstCombinerImpl &IC) : IC(IC) {} + + bool collectUsers(Instruction &I); void replacePointer(Instruction &I, Value *V); private: - void findLoadAndReplace(Instruction &I); void replace(Instruction *I); Value *getReplacement(Value *I); - SmallVector Path; + SmallSetVector Worklist; MapVector WorkMap; - InstCombiner &IC; + InstCombinerImpl &IC; }; } // end anonymous namespace -void PointerReplacer::findLoadAndReplace(Instruction &I) { +bool PointerReplacer::collectUsers(Instruction &I) { for (auto U : I.users()) { - auto *Inst = dyn_cast(&*U); - if (!Inst) - return; - LLVM_DEBUG(dbgs() << "Found pointer user: " << *U << '\n'); - if (isa(Inst)) { - for (auto P : Path) - replace(P); - replace(Inst); + Instruction *Inst = cast(&*U); + if (LoadInst *Load = dyn_cast(Inst)) { + if (Load->isVolatile()) + return false; + Worklist.insert(Load); } else if (isa(Inst) || isa(Inst)) { - Path.push_back(Inst); - findLoadAndReplace(*Inst); - Path.pop_back(); + Worklist.insert(Inst); + if (!collectUsers(*Inst)) + return false; + } else if (isa(Inst)) { + Worklist.insert(Inst); } else { - return; + LLVM_DEBUG(dbgs() << "Cannot handle pointer user: " << *U << '\n'); + return false; } } -} -Value *PointerReplacer::getReplacement(Value *V) { - auto Loc = WorkMap.find(V); - if (Loc != WorkMap.end()) - return Loc->second; - return nullptr; + return true; } +Value *PointerReplacer::getReplacement(Value *V) { return WorkMap.lookup(V); } + void PointerReplacer::replace(Instruction *I) { if (getReplacement(I)) return; @@ -282,9 +282,12 @@ void PointerReplacer::replace(Instruction *I) { if (auto *LT = dyn_cast(I)) { auto *V = getReplacement(LT->getPointerOperand()); assert(V && "Operand not replaced"); - auto *NewI = new LoadInst(I->getType(), V, "", false, - IC.getDataLayout().getABITypeAlign(I->getType())); + auto *NewI = new LoadInst(LT->getType(), V, "", LT->isVolatile(), + LT->getAlign(), LT->getOrdering(), + LT->getSyncScopeID()); NewI->takeName(LT); + copyMetadataForLoad(*NewI, *LT); + IC.InsertNewInstWith(NewI, *LT); IC.replaceInstUsesWith(*LT, NewI); WorkMap[LT] = NewI; @@ -307,6 +310,28 @@ void PointerReplacer::replace(Instruction *I) { IC.InsertNewInstWith(NewI, *BC); NewI->takeName(BC); WorkMap[BC] = NewI; + } else if (auto *MemCpy = dyn_cast(I)) { + auto *SrcV = getReplacement(MemCpy->getRawSource()); + // The pointer may appear in the destination of a copy, but we don't want to + // replace it. + if (!SrcV) { + assert(getReplacement(MemCpy->getRawDest()) && + "destination not in replace list"); + return; + } + + IC.Builder.SetInsertPoint(MemCpy); + auto *NewI = IC.Builder.CreateMemTransferInst( + MemCpy->getIntrinsicID(), MemCpy->getRawDest(), MemCpy->getDestAlign(), + SrcV, MemCpy->getSourceAlign(), MemCpy->getLength(), + MemCpy->isVolatile()); + AAMDNodes AAMD; + MemCpy->getAAMetadata(AAMD); + if (AAMD) + NewI->setAAMetadata(AAMD); + + IC.eraseInstFromFunction(*MemCpy); + WorkMap[MemCpy] = NewI; } else { llvm_unreachable("should never reach here"); } @@ -320,10 +345,12 @@ void PointerReplacer::replacePointer(Instruction &I, Value *V) { "Invalid usage"); #endif WorkMap[&I] = V; - findLoadAndReplace(I); + + for (Instruction *Workitem : Worklist) + replace(Workitem); } -Instruction *InstCombiner::visitAllocaInst(AllocaInst &AI) { +Instruction *InstCombinerImpl::visitAllocaInst(AllocaInst &AI) { if (auto *I = simplifyAllocaArraySize(*this, AI)) return I; @@ -374,23 +401,21 @@ Instruction *InstCombiner::visitAllocaInst(AllocaInst &AI) { // read. SmallVector ToDelete; if (MemTransferInst *Copy = isOnlyCopiedFromConstantMemory(AA, &AI, ToDelete)) { + Value *TheSrc = Copy->getSource(); Align AllocaAlign = AI.getAlign(); Align SourceAlign = getOrEnforceKnownAlignment( - Copy->getSource(), AllocaAlign, DL, &AI, &AC, &DT); + TheSrc, AllocaAlign, DL, &AI, &AC, &DT); if (AllocaAlign <= SourceAlign && - isDereferenceableForAllocaSize(Copy->getSource(), &AI, DL)) { + isDereferenceableForAllocaSize(TheSrc, &AI, DL)) { LLVM_DEBUG(dbgs() << "Found alloca equal to global: " << AI << '\n'); LLVM_DEBUG(dbgs() << " memcpy = " << *Copy << '\n'); - for (unsigned i = 0, e = ToDelete.size(); i != e; ++i) - eraseInstFromFunction(*ToDelete[i]); - Value *TheSrc = Copy->getSource(); - auto *SrcTy = TheSrc->getType(); - auto *DestTy = PointerType::get(AI.getType()->getPointerElementType(), - SrcTy->getPointerAddressSpace()); - Value *Cast = - Builder.CreatePointerBitCastOrAddrSpaceCast(TheSrc, DestTy); - if (AI.getType()->getPointerAddressSpace() == - SrcTy->getPointerAddressSpace()) { + unsigned SrcAddrSpace = TheSrc->getType()->getPointerAddressSpace(); + auto *DestTy = PointerType::get(AI.getAllocatedType(), SrcAddrSpace); + if (AI.getType()->getAddressSpace() == SrcAddrSpace) { + for (Instruction *Delete : ToDelete) + eraseInstFromFunction(*Delete); + + Value *Cast = Builder.CreateBitCast(TheSrc, DestTy); Instruction *NewI = replaceInstUsesWith(AI, Cast); eraseInstFromFunction(*Copy); ++NumGlobalCopies; @@ -398,8 +423,14 @@ Instruction *InstCombiner::visitAllocaInst(AllocaInst &AI) { } PointerReplacer PtrReplacer(*this); - PtrReplacer.replacePointer(AI, Cast); - ++NumGlobalCopies; + if (PtrReplacer.collectUsers(AI)) { + for (Instruction *Delete : ToDelete) + eraseInstFromFunction(*Delete); + + Value *Cast = Builder.CreateBitCast(TheSrc, DestTy); + PtrReplacer.replacePointer(AI, Cast); + ++NumGlobalCopies; + } } } @@ -421,9 +452,9 @@ static bool isSupportedAtomicType(Type *Ty) { /// that pointer type, load it, etc. /// /// Note that this will create all of the instructions with whatever insert -/// point the \c InstCombiner currently is using. -LoadInst *InstCombiner::combineLoadToNewType(LoadInst &LI, Type *NewTy, - const Twine &Suffix) { +/// point the \c InstCombinerImpl currently is using. +LoadInst *InstCombinerImpl::combineLoadToNewType(LoadInst &LI, Type *NewTy, + const Twine &Suffix) { assert((!LI.isAtomic() || isSupportedAtomicType(NewTy)) && "can't fold an atomic load to requested type"); @@ -445,7 +476,8 @@ LoadInst *InstCombiner::combineLoadToNewType(LoadInst &LI, Type *NewTy, /// Combine a store to a new type. /// /// Returns the newly created store instruction. -static StoreInst *combineStoreToNewValue(InstCombiner &IC, StoreInst &SI, Value *V) { +static StoreInst *combineStoreToNewValue(InstCombinerImpl &IC, StoreInst &SI, + Value *V) { assert((!SI.isAtomic() || isSupportedAtomicType(V->getType())) && "can't fold an atomic store of requested type"); @@ -485,6 +517,7 @@ static StoreInst *combineStoreToNewValue(InstCombiner &IC, StoreInst &SI, Value break; case LLVMContext::MD_invariant_load: case LLVMContext::MD_nonnull: + case LLVMContext::MD_noundef: case LLVMContext::MD_range: case LLVMContext::MD_align: case LLVMContext::MD_dereferenceable: @@ -502,7 +535,7 @@ static StoreInst *combineStoreToNewValue(InstCombiner &IC, StoreInst &SI, Value static bool isMinMaxWithLoads(Value *V, Type *&LoadTy) { assert(V->getType()->isPointerTy() && "Expected pointer type."); // Ignore possible ty* to ixx* bitcast. - V = peekThroughBitcast(V); + V = InstCombiner::peekThroughBitcast(V); // Check that select is select ((cmp load V1, load V2), V1, V2) - minmax // pattern. CmpInst::Predicate Pred; @@ -537,7 +570,8 @@ static bool isMinMaxWithLoads(Value *V, Type *&LoadTy) { /// or a volatile load. This is debatable, and might be reasonable to change /// later. However, it is risky in case some backend or other part of LLVM is /// relying on the exact type loaded to select appropriate atomic operations. -static Instruction *combineLoadToOperationType(InstCombiner &IC, LoadInst &LI) { +static Instruction *combineLoadToOperationType(InstCombinerImpl &IC, + LoadInst &LI) { // FIXME: We could probably with some care handle both volatile and ordered // atomic loads here but it isn't clear that this is important. if (!LI.isUnordered()) @@ -550,62 +584,38 @@ static Instruction *combineLoadToOperationType(InstCombiner &IC, LoadInst &LI) { if (LI.getPointerOperand()->isSwiftError()) return nullptr; - Type *Ty = LI.getType(); const DataLayout &DL = IC.getDataLayout(); - // Try to canonicalize loads which are only ever stored to operate over - // integers instead of any other type. We only do this when the loaded type - // is sized and has a size exactly the same as its store size and the store - // size is a legal integer type. - // Do not perform canonicalization if minmax pattern is found (to avoid - // infinite loop). - Type *Dummy; - if (!Ty->isIntegerTy() && Ty->isSized() && !isa(Ty) && - DL.isLegalInteger(DL.getTypeStoreSizeInBits(Ty)) && - DL.typeSizeEqualsStoreSize(Ty) && !DL.isNonIntegralPointerType(Ty) && - !isMinMaxWithLoads( - peekThroughBitcast(LI.getPointerOperand(), /*OneUseOnly=*/true), - Dummy)) { - if (all_of(LI.users(), [&LI](User *U) { - auto *SI = dyn_cast(U); - return SI && SI->getPointerOperand() != &LI && - !SI->getPointerOperand()->isSwiftError(); - })) { - LoadInst *NewLoad = IC.combineLoadToNewType( - LI, Type::getIntNTy(LI.getContext(), DL.getTypeStoreSizeInBits(Ty))); - // Replace all the stores with stores of the newly loaded value. - for (auto UI = LI.user_begin(), UE = LI.user_end(); UI != UE;) { - auto *SI = cast(*UI++); - IC.Builder.SetInsertPoint(SI); - combineStoreToNewValue(IC, *SI, NewLoad); - IC.eraseInstFromFunction(*SI); - } - assert(LI.use_empty() && "Failed to remove all users of the load!"); - // Return the old load so the combiner can delete it safely. - return &LI; + // Fold away bit casts of the loaded value by loading the desired type. + // Note that we should not do this for pointer<->integer casts, + // because that would result in type punning. + if (LI.hasOneUse()) { + // Don't transform when the type is x86_amx, it makes the pass that lower + // x86_amx type happy. + if (auto *BC = dyn_cast(LI.user_back())) { + assert(!LI.getType()->isX86_AMXTy() && + "load from x86_amx* should not happen!"); + if (BC->getType()->isX86_AMXTy()) + return nullptr; } - } - // Fold away bit casts of the loaded value by loading the desired type. - // We can do this for BitCastInsts as well as casts from and to pointer types, - // as long as those are noops (i.e., the source or dest type have the same - // bitwidth as the target's pointers). - if (LI.hasOneUse()) if (auto* CI = dyn_cast(LI.user_back())) - if (CI->isNoopCast(DL)) + if (CI->isNoopCast(DL) && LI.getType()->isPtrOrPtrVectorTy() == + CI->getDestTy()->isPtrOrPtrVectorTy()) if (!LI.isAtomic() || isSupportedAtomicType(CI->getDestTy())) { LoadInst *NewLoad = IC.combineLoadToNewType(LI, CI->getDestTy()); CI->replaceAllUsesWith(NewLoad); IC.eraseInstFromFunction(*CI); return &LI; } + } // FIXME: We should also canonicalize loads of vectors when their elements are // cast to other types. return nullptr; } -static Instruction *unpackLoadToAggregate(InstCombiner &IC, LoadInst &LI) { +static Instruction *unpackLoadToAggregate(InstCombinerImpl &IC, LoadInst &LI) { // FIXME: We could probably with some care handle both volatile and atomic // stores here but it isn't clear that this is important. if (!LI.isSimple()) @@ -743,8 +753,7 @@ static bool isObjectSizeLessThanOrEq(Value *V, uint64_t MaxSize, } if (PHINode *PN = dyn_cast(P)) { - for (Value *IncValue : PN->incoming_values()) - Worklist.push_back(IncValue); + append_range(Worklist, PN->incoming_values()); continue; } @@ -804,8 +813,9 @@ static bool isObjectSizeLessThanOrEq(Value *V, uint64_t MaxSize, // not zero. Currently, we only handle the first such index. Also, we could // also search through non-zero constant indices if we kept track of the // offsets those indices implied. -static bool canReplaceGEPIdxWithZero(InstCombiner &IC, GetElementPtrInst *GEPI, - Instruction *MemI, unsigned &Idx) { +static bool canReplaceGEPIdxWithZero(InstCombinerImpl &IC, + GetElementPtrInst *GEPI, Instruction *MemI, + unsigned &Idx) { if (GEPI->getNumOperands() < 2) return false; @@ -834,12 +844,17 @@ static bool canReplaceGEPIdxWithZero(InstCombiner &IC, GetElementPtrInst *GEPI, return false; SmallVector Ops(GEPI->idx_begin(), GEPI->idx_begin() + Idx); - Type *AllocTy = - GetElementPtrInst::getIndexedType(GEPI->getSourceElementType(), Ops); + Type *SourceElementType = GEPI->getSourceElementType(); + // Size information about scalable vectors is not available, so we cannot + // deduce whether indexing at n is undefined behaviour or not. Bail out. + if (isa(SourceElementType)) + return false; + + Type *AllocTy = GetElementPtrInst::getIndexedType(SourceElementType, Ops); if (!AllocTy || !AllocTy->isSized()) return false; const DataLayout &DL = IC.getDataLayout(); - uint64_t TyAllocSize = DL.getTypeAllocSize(AllocTy); + uint64_t TyAllocSize = DL.getTypeAllocSize(AllocTy).getFixedSize(); // If there are more indices after the one we might replace with a zero, make // sure they're all non-negative. If any of them are negative, the overall @@ -874,7 +889,7 @@ static bool canReplaceGEPIdxWithZero(InstCombiner &IC, GetElementPtrInst *GEPI, // access, but the object has only one element, we can assume that the index // will always be zero. If we replace the GEP, return it. template -static Instruction *replaceGEPIdxWithZero(InstCombiner &IC, Value *Ptr, +static Instruction *replaceGEPIdxWithZero(InstCombinerImpl &IC, Value *Ptr, T &MemI) { if (GetElementPtrInst *GEPI = dyn_cast(Ptr)) { unsigned Idx; @@ -916,7 +931,7 @@ static bool canSimplifyNullLoadOrGEP(LoadInst &LI, Value *Op) { return false; } -Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { +Instruction *InstCombinerImpl::visitLoadInst(LoadInst &LI) { Value *Op = LI.getOperand(0); // Try to canonicalize the loaded type. @@ -1033,7 +1048,7 @@ Instruction *InstCombiner::visitLoadInst(LoadInst &LI) { /// and the layout of a <2 x double> is isomorphic to a [2 x double], /// then %V1 can be safely approximated by a conceptual "bitcast" of %U. /// Note that %U may contain non-undef values where %V1 has undef. -static Value *likeBitCastFromVector(InstCombiner &IC, Value *V) { +static Value *likeBitCastFromVector(InstCombinerImpl &IC, Value *V) { Value *U = nullptr; while (auto *IV = dyn_cast(V)) { auto *E = dyn_cast(IV->getInsertedValueOperand()); @@ -1060,11 +1075,11 @@ static Value *likeBitCastFromVector(InstCombiner &IC, Value *V) { return nullptr; } if (auto *AT = dyn_cast(VT)) { - if (AT->getNumElements() != UT->getNumElements()) + if (AT->getNumElements() != cast(UT)->getNumElements()) return nullptr; } else { auto *ST = cast(VT); - if (ST->getNumElements() != UT->getNumElements()) + if (ST->getNumElements() != cast(UT)->getNumElements()) return nullptr; for (const auto *EltT : ST->elements()) { if (EltT != UT->getElementType()) @@ -1094,7 +1109,7 @@ static Value *likeBitCastFromVector(InstCombiner &IC, Value *V) { /// the caller must erase the store instruction. We have to let the caller erase /// the store instruction as otherwise there is no way to signal whether it was /// combined or not: IC.EraseInstFromFunction returns a null pointer. -static bool combineStoreToValueType(InstCombiner &IC, StoreInst &SI) { +static bool combineStoreToValueType(InstCombinerImpl &IC, StoreInst &SI) { // FIXME: We could probably with some care handle both volatile and ordered // atomic stores here but it isn't clear that this is important. if (!SI.isUnordered()) @@ -1108,7 +1123,13 @@ static bool combineStoreToValueType(InstCombiner &IC, StoreInst &SI) { // Fold away bit casts of the stored value by storing the original type. if (auto *BC = dyn_cast(V)) { + assert(!BC->getType()->isX86_AMXTy() && + "store to x86_amx* should not happen!"); V = BC->getOperand(0); + // Don't transform when the type is x86_amx, it makes the pass that lower + // x86_amx type happy. + if (V->getType()->isX86_AMXTy()) + return false; if (!SI.isAtomic() || isSupportedAtomicType(V->getType())) { combineStoreToNewValue(IC, SI, V); return true; @@ -1126,7 +1147,7 @@ static bool combineStoreToValueType(InstCombiner &IC, StoreInst &SI) { return false; } -static bool unpackStoreToAggregate(InstCombiner &IC, StoreInst &SI) { +static bool unpackStoreToAggregate(InstCombinerImpl &IC, StoreInst &SI) { // FIXME: We could probably with some care handle both volatile and atomic // stores here but it isn't clear that this is important. if (!SI.isSimple()) @@ -1266,7 +1287,7 @@ static bool equivalentAddressValues(Value *A, Value *B) { /// Converts store (bitcast (load (bitcast (select ...)))) to /// store (load (select ...)), where select is minmax: /// select ((cmp load V1, load V2), V1, V2). -static bool removeBitcastsFromLoadStoreOnMinMax(InstCombiner &IC, +static bool removeBitcastsFromLoadStoreOnMinMax(InstCombinerImpl &IC, StoreInst &SI) { // bitcast? if (!match(SI.getPointerOperand(), m_BitCast(m_Value()))) @@ -1296,7 +1317,8 @@ static bool removeBitcastsFromLoadStoreOnMinMax(InstCombiner &IC, if (!all_of(LI->users(), [LI, LoadAddr](User *U) { auto *SI = dyn_cast(U); return SI && SI->getPointerOperand() != LI && - peekThroughBitcast(SI->getPointerOperand()) != LoadAddr && + InstCombiner::peekThroughBitcast(SI->getPointerOperand()) != + LoadAddr && !SI->getPointerOperand()->isSwiftError(); })) return false; @@ -1314,7 +1336,7 @@ static bool removeBitcastsFromLoadStoreOnMinMax(InstCombiner &IC, return true; } -Instruction *InstCombiner::visitStoreInst(StoreInst &SI) { +Instruction *InstCombinerImpl::visitStoreInst(StoreInst &SI) { Value *Val = SI.getOperand(0); Value *Ptr = SI.getOperand(1); @@ -1433,7 +1455,7 @@ Instruction *InstCombiner::visitStoreInst(StoreInst &SI) { /// or: /// *P = v1; if () { *P = v2; } /// into a phi node with a store in the successor. -bool InstCombiner::mergeStoreIntoSuccessor(StoreInst &SI) { +bool InstCombinerImpl::mergeStoreIntoSuccessor(StoreInst &SI) { if (!SI.isUnordered()) return false; // This code has not been audited for volatile/ordered case. diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index c6233a68847d..4b485a0ad85e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -32,6 +32,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" #include #include @@ -46,7 +47,7 @@ using namespace PatternMatch; /// The specific integer value is used in a context where it is known to be /// non-zero. If this allows us to simplify the computation, do so and return /// the new operand, otherwise return null. -static Value *simplifyValueKnownNonZero(Value *V, InstCombiner &IC, +static Value *simplifyValueKnownNonZero(Value *V, InstCombinerImpl &IC, Instruction &CxtI) { // If V has multiple uses, then we would have to do more analysis to determine // if this is safe. For example, the use could be in dynamically unreached @@ -94,39 +95,6 @@ static Value *simplifyValueKnownNonZero(Value *V, InstCombiner &IC, return MadeChange ? V : nullptr; } -/// A helper routine of InstCombiner::visitMul(). -/// -/// If C is a scalar/fixed width vector of known powers of 2, then this -/// function returns a new scalar/fixed width vector obtained from logBase2 -/// of C. -/// Return a null pointer otherwise. -static Constant *getLogBase2(Type *Ty, Constant *C) { - const APInt *IVal; - if (match(C, m_APInt(IVal)) && IVal->isPowerOf2()) - return ConstantInt::get(Ty, IVal->logBase2()); - - // FIXME: We can extract pow of 2 of splat constant for scalable vectors. - if (!isa(Ty)) - return nullptr; - - SmallVector Elts; - for (unsigned I = 0, E = cast(Ty)->getNumElements(); I != E; - ++I) { - Constant *Elt = C->getAggregateElement(I); - if (!Elt) - return nullptr; - if (isa(Elt)) { - Elts.push_back(UndefValue::get(Ty->getScalarType())); - continue; - } - if (!match(Elt, m_APInt(IVal)) || !IVal->isPowerOf2()) - return nullptr; - Elts.push_back(ConstantInt::get(Ty->getScalarType(), IVal->logBase2())); - } - - return ConstantVector::get(Elts); -} - // TODO: This is a specific form of a much more general pattern. // We could detect a select with any binop identity constant, or we // could use SimplifyBinOp to see if either arm of the select reduces. @@ -171,7 +139,7 @@ static Value *foldMulSelectToNegate(BinaryOperator &I, return nullptr; } -Instruction *InstCombiner::visitMul(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { if (Value *V = SimplifyMulInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -185,8 +153,10 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { if (Value *V = SimplifyUsingDistributiveLaws(I)) return replaceInstUsesWith(I, V); - // X * -1 == 0 - X Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + unsigned BitWidth = I.getType()->getScalarSizeInBits(); + + // X * -1 == 0 - X if (match(Op1, m_AllOnes())) { BinaryOperator *BO = BinaryOperator::CreateNeg(Op0, I.getName()); if (I.hasNoSignedWrap()) @@ -216,7 +186,7 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { if (match(&I, m_Mul(m_Value(NewOp), m_Constant(C1)))) { // Replace X*(2^C) with X << C, where C is either a scalar or a vector. - if (Constant *NewCst = getLogBase2(NewOp->getType(), C1)) { + if (Constant *NewCst = ConstantExpr::getExactLogBase2(C1)) { BinaryOperator *Shl = BinaryOperator::CreateShl(NewOp, NewCst); if (I.hasNoUnsignedWrap()) @@ -232,29 +202,12 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { } } - if (ConstantInt *CI = dyn_cast(Op1)) { - // (Y - X) * (-(2**n)) -> (X - Y) * (2**n), for positive nonzero n - // (Y + const) * (-(2**n)) -> (-constY) * (2**n), for positive nonzero n - // The "* (2**n)" thus becomes a potential shifting opportunity. - { - const APInt & Val = CI->getValue(); - const APInt &PosVal = Val.abs(); - if (Val.isNegative() && PosVal.isPowerOf2()) { - Value *X = nullptr, *Y = nullptr; - if (Op0->hasOneUse()) { - ConstantInt *C1; - Value *Sub = nullptr; - if (match(Op0, m_Sub(m_Value(Y), m_Value(X)))) - Sub = Builder.CreateSub(X, Y, "suba"); - else if (match(Op0, m_Add(m_Value(Y), m_ConstantInt(C1)))) - Sub = Builder.CreateSub(Builder.CreateNeg(C1), Y, "subc"); - if (Sub) - return - BinaryOperator::CreateMul(Sub, - ConstantInt::get(Y->getType(), PosVal)); - } - } - } + if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) { + // Interpret X * (-1<(Op1)), I.getName()); } if (Instruction *FoldedMul = foldBinOpIntoSelectOrPhi(I)) @@ -284,6 +237,9 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { SelectPatternFlavor SPF = matchSelectPattern(Op0, X, Y).Flavor; if (SPF == SPF_ABS || SPF == SPF_NABS) return BinaryOperator::CreateMul(X, X); + + if (match(Op0, m_Intrinsic(m_Value(X)))) + return BinaryOperator::CreateMul(X, X); } // -X * C --> X * -C @@ -406,6 +362,19 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { if (match(Op1, m_LShr(m_Value(X), m_APInt(C))) && *C == C->getBitWidth() - 1) return BinaryOperator::CreateAnd(Builder.CreateAShr(X, *C), Op0); + // ((ashr X, 31) | 1) * X --> abs(X) + // X * ((ashr X, 31) | 1) --> abs(X) + if (match(&I, m_c_BinOp(m_Or(m_AShr(m_Value(X), + m_SpecificIntAllowUndef(BitWidth - 1)), + m_One()), + m_Deferred(X)))) { + Value *Abs = Builder.CreateBinaryIntrinsic( + Intrinsic::abs, X, + ConstantInt::getBool(I.getContext(), I.hasNoSignedWrap())); + Abs->takeName(&I); + return replaceInstUsesWith(I, Abs); + } + if (Instruction *Ext = narrowMathIfNoOverflow(I)) return Ext; @@ -423,7 +392,7 @@ Instruction *InstCombiner::visitMul(BinaryOperator &I) { return Changed ? &I : nullptr; } -Instruction *InstCombiner::foldFPSignBitOps(BinaryOperator &I) { +Instruction *InstCombinerImpl::foldFPSignBitOps(BinaryOperator &I) { BinaryOperator::BinaryOps Opcode = I.getOpcode(); assert((Opcode == Instruction::FMul || Opcode == Instruction::FDiv) && "Expected fmul or fdiv"); @@ -438,13 +407,12 @@ Instruction *InstCombiner::foldFPSignBitOps(BinaryOperator &I) { // fabs(X) * fabs(X) -> X * X // fabs(X) / fabs(X) -> X / X - if (Op0 == Op1 && match(Op0, m_Intrinsic(m_Value(X)))) + if (Op0 == Op1 && match(Op0, m_FAbs(m_Value(X)))) return BinaryOperator::CreateWithCopiedFlags(Opcode, X, X, &I); // fabs(X) * fabs(Y) --> fabs(X * Y) // fabs(X) / fabs(Y) --> fabs(X / Y) - if (match(Op0, m_Intrinsic(m_Value(X))) && - match(Op1, m_Intrinsic(m_Value(Y))) && + if (match(Op0, m_FAbs(m_Value(X))) && match(Op1, m_FAbs(m_Value(Y))) && (Op0->hasOneUse() || Op1->hasOneUse())) { IRBuilder<>::FastMathFlagGuard FMFGuard(Builder); Builder.setFastMathFlags(I.getFastMathFlags()); @@ -457,7 +425,7 @@ Instruction *InstCombiner::foldFPSignBitOps(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitFMul(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) { if (Value *V = SimplifyFMulInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), SQ.getWithInstruction(&I))) @@ -553,6 +521,21 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) { return replaceInstUsesWith(I, Sqrt); } + // The following transforms are done irrespective of the number of uses + // for the expression "1.0/sqrt(X)". + // 1) 1.0/sqrt(X) * X -> X/sqrt(X) + // 2) X * 1.0/sqrt(X) -> X/sqrt(X) + // We always expect the backend to reduce X/sqrt(X) to sqrt(X), if it + // has the necessary (reassoc) fast-math-flags. + if (I.hasNoSignedZeros() && + match(Op0, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && + match(Y, m_Intrinsic(m_Value(X))) && Op1 == X) + return BinaryOperator::CreateFDivFMF(X, Y, &I); + if (I.hasNoSignedZeros() && + match(Op1, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && + match(Y, m_Intrinsic(m_Value(X))) && Op0 == X) + return BinaryOperator::CreateFDivFMF(X, Y, &I); + // Like the similar transform in instsimplify, this requires 'nsz' because // sqrt(-0.0) = -0.0, and -0.0 * -0.0 does not simplify to -0.0. if (I.hasNoNaNs() && I.hasNoSignedZeros() && Op0 == Op1 && @@ -637,7 +620,7 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) { /// Fold a divide or remainder with a select instruction divisor when one of the /// select operands is zero. In that case, we can use the other select operand /// because div/rem by zero is undefined. -bool InstCombiner::simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I) { +bool InstCombinerImpl::simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I) { SelectInst *SI = dyn_cast(I.getOperand(1)); if (!SI) return false; @@ -738,7 +721,7 @@ static bool isMultiple(const APInt &C1, const APInt &C2, APInt &Quotient, /// instructions (udiv and sdiv). It is called by the visitors to those integer /// division instructions. /// Common integer divide transforms -Instruction *InstCombiner::commonIDivTransforms(BinaryOperator &I) { +Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); bool IsSigned = I.getOpcode() == Instruction::SDiv; Type *Ty = I.getType(); @@ -874,7 +857,7 @@ namespace { using FoldUDivOperandCb = Instruction *(*)(Value *Op0, Value *Op1, const BinaryOperator &I, - InstCombiner &IC); + InstCombinerImpl &IC); /// Used to maintain state for visitUDivOperand(). struct UDivFoldAction { @@ -903,8 +886,9 @@ struct UDivFoldAction { // X udiv 2^C -> X >> C static Instruction *foldUDivPow2Cst(Value *Op0, Value *Op1, - const BinaryOperator &I, InstCombiner &IC) { - Constant *C1 = getLogBase2(Op0->getType(), cast(Op1)); + const BinaryOperator &I, + InstCombinerImpl &IC) { + Constant *C1 = ConstantExpr::getExactLogBase2(cast(Op1)); if (!C1) llvm_unreachable("Failed to constant fold udiv -> logbase2"); BinaryOperator *LShr = BinaryOperator::CreateLShr(Op0, C1); @@ -916,7 +900,7 @@ static Instruction *foldUDivPow2Cst(Value *Op0, Value *Op1, // X udiv (C1 << N), where C1 is "1< X >> (N+C2) // X udiv (zext (C1 << N)), where C1 is "1< X >> (N+C2) static Instruction *foldUDivShl(Value *Op0, Value *Op1, const BinaryOperator &I, - InstCombiner &IC) { + InstCombinerImpl &IC) { Value *ShiftLeft; if (!match(Op1, m_ZExt(m_Value(ShiftLeft)))) ShiftLeft = Op1; @@ -925,7 +909,7 @@ static Instruction *foldUDivShl(Value *Op0, Value *Op1, const BinaryOperator &I, Value *N; if (!match(ShiftLeft, m_Shl(m_Constant(CI), m_Value(N)))) llvm_unreachable("match should never fail here!"); - Constant *Log2Base = getLogBase2(N->getType(), CI); + Constant *Log2Base = ConstantExpr::getExactLogBase2(CI); if (!Log2Base) llvm_unreachable("getLogBase2 should never fail here!"); N = IC.Builder.CreateAdd(N, Log2Base); @@ -944,6 +928,8 @@ static Instruction *foldUDivShl(Value *Op0, Value *Op1, const BinaryOperator &I, static size_t visitUDivOperand(Value *Op0, Value *Op1, const BinaryOperator &I, SmallVectorImpl &Actions, unsigned Depth = 0) { + // FIXME: assert that Op1 isn't/doesn't contain undef. + // Check to see if this is an unsigned division with an exact power of 2, // if so, convert to a right shift. if (match(Op1, m_Power2())) { @@ -963,6 +949,9 @@ static size_t visitUDivOperand(Value *Op0, Value *Op1, const BinaryOperator &I, return 0; if (SelectInst *SI = dyn_cast(Op1)) + // FIXME: missed optimization: if one of the hands of select is/contains + // undef, just directly pick the other one. + // FIXME: can both hands contain undef? if (size_t LHSIdx = visitUDivOperand(Op0, SI->getOperand(1), I, Actions, Depth)) if (visitUDivOperand(Op0, SI->getOperand(2), I, Actions, Depth)) { @@ -1010,7 +999,7 @@ static Instruction *narrowUDivURem(BinaryOperator &I, return nullptr; } -Instruction *InstCombiner::visitUDiv(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) { if (Value *V = SimplifyUDivInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1104,7 +1093,7 @@ Instruction *InstCombiner::visitUDiv(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) { if (Value *V = SimplifySDivInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1117,6 +1106,7 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { return Common; Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + Type *Ty = I.getType(); Value *X; // sdiv Op0, -1 --> -Op0 // sdiv Op0, (sext i1 X) --> -Op0 (because if X is 0, the op is undefined) @@ -1126,16 +1116,26 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { // X / INT_MIN --> X == INT_MIN if (match(Op1, m_SignMask())) - return new ZExtInst(Builder.CreateICmpEQ(Op0, Op1), I.getType()); + return new ZExtInst(Builder.CreateICmpEQ(Op0, Op1), Ty); + + // sdiv exact X, 1< ashr exact X, C iff 1< -(ashr exact X, C) + if (I.isExact() && ((match(Op1, m_Power2()) && match(Op1, m_NonNegative())) || + match(Op1, m_NegatedPower2()))) { + bool DivisorWasNegative = match(Op1, m_NegatedPower2()); + if (DivisorWasNegative) + Op1 = ConstantExpr::getNeg(cast(Op1)); + auto *AShr = BinaryOperator::CreateExactAShr( + Op0, ConstantExpr::getExactLogBase2(cast(Op1)), I.getName()); + if (!DivisorWasNegative) + return AShr; + Builder.Insert(AShr); + AShr->setName(I.getName() + ".neg"); + return BinaryOperator::CreateNeg(AShr, I.getName()); + } const APInt *Op1C; if (match(Op1, m_APInt(Op1C))) { - // sdiv exact X, C --> ashr exact X, log2(C) - if (I.isExact() && Op1C->isNonNegative() && Op1C->isPowerOf2()) { - Value *ShAmt = ConstantInt::get(Op1->getType(), Op1C->exactLogBase2()); - return BinaryOperator::CreateExactAShr(Op0, ShAmt, I.getName()); - } - // If the dividend is sign-extended and the constant divisor is small enough // to fit in the source type, shrink the division to the narrower type: // (sext X) sdiv C --> sext (X sdiv C) @@ -1150,7 +1150,7 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { Constant *NarrowDivisor = ConstantExpr::getTrunc(cast(Op1), Op0Src->getType()); Value *NarrowOp = Builder.CreateSDiv(Op0Src, NarrowDivisor); - return new SExtInst(NarrowOp, Op0->getType()); + return new SExtInst(NarrowOp, Ty); } // -X / C --> X / -C (if the negation doesn't overflow). @@ -1158,7 +1158,7 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { // checking if all elements are not the min-signed-val. if (!Op1C->isMinSignedValue() && match(Op0, m_NSWSub(m_Zero(), m_Value(X)))) { - Constant *NegC = ConstantInt::get(I.getType(), -(*Op1C)); + Constant *NegC = ConstantInt::get(Ty, -(*Op1C)); Instruction *BO = BinaryOperator::CreateSDiv(X, NegC); BO->setIsExact(I.isExact()); return BO; @@ -1171,9 +1171,19 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { return BinaryOperator::CreateNSWNeg( Builder.CreateSDiv(X, Y, I.getName(), I.isExact())); + // abs(X) / X --> X > -1 ? 1 : -1 + // X / abs(X) --> X > -1 ? 1 : -1 + if (match(&I, m_c_BinOp( + m_OneUse(m_Intrinsic(m_Value(X), m_One())), + m_Deferred(X)))) { + Constant *NegOne = ConstantInt::getAllOnesValue(Ty); + Value *Cond = Builder.CreateICmpSGT(X, NegOne); + return SelectInst::Create(Cond, ConstantInt::get(Ty, 1), NegOne); + } + // If the sign bits of both operands are zero (i.e. we can prove they are // unsigned inputs), turn this into a udiv. - APInt Mask(APInt::getSignMask(I.getType()->getScalarSizeInBits())); + APInt Mask(APInt::getSignMask(Ty->getScalarSizeInBits())); if (MaskedValueIsZero(Op0, Mask, 0, &I)) { if (MaskedValueIsZero(Op1, Mask, 0, &I)) { // X sdiv Y -> X udiv Y, iff X and Y don't have sign bit set @@ -1182,6 +1192,13 @@ Instruction *InstCombiner::visitSDiv(BinaryOperator &I) { return BO; } + if (match(Op1, m_NegatedPower2())) { + // X sdiv (-(1 << C)) -> -(X sdiv (1 << C)) -> + // -> -(X udiv (1 << C)) -> -(X u>> C) + return BinaryOperator::CreateNeg(Builder.Insert(foldUDivPow2Cst( + Op0, ConstantExpr::getNeg(cast(Op1)), I, *this))); + } + if (isKnownToBeAPowerOfTwo(Op1, /*OrZero*/ true, 0, &I)) { // X sdiv (1 << Y) -> X udiv (1 << Y) ( -> X u>> Y) // Safe because the only negative value (1 << Y) can take on is @@ -1258,7 +1275,7 @@ static Instruction *foldFDivConstantDividend(BinaryOperator &I) { return BinaryOperator::CreateFDivFMF(NewC, X, &I); } -Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) { if (Value *V = SimplifyFDivInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), SQ.getWithInstruction(&I))) @@ -1350,10 +1367,8 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { // X / fabs(X) -> copysign(1.0, X) // fabs(X) / X -> copysign(1.0, X) if (I.hasNoNaNs() && I.hasNoInfs() && - (match(&I, - m_FDiv(m_Value(X), m_Intrinsic(m_Deferred(X)))) || - match(&I, m_FDiv(m_Intrinsic(m_Value(X)), - m_Deferred(X))))) { + (match(&I, m_FDiv(m_Value(X), m_FAbs(m_Deferred(X)))) || + match(&I, m_FDiv(m_FAbs(m_Value(X)), m_Deferred(X))))) { Value *V = Builder.CreateBinaryIntrinsic( Intrinsic::copysign, ConstantFP::get(I.getType(), 1.0), X, &I); return replaceInstUsesWith(I, V); @@ -1365,7 +1380,7 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) { /// instructions (urem and srem). It is called by the visitors to those integer /// remainder instructions. /// Common integer remainder transforms -Instruction *InstCombiner::commonIRemTransforms(BinaryOperator &I) { +Instruction *InstCombinerImpl::commonIRemTransforms(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); // The RHS is known non-zero. @@ -1403,7 +1418,7 @@ Instruction *InstCombiner::commonIRemTransforms(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitURem(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitURem(BinaryOperator &I) { if (Value *V = SimplifyURemInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1454,7 +1469,7 @@ Instruction *InstCombiner::visitURem(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitSRem(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitSRem(BinaryOperator &I) { if (Value *V = SimplifySRemInst(I.getOperand(0), I.getOperand(1), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1477,7 +1492,7 @@ Instruction *InstCombiner::visitSRem(BinaryOperator &I) { // -X srem Y --> -(X srem Y) Value *X, *Y; if (match(&I, m_SRem(m_OneUse(m_NSWSub(m_Zero(), m_Value(X))), m_Value(Y)))) - return BinaryOperator::CreateNSWNeg(Builder.CreateSRem(X, Y)); + return BinaryOperator::CreateNSWNeg(Builder.CreateSRem(X, Y)); // If the sign bits of both operands are zero (i.e. we can prove they are // unsigned inputs), turn this into a urem. @@ -1491,7 +1506,7 @@ Instruction *InstCombiner::visitSRem(BinaryOperator &I) { // If it's a constant vector, flip any negative values positive. if (isa(Op1) || isa(Op1)) { Constant *C = cast(Op1); - unsigned VWidth = cast(C->getType())->getNumElements(); + unsigned VWidth = cast(C->getType())->getNumElements(); bool hasNegative = false; bool hasMissing = false; @@ -1526,7 +1541,7 @@ Instruction *InstCombiner::visitSRem(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitFRem(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitFRem(BinaryOperator &I) { if (Value *V = SimplifyFRemInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), SQ.getWithInstruction(&I))) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp index 3fe615ac5439..7718c8b0eedd 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp @@ -42,6 +42,9 @@ #include "llvm/Support/DebugCounter.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" +#include +#include #include #include #include @@ -112,6 +115,19 @@ Negator::~Negator() { } #endif +// Due to the InstCombine's worklist management, there are no guarantees that +// each instruction we'll encounter has been visited by InstCombine already. +// In particular, most importantly for us, that means we have to canonicalize +// constants to RHS ourselves, since that is helpful sometimes. +std::array Negator::getSortedOperandsOfBinOp(Instruction *I) { + assert(I->getNumOperands() == 2 && "Only for binops!"); + std::array Ops{I->getOperand(0), I->getOperand(1)}; + if (I->isCommutative() && InstCombiner::getComplexity(I->getOperand(0)) < + InstCombiner::getComplexity(I->getOperand(1))) + std::swap(Ops[0], Ops[1]); + return Ops; +} + // FIXME: can this be reworked into a worklist-based algorithm while preserving // the depth-first, early bailout traversal? LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { @@ -156,11 +172,13 @@ LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { // In some cases we can give the answer without further recursion. switch (I->getOpcode()) { - case Instruction::Add: + case Instruction::Add: { + std::array Ops = getSortedOperandsOfBinOp(I); // `inc` is always negatible. - if (match(I->getOperand(1), m_One())) - return Builder.CreateNot(I->getOperand(0), I->getName() + ".neg"); + if (match(Ops[1], m_One())) + return Builder.CreateNot(Ops[0], I->getName() + ".neg"); break; + } case Instruction::Xor: // `not` is always negatible. if (match(I, m_Not(m_Value(X)))) @@ -181,6 +199,10 @@ LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { } return BO; } + // While we could negate exact arithmetic shift: + // ashr exact %x, C --> sdiv exact i8 %x, -1<getOpcode() == Instruction::Sub && + (I->hasOneUse() || match(I->getOperand(0), m_ImmConstant()))) { + // `sub` is always negatible. + // However, only do this either if the old `sub` doesn't stick around, or + // it was subtracting from a constant. Otherwise, this isn't profitable. + return Builder.CreateSub(I->getOperand(1), I->getOperand(0), + I->getName() + ".neg"); + } + // Some other cases, while still don't require recursion, // are restricted to the one-use case. if (!V->hasOneUse()) return nullptr; switch (I->getOpcode()) { - case Instruction::Sub: - // `sub` is always negatible. - // But if the old `sub` sticks around, even thought we don't increase - // instruction count, this is a likely regression since we increased - // live-range of *both* of the operands, which might lead to more spilling. - return Builder.CreateSub(I->getOperand(1), I->getOperand(0), - I->getName() + ".neg"); case Instruction::SDiv: // `sdiv` is negatible if divisor is not undef/INT_MIN/1. // While this is normally not behind a use-check, // let's consider division to be special since it's costly. if (auto *Op1C = dyn_cast(I->getOperand(1))) { - if (!Op1C->containsUndefElement() && Op1C->isNotMinSignedValue() && - Op1C->isNotOneValue()) { + if (!Op1C->containsUndefOrPoisonElement() && + Op1C->isNotMinSignedValue() && Op1C->isNotOneValue()) { Value *BO = Builder.CreateSDiv(I->getOperand(0), ConstantExpr::getNeg(Op1C), I->getName() + ".neg"); @@ -237,6 +261,13 @@ LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { } switch (I->getOpcode()) { + case Instruction::Freeze: { + // `freeze` is negatible if its operand is negatible. + Value *NegOp = negate(I->getOperand(0), Depth + 1); + if (!NegOp) // Early return. + return nullptr; + return Builder.CreateFreeze(NegOp, I->getName() + ".neg"); + } case Instruction::PHI: { // `phi` is negatible if all the incoming values are negatible. auto *PHI = cast(I); @@ -254,20 +285,16 @@ LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { return NegatedPHI; } case Instruction::Select: { - { - // `abs`/`nabs` is always negatible. - Value *LHS, *RHS; - SelectPatternFlavor SPF = - matchSelectPattern(I, LHS, RHS, /*CastOp=*/nullptr, Depth).Flavor; - if (SPF == SPF_ABS || SPF == SPF_NABS) { - auto *NewSelect = cast(I->clone()); - // Just swap the operands of the select. - NewSelect->swapValues(); - // Don't swap prof metadata, we didn't change the branch behavior. - NewSelect->setName(I->getName() + ".neg"); - Builder.Insert(NewSelect); - return NewSelect; - } + if (isKnownNegation(I->getOperand(1), I->getOperand(2))) { + // Of one hand of select is known to be negation of another hand, + // just swap the hands around. + auto *NewSelect = cast(I->clone()); + // Just swap the operands of the select. + NewSelect->swapValues(); + // Don't swap prof metadata, we didn't change the branch behavior. + NewSelect->setName(I->getName() + ".neg"); + Builder.Insert(NewSelect); + return NewSelect; } // `select` is negatible if both hands of `select` are negatible. Value *NegOp1 = negate(I->getOperand(1), Depth + 1); @@ -323,51 +350,81 @@ LLVM_NODISCARD Value *Negator::visitImpl(Value *V, unsigned Depth) { } case Instruction::Shl: { // `shl` is negatible if the first operand is negatible. - Value *NegOp0 = negate(I->getOperand(0), Depth + 1); - if (!NegOp0) // Early return. + if (Value *NegOp0 = negate(I->getOperand(0), Depth + 1)) + return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg"); + // Otherwise, `shl %x, C` can be interpreted as `mul %x, 1<(I->getOperand(1)); + if (!Op1C) // Early return. return nullptr; - return Builder.CreateShl(NegOp0, I->getOperand(1), I->getName() + ".neg"); + return Builder.CreateMul( + I->getOperand(0), + ConstantExpr::getShl(Constant::getAllOnesValue(Op1C->getType()), Op1C), + I->getName() + ".neg"); } - case Instruction::Or: + case Instruction::Or: { if (!haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1), DL, &AC, I, &DT)) return nullptr; // Don't know how to handle `or` in general. + std::array Ops = getSortedOperandsOfBinOp(I); // `or`/`add` are interchangeable when operands have no common bits set. // `inc` is always negatible. - if (match(I->getOperand(1), m_One())) - return Builder.CreateNot(I->getOperand(0), I->getName() + ".neg"); + if (match(Ops[1], m_One())) + return Builder.CreateNot(Ops[0], I->getName() + ".neg"); // Else, just defer to Instruction::Add handling. LLVM_FALLTHROUGH; + } case Instruction::Add: { // `add` is negatible if both of its operands are negatible. - Value *NegOp0 = negate(I->getOperand(0), Depth + 1); - if (!NegOp0) // Early return. - return nullptr; - Value *NegOp1 = negate(I->getOperand(1), Depth + 1); - if (!NegOp1) + SmallVector NegatedOps, NonNegatedOps; + for (Value *Op : I->operands()) { + // Can we sink the negation into this operand? + if (Value *NegOp = negate(Op, Depth + 1)) { + NegatedOps.emplace_back(NegOp); // Successfully negated operand! + continue; + } + // Failed to sink negation into this operand. IFF we started from negation + // and we manage to sink negation into one operand, we can still do this. + if (!IsTrulyNegation) + return nullptr; + NonNegatedOps.emplace_back(Op); // Just record which operand that was. + } + assert((NegatedOps.size() + NonNegatedOps.size()) == 2 && + "Internal consistency sanity check."); + // Did we manage to sink negation into both of the operands? + if (NegatedOps.size() == 2) // Then we get to keep the `add`! + return Builder.CreateAdd(NegatedOps[0], NegatedOps[1], + I->getName() + ".neg"); + assert(IsTrulyNegation && "We should have early-exited then."); + // Completely failed to sink negation? + if (NonNegatedOps.size() == 2) return nullptr; - return Builder.CreateAdd(NegOp0, NegOp1, I->getName() + ".neg"); + // 0-(a+b) --> (-a)-b + return Builder.CreateSub(NegatedOps[0], NonNegatedOps[0], + I->getName() + ".neg"); } - case Instruction::Xor: + case Instruction::Xor: { + std::array Ops = getSortedOperandsOfBinOp(I); // `xor` is negatible if one of its operands is invertible. // FIXME: InstCombineInverter? But how to connect Inverter and Negator? - if (auto *C = dyn_cast(I->getOperand(1))) { - Value *Xor = Builder.CreateXor(I->getOperand(0), ConstantExpr::getNot(C)); + if (auto *C = dyn_cast(Ops[1])) { + Value *Xor = Builder.CreateXor(Ops[0], ConstantExpr::getNot(C)); return Builder.CreateAdd(Xor, ConstantInt::get(Xor->getType(), 1), I->getName() + ".neg"); } return nullptr; + } case Instruction::Mul: { + std::array Ops = getSortedOperandsOfBinOp(I); // `mul` is negatible if one of its operands is negatible. Value *NegatedOp, *OtherOp; // First try the second operand, in case it's a constant it will be best to // just invert it instead of sinking the `neg` deeper. - if (Value *NegOp1 = negate(I->getOperand(1), Depth + 1)) { + if (Value *NegOp1 = negate(Ops[1], Depth + 1)) { NegatedOp = NegOp1; - OtherOp = I->getOperand(0); - } else if (Value *NegOp0 = negate(I->getOperand(0), Depth + 1)) { + OtherOp = Ops[0]; + } else if (Value *NegOp0 = negate(Ops[0], Depth + 1)) { NegatedOp = NegOp0; - OtherOp = I->getOperand(1); + OtherOp = Ops[1]; } else // Can't negate either of them. return nullptr; @@ -430,7 +487,7 @@ LLVM_NODISCARD Optional Negator::run(Value *Root) { } LLVM_NODISCARD Value *Negator::Negate(bool LHSIsZero, Value *Root, - InstCombiner &IC) { + InstCombinerImpl &IC) { ++NegatorTotalNegationsAttempted; LLVM_DEBUG(dbgs() << "Negator: attempting to sink negation into " << *Root << "\n"); diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp index 2b2f2e1b9470..d687ec654438 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp @@ -13,11 +13,14 @@ #include "InstCombineInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include "llvm/Transforms/Utils/Local.h" + using namespace llvm; using namespace llvm::PatternMatch; @@ -27,10 +30,16 @@ static cl::opt MaxNumPhis("instcombine-max-num-phis", cl::init(512), cl::desc("Maximum number phis to handle in intptr/ptrint folding")); +STATISTIC(NumPHIsOfInsertValues, + "Number of phi-of-insertvalue turned into insertvalue-of-phis"); +STATISTIC(NumPHIsOfExtractValues, + "Number of phi-of-extractvalue turned into extractvalue-of-phi"); +STATISTIC(NumPHICSEs, "Number of PHI's that got CSE'd"); + /// The PHI arguments will be folded into a single operation with a PHI node /// as input. The debug location of the single operation will be the merged /// locations of the original PHI node arguments. -void InstCombiner::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) { +void InstCombinerImpl::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) { auto *FirstInst = cast(PN.getIncomingValue(0)); Inst->setDebugLoc(FirstInst->getDebugLoc()); // We do not expect a CallInst here, otherwise, N-way merging of DebugLoc @@ -93,7 +102,7 @@ void InstCombiner::PHIArgMergedDebugLoc(Instruction *Inst, PHINode &PN) { // ptr_val_inc = ... // ... // -Instruction *InstCombiner::FoldIntegerTypedPHI(PHINode &PN) { +Instruction *InstCombinerImpl::foldIntegerTypedPHI(PHINode &PN) { if (!PN.getType()->isIntegerTy()) return nullptr; if (!PN.hasOneUse()) @@ -290,9 +299,86 @@ Instruction *InstCombiner::FoldIntegerTypedPHI(PHINode &PN) { IntToPtr->getOperand(0)->getType()); } +/// If we have something like phi [insertvalue(a,b,0), insertvalue(c,d,0)], +/// turn this into a phi[a,c] and phi[b,d] and a single insertvalue. +Instruction * +InstCombinerImpl::foldPHIArgInsertValueInstructionIntoPHI(PHINode &PN) { + auto *FirstIVI = cast(PN.getIncomingValue(0)); + + // Scan to see if all operands are `insertvalue`'s with the same indicies, + // and all have a single use. + for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { + auto *I = dyn_cast(PN.getIncomingValue(i)); + if (!I || !I->hasOneUser() || I->getIndices() != FirstIVI->getIndices()) + return nullptr; + } + + // For each operand of an `insertvalue` + std::array NewOperands; + for (int OpIdx : {0, 1}) { + auto *&NewOperand = NewOperands[OpIdx]; + // Create a new PHI node to receive the values the operand has in each + // incoming basic block. + NewOperand = PHINode::Create( + FirstIVI->getOperand(OpIdx)->getType(), PN.getNumIncomingValues(), + FirstIVI->getOperand(OpIdx)->getName() + ".pn"); + // And populate each operand's PHI with said values. + for (auto Incoming : zip(PN.blocks(), PN.incoming_values())) + NewOperand->addIncoming( + cast(std::get<1>(Incoming))->getOperand(OpIdx), + std::get<0>(Incoming)); + InsertNewInstBefore(NewOperand, PN); + } + + // And finally, create `insertvalue` over the newly-formed PHI nodes. + auto *NewIVI = InsertValueInst::Create(NewOperands[0], NewOperands[1], + FirstIVI->getIndices(), PN.getName()); + + PHIArgMergedDebugLoc(NewIVI, PN); + ++NumPHIsOfInsertValues; + return NewIVI; +} + +/// If we have something like phi [extractvalue(a,0), extractvalue(b,0)], +/// turn this into a phi[a,b] and a single extractvalue. +Instruction * +InstCombinerImpl::foldPHIArgExtractValueInstructionIntoPHI(PHINode &PN) { + auto *FirstEVI = cast(PN.getIncomingValue(0)); + + // Scan to see if all operands are `extractvalue`'s with the same indicies, + // and all have a single use. + for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { + auto *I = dyn_cast(PN.getIncomingValue(i)); + if (!I || !I->hasOneUser() || I->getIndices() != FirstEVI->getIndices() || + I->getAggregateOperand()->getType() != + FirstEVI->getAggregateOperand()->getType()) + return nullptr; + } + + // Create a new PHI node to receive the values the aggregate operand has + // in each incoming basic block. + auto *NewAggregateOperand = PHINode::Create( + FirstEVI->getAggregateOperand()->getType(), PN.getNumIncomingValues(), + FirstEVI->getAggregateOperand()->getName() + ".pn"); + // And populate the PHI with said values. + for (auto Incoming : zip(PN.blocks(), PN.incoming_values())) + NewAggregateOperand->addIncoming( + cast(std::get<1>(Incoming))->getAggregateOperand(), + std::get<0>(Incoming)); + InsertNewInstBefore(NewAggregateOperand, PN); + + // And finally, create `extractvalue` over the newly-formed PHI nodes. + auto *NewEVI = ExtractValueInst::Create(NewAggregateOperand, + FirstEVI->getIndices(), PN.getName()); + + PHIArgMergedDebugLoc(NewEVI, PN); + ++NumPHIsOfExtractValues; + return NewEVI; +} + /// If we have something like phi [add (a,b), add(a,c)] and if a/b/c and the -/// adds all have a single use, turn this into a phi and a single binop. -Instruction *InstCombiner::FoldPHIArgBinOpIntoPHI(PHINode &PN) { +/// adds all have a single user, turn this into a phi and a single binop. +Instruction *InstCombinerImpl::foldPHIArgBinOpIntoPHI(PHINode &PN) { Instruction *FirstInst = cast(PN.getIncomingValue(0)); assert(isa(FirstInst) || isa(FirstInst)); unsigned Opc = FirstInst->getOpcode(); @@ -302,10 +388,10 @@ Instruction *InstCombiner::FoldPHIArgBinOpIntoPHI(PHINode &PN) { Type *LHSType = LHSVal->getType(); Type *RHSType = RHSVal->getType(); - // Scan to see if all operands are the same opcode, and all have one use. + // Scan to see if all operands are the same opcode, and all have one user. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { Instruction *I = dyn_cast(PN.getIncomingValue(i)); - if (!I || I->getOpcode() != Opc || !I->hasOneUse() || + if (!I || I->getOpcode() != Opc || !I->hasOneUser() || // Verify type of the LHS matches so we don't fold cmp's of different // types. I->getOperand(0)->getType() != LHSType || @@ -385,7 +471,7 @@ Instruction *InstCombiner::FoldPHIArgBinOpIntoPHI(PHINode &PN) { return NewBinOp; } -Instruction *InstCombiner::FoldPHIArgGEPIntoPHI(PHINode &PN) { +Instruction *InstCombinerImpl::foldPHIArgGEPIntoPHI(PHINode &PN) { GetElementPtrInst *FirstInst =cast(PN.getIncomingValue(0)); SmallVector FixedOperands(FirstInst->op_begin(), @@ -401,11 +487,12 @@ Instruction *InstCombiner::FoldPHIArgGEPIntoPHI(PHINode &PN) { bool AllInBounds = true; - // Scan to see if all operands are the same opcode, and all have one use. + // Scan to see if all operands are the same opcode, and all have one user. for (unsigned i = 1; i != PN.getNumIncomingValues(); ++i) { - GetElementPtrInst *GEP= dyn_cast(PN.getIncomingValue(i)); - if (!GEP || !GEP->hasOneUse() || GEP->getType() != FirstInst->getType() || - GEP->getNumOperands() != FirstInst->getNumOperands()) + GetElementPtrInst *GEP = + dyn_cast(PN.getIncomingValue(i)); + if (!GEP || !GEP->hasOneUser() || GEP->getType() != FirstInst->getType() || + GEP->getNumOperands() != FirstInst->getNumOperands()) return nullptr; AllInBounds &= GEP->isInBounds(); @@ -494,7 +581,6 @@ Instruction *InstCombiner::FoldPHIArgGEPIntoPHI(PHINode &PN) { return NewGEP; } - /// Return true if we know that it is safe to sink the load out of the block /// that defines it. This means that it must be obvious the value of the load is /// not changed from the point of the load to the end of the block it is in. @@ -540,7 +626,7 @@ static bool isSafeAndProfitableToSinkLoad(LoadInst *L) { return true; } -Instruction *InstCombiner::FoldPHIArgLoadIntoPHI(PHINode &PN) { +Instruction *InstCombinerImpl::foldPHIArgLoadIntoPHI(PHINode &PN) { LoadInst *FirstLI = cast(PN.getIncomingValue(0)); // FIXME: This is overconservative; this transform is allowed in some cases @@ -573,7 +659,7 @@ Instruction *InstCombiner::FoldPHIArgLoadIntoPHI(PHINode &PN) { // Check to see if all arguments are the same operation. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { LoadInst *LI = dyn_cast(PN.getIncomingValue(i)); - if (!LI || !LI->hasOneUse()) + if (!LI || !LI->hasOneUser()) return nullptr; // We can't sink the load if the loaded value could be modified between @@ -654,7 +740,7 @@ Instruction *InstCombiner::FoldPHIArgLoadIntoPHI(PHINode &PN) { /// TODO: This function could handle other cast types, but then it might /// require special-casing a cast from the 'i1' type. See the comment in /// FoldPHIArgOpIntoPHI() about pessimizing illegal integer types. -Instruction *InstCombiner::FoldPHIArgZextsIntoPHI(PHINode &Phi) { +Instruction *InstCombinerImpl::foldPHIArgZextsIntoPHI(PHINode &Phi) { // We cannot create a new instruction after the PHI if the terminator is an // EHPad because there is no valid insertion point. if (Instruction *TI = Phi.getParent()->getTerminator()) @@ -686,8 +772,8 @@ Instruction *InstCombiner::FoldPHIArgZextsIntoPHI(PHINode &Phi) { unsigned NumConsts = 0; for (Value *V : Phi.incoming_values()) { if (auto *Zext = dyn_cast(V)) { - // All zexts must be identical and have one use. - if (Zext->getSrcTy() != NarrowType || !Zext->hasOneUse()) + // All zexts must be identical and have one user. + if (Zext->getSrcTy() != NarrowType || !Zext->hasOneUser()) return nullptr; NewIncoming.push_back(Zext->getOperand(0)); NumZexts++; @@ -728,7 +814,7 @@ Instruction *InstCombiner::FoldPHIArgZextsIntoPHI(PHINode &Phi) { /// If all operands to a PHI node are the same "unary" operator and they all are /// only used by the PHI, PHI together their inputs, and do the operation once, /// to the result of the PHI. -Instruction *InstCombiner::FoldPHIArgOpIntoPHI(PHINode &PN) { +Instruction *InstCombinerImpl::foldPHIArgOpIntoPHI(PHINode &PN) { // We cannot create a new instruction after the PHI if the terminator is an // EHPad because there is no valid insertion point. if (Instruction *TI = PN.getParent()->getTerminator()) @@ -738,9 +824,13 @@ Instruction *InstCombiner::FoldPHIArgOpIntoPHI(PHINode &PN) { Instruction *FirstInst = cast(PN.getIncomingValue(0)); if (isa(FirstInst)) - return FoldPHIArgGEPIntoPHI(PN); + return foldPHIArgGEPIntoPHI(PN); if (isa(FirstInst)) - return FoldPHIArgLoadIntoPHI(PN); + return foldPHIArgLoadIntoPHI(PN); + if (isa(FirstInst)) + return foldPHIArgInsertValueInstructionIntoPHI(PN); + if (isa(FirstInst)) + return foldPHIArgExtractValueInstructionIntoPHI(PN); // Scan the instruction, looking for input operations that can be folded away. // If all input operands to the phi are the same instruction (e.g. a cast from @@ -763,7 +853,7 @@ Instruction *InstCombiner::FoldPHIArgOpIntoPHI(PHINode &PN) { // otherwise call FoldPHIArgBinOpIntoPHI. ConstantOp = dyn_cast(FirstInst->getOperand(1)); if (!ConstantOp) - return FoldPHIArgBinOpIntoPHI(PN); + return foldPHIArgBinOpIntoPHI(PN); } else { return nullptr; // Cannot fold this operation. } @@ -771,7 +861,7 @@ Instruction *InstCombiner::FoldPHIArgOpIntoPHI(PHINode &PN) { // Check to see if all arguments are the same operation. for (unsigned i = 1, e = PN.getNumIncomingValues(); i != e; ++i) { Instruction *I = dyn_cast(PN.getIncomingValue(i)); - if (!I || !I->hasOneUse() || !I->isSameOperationAs(FirstInst)) + if (!I || !I->hasOneUser() || !I->isSameOperationAs(FirstInst)) return nullptr; if (CastSrcTy) { if (I->getOperand(0)->getType() != CastSrcTy) @@ -923,7 +1013,7 @@ struct LoweredPHIRecord { LoweredPHIRecord(PHINode *pn, unsigned Sh) : PN(pn), Shift(Sh), Width(0) {} }; -} +} // namespace namespace llvm { template<> @@ -944,7 +1034,7 @@ namespace llvm { LHS.Width == RHS.Width; } }; -} +} // namespace llvm /// This is an integer PHI and we know that it has an illegal type: see if it is @@ -955,7 +1045,7 @@ namespace llvm { /// TODO: The user of the trunc may be an bitcast to float/double/vector or an /// inttoptr. We should produce new PHIs in the right type. /// -Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) { +Instruction *InstCombinerImpl::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) { // PHIUsers - Keep track of all of the truncated values extracted from a set // of PHIs, along with their offset. These are the things we want to rewrite. SmallVector PHIUsers; @@ -1129,13 +1219,85 @@ Instruction *InstCombiner::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) { return replaceInstUsesWith(FirstPhi, Undef); } +static Value *SimplifyUsingControlFlow(InstCombiner &Self, PHINode &PN, + const DominatorTree &DT) { + // Simplify the following patterns: + // if (cond) + // / \ + // ... ... + // \ / + // phi [true] [false] + if (!PN.getType()->isIntegerTy(1)) + return nullptr; + + if (PN.getNumOperands() != 2) + return nullptr; + + // Make sure all inputs are constants. + if (!all_of(PN.operands(), [](Value *V) { return isa(V); })) + return nullptr; + + BasicBlock *BB = PN.getParent(); + // Do not bother with unreachable instructions. + if (!DT.isReachableFromEntry(BB)) + return nullptr; + + // Same inputs. + if (PN.getOperand(0) == PN.getOperand(1)) + return PN.getOperand(0); + + BasicBlock *TruePred = nullptr, *FalsePred = nullptr; + for (auto *Pred : predecessors(BB)) { + auto *Input = cast(PN.getIncomingValueForBlock(Pred)); + if (Input->isAllOnesValue()) + TruePred = Pred; + else + FalsePred = Pred; + } + assert(TruePred && FalsePred && "Must be!"); + + // Check which edge of the dominator dominates the true input. If it is the + // false edge, we should invert the condition. + auto *IDom = DT.getNode(BB)->getIDom()->getBlock(); + auto *BI = dyn_cast(IDom->getTerminator()); + if (!BI || BI->isUnconditional()) + return nullptr; + + // Check that edges outgoing from the idom's terminators dominate respective + // inputs of the Phi. + BasicBlockEdge TrueOutEdge(IDom, BI->getSuccessor(0)); + BasicBlockEdge FalseOutEdge(IDom, BI->getSuccessor(1)); + + BasicBlockEdge TrueIncEdge(TruePred, BB); + BasicBlockEdge FalseIncEdge(FalsePred, BB); + + auto *Cond = BI->getCondition(); + if (DT.dominates(TrueOutEdge, TrueIncEdge) && + DT.dominates(FalseOutEdge, FalseIncEdge)) + // This Phi is actually equivalent to branching condition of IDom. + return Cond; + else if (DT.dominates(TrueOutEdge, FalseIncEdge) && + DT.dominates(FalseOutEdge, TrueIncEdge)) { + // This Phi is actually opposite to branching condition of IDom. We invert + // the condition that will potentially open up some opportunities for + // sinking. + auto InsertPt = BB->getFirstInsertionPt(); + if (InsertPt != BB->end()) { + Self.Builder.SetInsertPoint(&*InsertPt); + return Self.Builder.CreateNot(Cond); + } + } + + return nullptr; +} + // PHINode simplification // -Instruction *InstCombiner::visitPHINode(PHINode &PN) { +Instruction *InstCombinerImpl::visitPHINode(PHINode &PN) { if (Value *V = SimplifyInstruction(&PN, SQ.getWithInstruction(&PN))) return replaceInstUsesWith(PN, V); - if (Instruction *Result = FoldPHIArgZextsIntoPHI(PN)) + if (Instruction *Result = foldPHIArgZextsIntoPHI(PN)) return Result; // If all PHI operands are the same operation, pull them through the PHI, @@ -1143,18 +1305,16 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) { if (isa(PN.getIncomingValue(0)) && isa(PN.getIncomingValue(1)) && cast(PN.getIncomingValue(0))->getOpcode() == - cast(PN.getIncomingValue(1))->getOpcode() && - // FIXME: The hasOneUse check will fail for PHIs that use the value more - // than themselves more than once. - PN.getIncomingValue(0)->hasOneUse()) - if (Instruction *Result = FoldPHIArgOpIntoPHI(PN)) + cast(PN.getIncomingValue(1))->getOpcode() && + PN.getIncomingValue(0)->hasOneUser()) + if (Instruction *Result = foldPHIArgOpIntoPHI(PN)) return Result; // If this is a trivial cycle in the PHI node graph, remove it. Basically, if // this PHI only has a single use (a PHI), and if that PHI only has one use (a // PHI)... break the cycle. if (PN.hasOneUse()) { - if (Instruction *Result = FoldIntegerTypedPHI(PN)) + if (Instruction *Result = foldIntegerTypedPHI(PN)) return Result; Instruction *PHIUser = cast(PN.user_back()); @@ -1267,6 +1427,21 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) { } } + // Is there an identical PHI node in this basic block? + for (PHINode &IdenticalPN : PN.getParent()->phis()) { + // Ignore the PHI node itself. + if (&IdenticalPN == &PN) + continue; + // Note that even though we've just canonicalized this PHI, due to the + // worklist visitation order, there are no guarantess that *every* PHI + // has been canonicalized, so we can't just compare operands ranges. + if (!PN.isIdenticalToWhenDefined(&IdenticalPN)) + continue; + // Just use that PHI instead then. + ++NumPHICSEs; + return replaceInstUsesWith(PN, &IdenticalPN); + } + // If this is an integer PHI and we know that it has an illegal type, see if // it is only used by trunc or trunc(lshr) operations. If so, we split the // PHI into the various pieces being extracted. This sort of thing is @@ -1276,5 +1451,9 @@ Instruction *InstCombiner::visitPHINode(PHINode &PN) { if (Instruction *Res = SliceUpIllegalIntegerPHI(PN)) return Res; + // Ultimately, try to replace this Phi with a dominating condition. + if (auto *V = SimplifyUsingControlFlow(*this, PN, DT)) + return replaceInstUsesWith(PN, V); + return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 17124f717af7..f26c194d31b9 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -38,6 +38,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include #include @@ -46,6 +47,11 @@ using namespace PatternMatch; #define DEBUG_TYPE "instcombine" +/// FIXME: Enabled by default until the pattern is supported well. +static cl::opt EnableUnsafeSelectTransform( + "instcombine-unsafe-select-transform", cl::init(true), + cl::desc("Enable poison-unsafe select to and/or transform")); + static Value *createMinMax(InstCombiner::BuilderTy &Builder, SelectPatternFlavor SPF, Value *A, Value *B) { CmpInst::Predicate Pred = getMinMaxPred(SPF); @@ -57,7 +63,7 @@ static Value *createMinMax(InstCombiner::BuilderTy &Builder, /// constant of a binop. static Instruction *foldSelectBinOpIdentity(SelectInst &Sel, const TargetLibraryInfo &TLI, - InstCombiner &IC) { + InstCombinerImpl &IC) { // The select condition must be an equality compare with a constant operand. Value *X; Constant *C; @@ -258,29 +264,9 @@ static unsigned getSelectFoldableOperands(BinaryOperator *I) { } } -/// For the same transformation as the previous function, return the identity -/// constant that goes into the select. -static APInt getSelectFoldableConstant(BinaryOperator *I) { - switch (I->getOpcode()) { - default: llvm_unreachable("This cannot happen!"); - case Instruction::Add: - case Instruction::Sub: - case Instruction::Or: - case Instruction::Xor: - case Instruction::Shl: - case Instruction::LShr: - case Instruction::AShr: - return APInt::getNullValue(I->getType()->getScalarSizeInBits()); - case Instruction::And: - return APInt::getAllOnesValue(I->getType()->getScalarSizeInBits()); - case Instruction::Mul: - return APInt(I->getType()->getScalarSizeInBits(), 1); - } -} - /// We have (select c, TI, FI), and we know that TI and FI have the same opcode. -Instruction *InstCombiner::foldSelectOpOp(SelectInst &SI, Instruction *TI, - Instruction *FI) { +Instruction *InstCombinerImpl::foldSelectOpOp(SelectInst &SI, Instruction *TI, + Instruction *FI) { // Don't break up min/max patterns. The hasOneUse checks below prevent that // for most cases, but vector min/max with bitcasts can be transformed. If the // one-use restrictions are eased for other patterns, we still don't want to @@ -302,10 +288,9 @@ Instruction *InstCombiner::foldSelectOpOp(SelectInst &SI, Instruction *TI, // The select condition may be a vector. We may only change the operand // type if the vector width remains the same (and matches the condition). if (auto *CondVTy = dyn_cast(CondTy)) { - if (!FIOpndTy->isVectorTy()) - return nullptr; - if (CondVTy->getNumElements() != - cast(FIOpndTy)->getNumElements()) + if (!FIOpndTy->isVectorTy() || + CondVTy->getElementCount() != + cast(FIOpndTy)->getElementCount()) return nullptr; // TODO: If the backend knew how to deal with casts better, we could @@ -418,8 +403,8 @@ static bool isSelect01(const APInt &C1I, const APInt &C2I) { /// Try to fold the select into one of the operands to allow further /// optimization. -Instruction *InstCombiner::foldSelectIntoOp(SelectInst &SI, Value *TrueVal, - Value *FalseVal) { +Instruction *InstCombinerImpl::foldSelectIntoOp(SelectInst &SI, Value *TrueVal, + Value *FalseVal) { // See the comment above GetSelectFoldableOperands for a description of the // transformation we are doing here. if (auto *TVI = dyn_cast(TrueVal)) { @@ -433,14 +418,15 @@ Instruction *InstCombiner::foldSelectIntoOp(SelectInst &SI, Value *TrueVal, } if (OpToFold) { - APInt CI = getSelectFoldableConstant(TVI); + Constant *C = ConstantExpr::getBinOpIdentity(TVI->getOpcode(), + TVI->getType(), true); Value *OOp = TVI->getOperand(2-OpToFold); // Avoid creating select between 2 constants unless it's selecting // between 0, 1 and -1. const APInt *OOpC; bool OOpIsAPInt = match(OOp, m_APInt(OOpC)); - if (!isa(OOp) || (OOpIsAPInt && isSelect01(CI, *OOpC))) { - Value *C = ConstantInt::get(OOp->getType(), CI); + if (!isa(OOp) || + (OOpIsAPInt && isSelect01(C->getUniqueInteger(), *OOpC))) { Value *NewSel = Builder.CreateSelect(SI.getCondition(), OOp, C); NewSel->takeName(TVI); BinaryOperator *BO = BinaryOperator::Create(TVI->getOpcode(), @@ -464,14 +450,15 @@ Instruction *InstCombiner::foldSelectIntoOp(SelectInst &SI, Value *TrueVal, } if (OpToFold) { - APInt CI = getSelectFoldableConstant(FVI); + Constant *C = ConstantExpr::getBinOpIdentity(FVI->getOpcode(), + FVI->getType(), true); Value *OOp = FVI->getOperand(2-OpToFold); // Avoid creating select between 2 constants unless it's selecting // between 0, 1 and -1. const APInt *OOpC; bool OOpIsAPInt = match(OOp, m_APInt(OOpC)); - if (!isa(OOp) || (OOpIsAPInt && isSelect01(CI, *OOpC))) { - Value *C = ConstantInt::get(OOp->getType(), CI); + if (!isa(OOp) || + (OOpIsAPInt && isSelect01(C->getUniqueInteger(), *OOpC))) { Value *NewSel = Builder.CreateSelect(SI.getCondition(), C, OOp); NewSel->takeName(FVI); BinaryOperator *BO = BinaryOperator::Create(FVI->getOpcode(), @@ -782,25 +769,24 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal, // Match unsigned saturated add of 2 variables with an unnecessary 'not'. // There are 8 commuted variants. - // Canonicalize -1 (saturated result) to true value of the select. Just - // swapping the compare operands is legal, because the selected value is the - // same in case of equality, so we can interchange u< and u<=. + // Canonicalize -1 (saturated result) to true value of the select. if (match(FVal, m_AllOnes())) { std::swap(TVal, FVal); - std::swap(Cmp0, Cmp1); + Pred = CmpInst::getInversePredicate(Pred); } if (!match(TVal, m_AllOnes())) return nullptr; - // Canonicalize predicate to 'ULT'. - if (Pred == ICmpInst::ICMP_UGT) { - Pred = ICmpInst::ICMP_ULT; + // Canonicalize predicate to less-than or less-or-equal-than. + if (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_UGE) { std::swap(Cmp0, Cmp1); + Pred = CmpInst::getSwappedPredicate(Pred); } - if (Pred != ICmpInst::ICMP_ULT) + if (Pred != ICmpInst::ICMP_ULT && Pred != ICmpInst::ICMP_ULE) return nullptr; // Match unsigned saturated add of 2 variables with an unnecessary 'not'. + // Strictness of the comparison is irrelevant. Value *Y; if (match(Cmp0, m_Not(m_Value(X))) && match(FVal, m_c_Add(m_Specific(X), m_Value(Y))) && Y == Cmp1) { @@ -809,6 +795,7 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal, return Builder.CreateBinaryIntrinsic(Intrinsic::uadd_sat, X, Y); } // The 'not' op may be included in the sum but not the compare. + // Strictness of the comparison is irrelevant. X = Cmp0; Y = Cmp1; if (match(FVal, m_c_Add(m_Not(m_Specific(X)), m_Specific(Y)))) { @@ -819,7 +806,9 @@ static Value *canonicalizeSaturatedAdd(ICmpInst *Cmp, Value *TVal, Value *FVal, Intrinsic::uadd_sat, BO->getOperand(0), BO->getOperand(1)); } // The overflow may be detected via the add wrapping round. - if (match(Cmp0, m_c_Add(m_Specific(Cmp1), m_Value(Y))) && + // This is only valid for strict comparison! + if (Pred == ICmpInst::ICMP_ULT && + match(Cmp0, m_c_Add(m_Specific(Cmp1), m_Value(Y))) && match(FVal, m_c_Add(m_Specific(Cmp1), m_Specific(Y)))) { // ((X + Y) u< X) ? -1 : (X + Y) --> uadd.sat(X, Y) // ((X + Y) u< Y) ? -1 : (X + Y) --> uadd.sat(X, Y) @@ -1024,9 +1013,9 @@ static bool adjustMinMax(SelectInst &Sel, ICmpInst &Cmp) { /// select (icmp Pred X, C1), C2, X --> select (icmp Pred' X, C2), X, C2 /// Note: if C1 != C2, this will change the icmp constant to the existing /// constant operand of the select. -static Instruction * -canonicalizeMinMaxWithConstant(SelectInst &Sel, ICmpInst &Cmp, - InstCombiner &IC) { +static Instruction *canonicalizeMinMaxWithConstant(SelectInst &Sel, + ICmpInst &Cmp, + InstCombinerImpl &IC) { if (!Cmp.hasOneUse() || !isa(Cmp.getOperand(1))) return nullptr; @@ -1063,105 +1052,29 @@ canonicalizeMinMaxWithConstant(SelectInst &Sel, ICmpInst &Cmp, return &Sel; } -/// There are many select variants for each of ABS/NABS. -/// In matchSelectPattern(), there are different compare constants, compare -/// predicates/operands and select operands. -/// In isKnownNegation(), there are different formats of negated operands. -/// Canonicalize all these variants to 1 pattern. -/// This makes CSE more likely. static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp, - InstCombiner &IC) { + InstCombinerImpl &IC) { if (!Cmp.hasOneUse() || !isa(Cmp.getOperand(1))) return nullptr; - // Choose a sign-bit check for the compare (likely simpler for codegen). - // ABS: (X hasOneUse() || (RHS->hasNUses(2) && CmpUsesNegatedOp))) - return nullptr; + // Note that NSW flag can only be propagated for normal, non-negated abs! + bool IntMinIsPoison = SPF == SelectPatternFlavor::SPF_ABS && + match(RHS, m_NSWNeg(m_Specific(LHS))); + Constant *IntMinIsPoisonC = + ConstantInt::get(Type::getInt1Ty(Sel.getContext()), IntMinIsPoison); + Instruction *Abs = + IC.Builder.CreateBinaryIntrinsic(Intrinsic::abs, LHS, IntMinIsPoisonC); - // Create the canonical compare: icmp slt LHS 0. - if (!CmpCanonicalized) { - Cmp.setPredicate(ICmpInst::ICMP_SLT); - Cmp.setOperand(1, ConstantInt::getNullValue(Cmp.getOperand(0)->getType())); - if (CmpUsesNegatedOp) - Cmp.setOperand(0, LHS); - } - - // Create the canonical RHS: RHS = sub (0, LHS). - if (!RHSCanonicalized) { - assert(RHS->hasOneUse() && "RHS use number is not right"); - RHS = IC.Builder.CreateNeg(LHS); - if (TVal == LHS) { - // Replace false value. - IC.replaceOperand(Sel, 2, RHS); - FVal = RHS; - } else { - // Replace true value. - IC.replaceOperand(Sel, 1, RHS); - TVal = RHS; - } - } + if (SPF == SelectPatternFlavor::SPF_NABS) + return BinaryOperator::CreateNeg(Abs); // Always without NSW flag! - // If the select operands do not change, we're done. - if (SPF == SelectPatternFlavor::SPF_NABS) { - if (TVal == LHS) - return &Sel; - assert(FVal == LHS && "Unexpected results from matchSelectPattern"); - } else { - if (FVal == LHS) - return &Sel; - assert(TVal == LHS && "Unexpected results from matchSelectPattern"); - } - - // We are swapping the select operands, so swap the metadata too. - Sel.swapValues(); - Sel.swapProfMetadata(); - return &Sel; -} - -static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *ReplaceOp, - const SimplifyQuery &Q) { - // If this is a binary operator, try to simplify it with the replaced op - // because we know Op and ReplaceOp are equivalant. - // For example: V = X + 1, Op = X, ReplaceOp = 42 - // Simplifies as: add(42, 1) --> 43 - if (auto *BO = dyn_cast(V)) { - if (BO->getOperand(0) == Op) - return SimplifyBinOp(BO->getOpcode(), ReplaceOp, BO->getOperand(1), Q); - if (BO->getOperand(1) == Op) - return SimplifyBinOp(BO->getOpcode(), BO->getOperand(0), ReplaceOp, Q); - } - - return nullptr; + return IC.replaceInstUsesWith(Sel, Abs); } /// If we have a select with an equality comparison, then we know the value in @@ -1180,30 +1093,97 @@ static Value *simplifyWithOpReplaced(Value *V, Value *Op, Value *ReplaceOp, /// /// We can't replace %sel with %add unless we strip away the flags. /// TODO: Wrapping flags could be preserved in some cases with better analysis. -static Value *foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp, - const SimplifyQuery &Q) { +Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel, + ICmpInst &Cmp) { if (!Cmp.isEquality()) return nullptr; // Canonicalize the pattern to ICMP_EQ by swapping the select operands. Value *TrueVal = Sel.getTrueValue(), *FalseVal = Sel.getFalseValue(); - if (Cmp.getPredicate() == ICmpInst::ICMP_NE) + bool Swapped = false; + if (Cmp.getPredicate() == ICmpInst::ICMP_NE) { std::swap(TrueVal, FalseVal); + Swapped = true; + } + + // In X == Y ? f(X) : Z, try to evaluate f(Y) and replace the operand. + // Make sure Y cannot be undef though, as we might pick different values for + // undef in the icmp and in f(Y). Additionally, take care to avoid replacing + // X == Y ? X : Z with X == Y ? Y : Z, as that would lead to an infinite + // replacement cycle. + Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1); + if (TrueVal != CmpLHS && + isGuaranteedNotToBeUndefOrPoison(CmpRHS, SQ.AC, &Sel, &DT)) { + if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ, + /* AllowRefinement */ true)) + return replaceOperand(Sel, Swapped ? 2 : 1, V); + + // Even if TrueVal does not simplify, we can directly replace a use of + // CmpLHS with CmpRHS, as long as the instruction is not used anywhere + // else and is safe to speculatively execute (we may end up executing it + // with different operands, which should not cause side-effects or trigger + // undefined behavior). Only do this if CmpRHS is a constant, as + // profitability is not clear for other cases. + // FIXME: The replacement could be performed recursively. + if (match(CmpRHS, m_ImmConstant()) && !match(CmpLHS, m_ImmConstant())) + if (auto *I = dyn_cast(TrueVal)) + if (I->hasOneUse() && isSafeToSpeculativelyExecute(I)) + for (Use &U : I->operands()) + if (U == CmpLHS) { + replaceUse(U, CmpRHS); + return &Sel; + } + } + if (TrueVal != CmpRHS && + isGuaranteedNotToBeUndefOrPoison(CmpLHS, SQ.AC, &Sel, &DT)) + if (Value *V = SimplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ, + /* AllowRefinement */ true)) + return replaceOperand(Sel, Swapped ? 2 : 1, V); + + auto *FalseInst = dyn_cast(FalseVal); + if (!FalseInst) + return nullptr; + + // InstSimplify already performed this fold if it was possible subject to + // current poison-generating flags. Try the transform again with + // poison-generating flags temporarily dropped. + bool WasNUW = false, WasNSW = false, WasExact = false, WasInBounds = false; + if (auto *OBO = dyn_cast(FalseVal)) { + WasNUW = OBO->hasNoUnsignedWrap(); + WasNSW = OBO->hasNoSignedWrap(); + FalseInst->setHasNoUnsignedWrap(false); + FalseInst->setHasNoSignedWrap(false); + } + if (auto *PEO = dyn_cast(FalseVal)) { + WasExact = PEO->isExact(); + FalseInst->setIsExact(false); + } + if (auto *GEP = dyn_cast(FalseVal)) { + WasInBounds = GEP->isInBounds(); + GEP->setIsInBounds(false); + } // Try each equivalence substitution possibility. // We have an 'EQ' comparison, so the select's false value will propagate. // Example: // (X == 42) ? 43 : (X + 1) --> (X == 42) ? (X + 1) : (X + 1) --> X + 1 - // (X == 42) ? (X + 1) : 43 --> (X == 42) ? (42 + 1) : 43 --> 43 - Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1); - if (simplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q) == TrueVal || - simplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, Q) == TrueVal || - simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, Q) == FalseVal || - simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, Q) == FalseVal) { - if (auto *FalseInst = dyn_cast(FalseVal)) - FalseInst->dropPoisonGeneratingFlags(); - return FalseVal; - } + if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, SQ, + /* AllowRefinement */ false) == TrueVal || + SimplifyWithOpReplaced(FalseVal, CmpRHS, CmpLHS, SQ, + /* AllowRefinement */ false) == TrueVal) { + return replaceInstUsesWith(Sel, FalseVal); + } + + // Restore poison-generating flags if the transform did not apply. + if (WasNUW) + FalseInst->setHasNoUnsignedWrap(); + if (WasNSW) + FalseInst->setHasNoSignedWrap(); + if (WasExact) + FalseInst->setIsExact(); + if (WasInBounds) + cast(FalseInst)->setIsInBounds(); + return nullptr; } @@ -1253,7 +1233,7 @@ static Instruction *canonicalizeClampLike(SelectInst &Sel0, ICmpInst &Cmp0, APInt::getAllOnesValue( C0->getType()->getScalarSizeInBits())))) return nullptr; // Can't do, have all-ones element[s]. - C0 = AddOne(C0); + C0 = InstCombiner::AddOne(C0); std::swap(X, Sel1); break; case ICmpInst::Predicate::ICMP_UGE: @@ -1313,7 +1293,7 @@ static Instruction *canonicalizeClampLike(SelectInst &Sel0, ICmpInst &Cmp0, APInt::getSignedMaxValue( C2->getType()->getScalarSizeInBits())))) return nullptr; // Can't do, have signed max element[s]. - C2 = AddOne(C2); + C2 = InstCombiner::AddOne(C2); LLVM_FALLTHROUGH; case ICmpInst::Predicate::ICMP_SGE: // Also non-canonical, but here we don't need to change C2, @@ -1360,7 +1340,7 @@ static Instruction *canonicalizeClampLike(SelectInst &Sel0, ICmpInst &Cmp0, // and swap the hands of select. static Instruction * tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp, - InstCombiner &IC) { + InstCombinerImpl &IC) { ICmpInst::Predicate Pred; Value *X; Constant *C0; @@ -1375,7 +1355,7 @@ tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp, // If comparison predicate is non-canonical, then we certainly won't be able // to make it canonical; canonicalizeCmpWithConstant() already tried. - if (!isCanonicalPredicate(Pred)) + if (!InstCombiner::isCanonicalPredicate(Pred)) return nullptr; // If the [input] type of comparison and select type are different, lets abort @@ -1403,7 +1383,8 @@ tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp, return nullptr; // Check the constant we'd have with flipped-strictness predicate. - auto FlippedStrictness = getFlippedStrictnessPredicateAndConstant(Pred, C0); + auto FlippedStrictness = + InstCombiner::getFlippedStrictnessPredicateAndConstant(Pred, C0); if (!FlippedStrictness) return nullptr; @@ -1426,10 +1407,10 @@ tryToReuseConstantFromSelectInComparison(SelectInst &Sel, ICmpInst &Cmp, } /// Visit a SelectInst that has an ICmpInst as its first operand. -Instruction *InstCombiner::foldSelectInstWithICmp(SelectInst &SI, - ICmpInst *ICI) { - if (Value *V = foldSelectValueEquivalence(SI, *ICI, SQ)) - return replaceInstUsesWith(SI, V); +Instruction *InstCombinerImpl::foldSelectInstWithICmp(SelectInst &SI, + ICmpInst *ICI) { + if (Instruction *NewSel = foldSelectValueEquivalence(SI, *ICI)) + return NewSel; if (Instruction *NewSel = canonicalizeMinMaxWithConstant(SI, *ICI, *this)) return NewSel; @@ -1579,11 +1560,11 @@ static bool canSelectOperandBeMappingIntoPredBlock(const Value *V, /// We have an SPF (e.g. a min or max) of an SPF of the form: /// SPF2(SPF1(A, B), C) -Instruction *InstCombiner::foldSPFofSPF(Instruction *Inner, - SelectPatternFlavor SPF1, - Value *A, Value *B, - Instruction &Outer, - SelectPatternFlavor SPF2, Value *C) { +Instruction *InstCombinerImpl::foldSPFofSPF(Instruction *Inner, + SelectPatternFlavor SPF1, Value *A, + Value *B, Instruction &Outer, + SelectPatternFlavor SPF2, + Value *C) { if (Outer.getType() != Inner->getType()) return nullptr; @@ -1900,7 +1881,7 @@ foldOverflowingAddSubSelect(SelectInst &SI, InstCombiner::BuilderTy &Builder) { return CallInst::Create(F, {X, Y}); } -Instruction *InstCombiner::foldSelectExtConst(SelectInst &Sel) { +Instruction *InstCombinerImpl::foldSelectExtConst(SelectInst &Sel) { Constant *C; if (!match(Sel.getTrueValue(), m_Constant(C)) && !match(Sel.getFalseValue(), m_Constant(C))) @@ -1966,10 +1947,11 @@ Instruction *InstCombiner::foldSelectExtConst(SelectInst &Sel) { static Instruction *canonicalizeSelectToShuffle(SelectInst &SI) { Value *CondVal = SI.getCondition(); Constant *CondC; - if (!CondVal->getType()->isVectorTy() || !match(CondVal, m_Constant(CondC))) + auto *CondValTy = dyn_cast(CondVal->getType()); + if (!CondValTy || !match(CondVal, m_Constant(CondC))) return nullptr; - unsigned NumElts = cast(CondVal->getType())->getNumElements(); + unsigned NumElts = CondValTy->getNumElements(); SmallVector Mask; Mask.reserve(NumElts); for (unsigned i = 0; i != NumElts; ++i) { @@ -2001,8 +1983,8 @@ static Instruction *canonicalizeSelectToShuffle(SelectInst &SI) { /// to a vector select by splatting the condition. A splat may get folded with /// other operations in IR and having all operands of a select be vector types /// is likely better for vector codegen. -static Instruction *canonicalizeScalarSelectOfVecs( - SelectInst &Sel, InstCombiner &IC) { +static Instruction *canonicalizeScalarSelectOfVecs(SelectInst &Sel, + InstCombinerImpl &IC) { auto *Ty = dyn_cast(Sel.getType()); if (!Ty) return nullptr; @@ -2015,8 +1997,8 @@ static Instruction *canonicalizeScalarSelectOfVecs( // select (extelt V, Index), T, F --> select (splat V, Index), T, F // Splatting the extracted condition reduces code (we could directly create a // splat shuffle of the source vector to eliminate the intermediate step). - unsigned NumElts = Ty->getNumElements(); - return IC.replaceOperand(Sel, 0, IC.Builder.CreateVectorSplat(NumElts, Cond)); + return IC.replaceOperand( + Sel, 0, IC.Builder.CreateVectorSplat(Ty->getElementCount(), Cond)); } /// Reuse bitcasted operands between a compare and select: @@ -2172,7 +2154,7 @@ static Instruction *moveAddAfterMinMax(SelectPatternFlavor SPF, Value *X, } /// Match a sadd_sat or ssub_sat which is using min/max to clamp the value. -Instruction *InstCombiner::matchSAddSubSat(SelectInst &MinMax1) { +Instruction *InstCombinerImpl::matchSAddSubSat(SelectInst &MinMax1) { Type *Ty = MinMax1.getType(); // We are looking for a tree of: @@ -2293,34 +2275,42 @@ static Instruction *factorizeMinMaxTree(SelectPatternFlavor SPF, Value *LHS, return SelectInst::Create(CmpABC, MinMaxOp, ThirdOp); } -/// Try to reduce a rotate pattern that includes a compare and select into a -/// funnel shift intrinsic. Example: +/// Try to reduce a funnel/rotate pattern that includes a compare and select +/// into a funnel shift intrinsic. Example: /// rotl32(a, b) --> (b == 0 ? a : ((a >> (32 - b)) | (a << b))) /// --> call llvm.fshl.i32(a, a, b) -static Instruction *foldSelectRotate(SelectInst &Sel) { - // The false value of the select must be a rotate of the true value. - Value *Or0, *Or1; - if (!match(Sel.getFalseValue(), m_OneUse(m_Or(m_Value(Or0), m_Value(Or1))))) +/// fshl32(a, b, c) --> (c == 0 ? a : ((b >> (32 - c)) | (a << c))) +/// --> call llvm.fshl.i32(a, b, c) +/// fshr32(a, b, c) --> (c == 0 ? b : ((a >> (32 - c)) | (b << c))) +/// --> call llvm.fshr.i32(a, b, c) +static Instruction *foldSelectFunnelShift(SelectInst &Sel, + InstCombiner::BuilderTy &Builder) { + // This must be a power-of-2 type for a bitmasking transform to be valid. + unsigned Width = Sel.getType()->getScalarSizeInBits(); + if (!isPowerOf2_32(Width)) return nullptr; - Value *TVal = Sel.getTrueValue(); - Value *SA0, *SA1; - if (!match(Or0, m_OneUse(m_LogicalShift(m_Specific(TVal), m_Value(SA0)))) || - !match(Or1, m_OneUse(m_LogicalShift(m_Specific(TVal), m_Value(SA1))))) + BinaryOperator *Or0, *Or1; + if (!match(Sel.getFalseValue(), m_OneUse(m_Or(m_BinOp(Or0), m_BinOp(Or1))))) return nullptr; - auto ShiftOpcode0 = cast(Or0)->getOpcode(); - auto ShiftOpcode1 = cast(Or1)->getOpcode(); - if (ShiftOpcode0 == ShiftOpcode1) + Value *SV0, *SV1, *SA0, *SA1; + if (!match(Or0, m_OneUse(m_LogicalShift(m_Value(SV0), + m_ZExtOrSelf(m_Value(SA0))))) || + !match(Or1, m_OneUse(m_LogicalShift(m_Value(SV1), + m_ZExtOrSelf(m_Value(SA1))))) || + Or0->getOpcode() == Or1->getOpcode()) return nullptr; - // We have one of these patterns so far: - // select ?, TVal, (or (lshr TVal, SA0), (shl TVal, SA1)) - // select ?, TVal, (or (shl TVal, SA0), (lshr TVal, SA1)) - // This must be a power-of-2 rotate for a bitmasking transform to be valid. - unsigned Width = Sel.getType()->getScalarSizeInBits(); - if (!isPowerOf2_32(Width)) - return nullptr; + // Canonicalize to or(shl(SV0, SA0), lshr(SV1, SA1)). + if (Or0->getOpcode() == BinaryOperator::LShr) { + std::swap(Or0, Or1); + std::swap(SV0, SV1); + std::swap(SA0, SA1); + } + assert(Or0->getOpcode() == BinaryOperator::Shl && + Or1->getOpcode() == BinaryOperator::LShr && + "Illegal or(shift,shift) pair"); // Check the shift amounts to see if they are an opposite pair. Value *ShAmt; @@ -2331,6 +2321,15 @@ static Instruction *foldSelectRotate(SelectInst &Sel) { else return nullptr; + // We should now have this pattern: + // select ?, TVal, (or (shl SV0, SA0), (lshr SV1, SA1)) + // The false value of the select must be a funnel-shift of the true value: + // IsFShl -> TVal must be SV0 else TVal must be SV1. + bool IsFshl = (ShAmt == SA0); + Value *TVal = Sel.getTrueValue(); + if ((IsFshl && TVal != SV0) || (!IsFshl && TVal != SV1)) + return nullptr; + // Finally, see if the select is filtering out a shift-by-zero. Value *Cond = Sel.getCondition(); ICmpInst::Predicate Pred; @@ -2338,13 +2337,21 @@ static Instruction *foldSelectRotate(SelectInst &Sel) { Pred != ICmpInst::ICMP_EQ) return nullptr; - // This is a rotate that avoids shift-by-bitwidth UB in a suboptimal way. + // If this is not a rotate then the select was blocking poison from the + // 'shift-by-zero' non-TVal, but a funnel shift won't - so freeze it. + if (SV0 != SV1) { + if (IsFshl && !llvm::isGuaranteedNotToBePoison(SV1)) + SV1 = Builder.CreateFreeze(SV1); + else if (!IsFshl && !llvm::isGuaranteedNotToBePoison(SV0)) + SV0 = Builder.CreateFreeze(SV0); + } + + // This is a funnel/rotate that avoids shift-by-bitwidth UB in a suboptimal way. // Convert to funnel shift intrinsic. - bool IsFshl = (ShAmt == SA0 && ShiftOpcode0 == BinaryOperator::Shl) || - (ShAmt == SA1 && ShiftOpcode1 == BinaryOperator::Shl); Intrinsic::ID IID = IsFshl ? Intrinsic::fshl : Intrinsic::fshr; Function *F = Intrinsic::getDeclaration(Sel.getModule(), IID, Sel.getType()); - return IntrinsicInst::Create(F, { TVal, TVal, ShAmt }); + ShAmt = Builder.CreateZExt(ShAmt, Sel.getType()); + return IntrinsicInst::Create(F, { SV0, SV1, ShAmt }); } static Instruction *foldSelectToCopysign(SelectInst &Sel, @@ -2368,7 +2375,8 @@ static Instruction *foldSelectToCopysign(SelectInst &Sel, bool IsTrueIfSignSet; ICmpInst::Predicate Pred; if (!match(Cond, m_OneUse(m_ICmp(Pred, m_BitCast(m_Value(X)), m_APInt(C)))) || - !isSignBitCheck(Pred, *C, IsTrueIfSignSet) || X->getType() != SelType) + !InstCombiner::isSignBitCheck(Pred, *C, IsTrueIfSignSet) || + X->getType() != SelType) return nullptr; // If needed, negate the value that will be the sign argument of the copysign: @@ -2389,7 +2397,7 @@ static Instruction *foldSelectToCopysign(SelectInst &Sel, return CopySign; } -Instruction *InstCombiner::foldVectorSelect(SelectInst &Sel) { +Instruction *InstCombinerImpl::foldVectorSelect(SelectInst &Sel) { auto *VecTy = dyn_cast(Sel.getType()); if (!VecTy) return nullptr; @@ -2469,6 +2477,10 @@ static Instruction *foldSelectToPhiImpl(SelectInst &Sel, BasicBlock *BB, } else return nullptr; + // Make sure the branches are actually different. + if (TrueSucc == FalseSucc) + return nullptr; + // We want to replace select %cond, %a, %b with a phi that takes value %a // for all incoming edges that are dominated by condition `%cond == true`, // and value %b for edges dominated by condition `%cond == false`. If %a @@ -2515,7 +2527,33 @@ static Instruction *foldSelectToPhi(SelectInst &Sel, const DominatorTree &DT, return nullptr; } -Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { +static Value *foldSelectWithFrozenICmp(SelectInst &Sel, InstCombiner::BuilderTy &Builder) { + FreezeInst *FI = dyn_cast(Sel.getCondition()); + if (!FI) + return nullptr; + + Value *Cond = FI->getOperand(0); + Value *TrueVal = Sel.getTrueValue(), *FalseVal = Sel.getFalseValue(); + + // select (freeze(x == y)), x, y --> y + // select (freeze(x != y)), x, y --> x + // The freeze should be only used by this select. Otherwise, remaining uses of + // the freeze can observe a contradictory value. + // c = freeze(x == y) ; Let's assume that y = poison & x = 42; c is 0 or 1 + // a = select c, x, y ; + // f(a, c) ; f(poison, 1) cannot happen, but if a is folded + // ; to y, this can happen. + CmpInst::Predicate Pred; + if (FI->hasOneUse() && + match(Cond, m_c_ICmp(Pred, m_Specific(TrueVal), m_Specific(FalseVal))) && + (Pred == ICmpInst::ICMP_EQ || Pred == ICmpInst::ICMP_NE)) { + return Pred == ICmpInst::ICMP_EQ ? FalseVal : TrueVal; + } + + return nullptr; +} + +Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { Value *CondVal = SI.getCondition(); Value *TrueVal = SI.getTrueValue(); Value *FalseVal = SI.getFalseValue(); @@ -2551,38 +2589,45 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { if (SelType->isIntOrIntVectorTy(1) && TrueVal->getType() == CondVal->getType()) { - if (match(TrueVal, m_One())) { + if (match(TrueVal, m_One()) && + (EnableUnsafeSelectTransform || impliesPoison(FalseVal, CondVal))) { // Change: A = select B, true, C --> A = or B, C return BinaryOperator::CreateOr(CondVal, FalseVal); } - if (match(TrueVal, m_Zero())) { - // Change: A = select B, false, C --> A = and !B, C - Value *NotCond = Builder.CreateNot(CondVal, "not." + CondVal->getName()); - return BinaryOperator::CreateAnd(NotCond, FalseVal); - } - if (match(FalseVal, m_Zero())) { + if (match(FalseVal, m_Zero()) && + (EnableUnsafeSelectTransform || impliesPoison(TrueVal, CondVal))) { // Change: A = select B, C, false --> A = and B, C return BinaryOperator::CreateAnd(CondVal, TrueVal); } + + // select a, false, b -> select !a, b, false + if (match(TrueVal, m_Zero())) { + Value *NotCond = Builder.CreateNot(CondVal, "not." + CondVal->getName()); + return SelectInst::Create(NotCond, FalseVal, + ConstantInt::getFalse(SelType)); + } + // select a, b, true -> select !a, true, b if (match(FalseVal, m_One())) { - // Change: A = select B, C, true --> A = or !B, C Value *NotCond = Builder.CreateNot(CondVal, "not." + CondVal->getName()); - return BinaryOperator::CreateOr(NotCond, TrueVal); + return SelectInst::Create(NotCond, ConstantInt::getTrue(SelType), + TrueVal); } - // select a, a, b -> a | b - // select a, b, a -> a & b + // select a, a, b -> select a, true, b if (CondVal == TrueVal) - return BinaryOperator::CreateOr(CondVal, FalseVal); + return replaceOperand(SI, 1, ConstantInt::getTrue(SelType)); + // select a, b, a -> select a, b, false if (CondVal == FalseVal) - return BinaryOperator::CreateAnd(CondVal, TrueVal); + return replaceOperand(SI, 2, ConstantInt::getFalse(SelType)); - // select a, ~a, b -> (~a) & b - // select a, b, ~a -> (~a) | b + // select a, !a, b -> select !a, b, false if (match(TrueVal, m_Not(m_Specific(CondVal)))) - return BinaryOperator::CreateAnd(TrueVal, FalseVal); + return SelectInst::Create(TrueVal, FalseVal, + ConstantInt::getFalse(SelType)); + // select a, b, !a -> select !a, true, b if (match(FalseVal, m_Not(m_Specific(CondVal)))) - return BinaryOperator::CreateOr(TrueVal, FalseVal); + return SelectInst::Create(FalseVal, ConstantInt::getTrue(SelType), + TrueVal); } // Selecting between two integer or vector splat integer constants? @@ -2591,7 +2636,10 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { // select i1 %c, <2 x i8> <1, 1>, <2 x i8> <0, 0> // because that may need 3 instructions to splat the condition value: // extend, insertelement, shufflevector. - if (SelType->isIntOrIntVectorTy() && + // + // Do not handle i1 TrueVal and FalseVal otherwise would result in + // zext/sext i1 to i1. + if (SelType->isIntOrIntVectorTy() && !SelType->isIntOrIntVectorTy(1) && CondVal->getType()->isVectorTy() == SelType->isVectorTy()) { // select C, 1, 0 -> zext C to int if (match(TrueVal, m_One()) && match(FalseVal, m_Zero())) @@ -2838,8 +2886,9 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { return replaceOperand(SI, 1, TrueSI->getTrueValue()); } // select(C0, select(C1, a, b), b) -> select(C0&C1, a, b) - // We choose this as normal form to enable folding on the And and shortening - // paths for the values (this helps GetUnderlyingObjects() for example). + // We choose this as normal form to enable folding on the And and + // shortening paths for the values (this helps getUnderlyingObjects() for + // example). if (TrueSI->getFalseValue() == FalseVal && TrueSI->hasOneUse()) { Value *And = Builder.CreateAnd(CondVal, TrueSI->getCondition()); replaceOperand(SI, 0, And); @@ -2922,7 +2971,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { } Value *NotCond; - if (match(CondVal, m_Not(m_Value(NotCond)))) { + if (match(CondVal, m_Not(m_Value(NotCond))) && + !InstCombiner::shouldAvoidAbsorbingNotIntoSelect(SI)) { replaceOperand(SI, 0, NotCond); SI.swapValues(); SI.swapProfMetadata(); @@ -2956,8 +3006,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { if (Instruction *Select = foldSelectBinOpIdentity(SI, TLI, *this)) return Select; - if (Instruction *Rot = foldSelectRotate(SI)) - return Rot; + if (Instruction *Funnel = foldSelectFunnelShift(SI, Builder)) + return Funnel; if (Instruction *Copysign = foldSelectToCopysign(SI, Builder)) return Copysign; @@ -2965,5 +3015,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) { if (Instruction *PN = foldSelectToPhi(SI, DT, Builder)) return replaceInstUsesWith(SI, PN); + if (Value *Fr = foldSelectWithFrozenICmp(SI, Builder)) + return replaceInstUsesWith(SI, Fr); + return nullptr; } diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 0a842b4e1047..7295369365c4 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -15,6 +15,7 @@ #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" using namespace llvm; using namespace PatternMatch; @@ -31,7 +32,7 @@ using namespace PatternMatch; // // AnalyzeForSignBitExtraction indicates that we will only analyze whether this // pattern has any 2 right-shifts that sum to 1 less than original bit width. -Value *InstCombiner::reassociateShiftAmtsOfTwoSameDirectionShifts( +Value *InstCombinerImpl::reassociateShiftAmtsOfTwoSameDirectionShifts( BinaryOperator *Sh0, const SimplifyQuery &SQ, bool AnalyzeForSignBitExtraction) { // Look for a shift of some instruction, ignore zext of shift amount if any. @@ -327,8 +328,8 @@ static Instruction *foldShiftOfShiftedLogic(BinaryOperator &I, if (!LogicInst || !LogicInst->isBitwiseLogicOp() || !LogicInst->hasOneUse()) return nullptr; - const APInt *C0, *C1; - if (!match(I.getOperand(1), m_APInt(C1))) + Constant *C0, *C1; + if (!match(I.getOperand(1), m_Constant(C1))) return nullptr; Instruction::BinaryOps ShiftOpcode = I.getOpcode(); @@ -339,10 +340,12 @@ static Instruction *foldShiftOfShiftedLogic(BinaryOperator &I, // TODO: Remove the one-use check if the other logic operand (Y) is constant. Value *X, *Y; auto matchFirstShift = [&](Value *V) { - return !isa(V) && - match(V, m_OneUse(m_Shift(m_Value(X), m_APInt(C0)))) && - cast(V)->getOpcode() == ShiftOpcode && - (*C0 + *C1).ult(Ty->getScalarSizeInBits()); + BinaryOperator *BO; + APInt Threshold(Ty->getScalarSizeInBits(), Ty->getScalarSizeInBits()); + return match(V, m_BinOp(BO)) && BO->getOpcode() == ShiftOpcode && + match(V, m_OneUse(m_Shift(m_Value(X), m_Constant(C0)))) && + match(ConstantExpr::getAdd(C0, C1), + m_SpecificInt_ICMP(ICmpInst::ICMP_ULT, Threshold)); }; // Logic ops are commutative, so check each operand for a match. @@ -354,13 +357,13 @@ static Instruction *foldShiftOfShiftedLogic(BinaryOperator &I, return nullptr; // shift (logic (shift X, C0), Y), C1 -> logic (shift X, C0+C1), (shift Y, C1) - Constant *ShiftSumC = ConstantInt::get(Ty, *C0 + *C1); + Constant *ShiftSumC = ConstantExpr::getAdd(C0, C1); Value *NewShift1 = Builder.CreateBinOp(ShiftOpcode, X, ShiftSumC); Value *NewShift2 = Builder.CreateBinOp(ShiftOpcode, Y, I.getOperand(1)); return BinaryOperator::Create(LogicInst->getOpcode(), NewShift1, NewShift2); } -Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) { +Instruction *InstCombinerImpl::commonShiftTransforms(BinaryOperator &I) { Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); assert(Op0->getType() == Op1->getType()); @@ -399,15 +402,15 @@ Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) { return BinaryOperator::Create( I.getOpcode(), Builder.CreateBinOp(I.getOpcode(), Op0, C), A); - // X shift (A srem B) -> X shift (A and B-1) iff B is a power of 2. + // X shift (A srem C) -> X shift (A and (C - 1)) iff C is a power of 2. // Because shifts by negative values (which could occur if A were negative) // are undefined. - const APInt *B; - if (Op1->hasOneUse() && match(Op1, m_SRem(m_Value(A), m_Power2(B)))) { + if (Op1->hasOneUse() && match(Op1, m_SRem(m_Value(A), m_Constant(C))) && + match(C, m_Power2())) { // FIXME: Should this get moved into SimplifyDemandedBits by saying we don't // demand the sign bit (and many others) here?? - Value *Rem = Builder.CreateAnd(A, ConstantInt::get(I.getType(), *B - 1), - Op1->getName()); + Constant *Mask = ConstantExpr::getSub(C, ConstantInt::get(I.getType(), 1)); + Value *Rem = Builder.CreateAnd(A, Mask, Op1->getName()); return replaceOperand(I, 1, Rem); } @@ -420,8 +423,8 @@ Instruction *InstCombiner::commonShiftTransforms(BinaryOperator &I) { /// Return true if we can simplify two logical (either left or right) shifts /// that have constant shift amounts: OuterShift (InnerShift X, C1), C2. static bool canEvaluateShiftedShift(unsigned OuterShAmt, bool IsOuterShl, - Instruction *InnerShift, InstCombiner &IC, - Instruction *CxtI) { + Instruction *InnerShift, + InstCombinerImpl &IC, Instruction *CxtI) { assert(InnerShift->isLogicalShift() && "Unexpected instruction type"); // We need constant scalar or constant splat shifts. @@ -472,7 +475,7 @@ static bool canEvaluateShiftedShift(unsigned OuterShAmt, bool IsOuterShl, /// where the client will ask if E can be computed shifted right by 64-bits. If /// this succeeds, getShiftedValue() will be called to produce the value. static bool canEvaluateShifted(Value *V, unsigned NumBits, bool IsLeftShift, - InstCombiner &IC, Instruction *CxtI) { + InstCombinerImpl &IC, Instruction *CxtI) { // We can always evaluate constants shifted. if (isa(V)) return true; @@ -480,31 +483,6 @@ static bool canEvaluateShifted(Value *V, unsigned NumBits, bool IsLeftShift, Instruction *I = dyn_cast(V); if (!I) return false; - // If this is the opposite shift, we can directly reuse the input of the shift - // if the needed bits are already zero in the input. This allows us to reuse - // the value which means that we don't care if the shift has multiple uses. - // TODO: Handle opposite shift by exact value. - ConstantInt *CI = nullptr; - if ((IsLeftShift && match(I, m_LShr(m_Value(), m_ConstantInt(CI)))) || - (!IsLeftShift && match(I, m_Shl(m_Value(), m_ConstantInt(CI))))) { - if (CI->getValue() == NumBits) { - // TODO: Check that the input bits are already zero with MaskedValueIsZero -#if 0 - // If this is a truncate of a logical shr, we can truncate it to a smaller - // lshr iff we know that the bits we would otherwise be shifting in are - // already zeros. - uint32_t OrigBitWidth = OrigTy->getScalarSizeInBits(); - uint32_t BitWidth = Ty->getScalarSizeInBits(); - if (MaskedValueIsZero(I->getOperand(0), - APInt::getHighBitsSet(OrigBitWidth, OrigBitWidth-BitWidth)) && - CI->getLimitedValue(BitWidth) < BitWidth) { - return CanEvaluateTruncated(I->getOperand(0), Ty); - } -#endif - - } - } - // We can't mutate something that has multiple uses: doing so would // require duplicating the instruction in general, which isn't profitable. if (!I->hasOneUse()) return false; @@ -608,7 +586,7 @@ static Value *foldShiftedShift(BinaryOperator *InnerShift, unsigned OuterShAmt, /// When canEvaluateShifted() returns true for an expression, this function /// inserts the new computation that produces the shifted value. static Value *getShiftedValue(Value *V, unsigned NumBits, bool isLeftShift, - InstCombiner &IC, const DataLayout &DL) { + InstCombinerImpl &IC, const DataLayout &DL) { // We can always evaluate constants shifted. if (Constant *C = dyn_cast(V)) { if (isLeftShift) @@ -618,7 +596,7 @@ static Value *getShiftedValue(Value *V, unsigned NumBits, bool isLeftShift, } Instruction *I = cast(V); - IC.Worklist.push(I); + IC.addToWorklist(I); switch (I->getOpcode()) { default: llvm_unreachable("Inconsistency with CanEvaluateShifted"); @@ -666,14 +644,17 @@ static bool canShiftBinOpWithConstantRHS(BinaryOperator &Shift, case Instruction::Add: return Shift.getOpcode() == Instruction::Shl; case Instruction::Or: - case Instruction::Xor: case Instruction::And: return true; + case Instruction::Xor: + // Do not change a 'not' of logical shift because that would create a normal + // 'xor'. The 'not' is likely better for analysis, SCEV, and codegen. + return !(Shift.isLogicalShift() && match(BO, m_Not(m_Value()))); } } -Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, - BinaryOperator &I) { +Instruction *InstCombinerImpl::FoldShiftByConstant(Value *Op0, Constant *Op1, + BinaryOperator &I) { bool isLeftShift = I.getOpcode() == Instruction::Shl; const APInt *Op1C; @@ -695,8 +676,8 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, // See if we can simplify any instructions used by the instruction whose sole // purpose is to compute bits we don't care about. - unsigned TypeBits = Op0->getType()->getScalarSizeInBits(); - + Type *Ty = I.getType(); + unsigned TypeBits = Ty->getScalarSizeInBits(); assert(!Op1C->uge(TypeBits) && "Shift over the type width should have been removed already"); @@ -704,18 +685,20 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, return FoldedShift; // Fold shift2(trunc(shift1(x,c1)), c2) -> trunc(shift2(shift1(x,c1),c2)) - if (TruncInst *TI = dyn_cast(Op0)) { - Instruction *TrOp = dyn_cast(TI->getOperand(0)); + if (auto *TI = dyn_cast(Op0)) { // If 'shift2' is an ashr, we would have to get the sign bit into a funny // place. Don't try to do this transformation in this case. Also, we // require that the input operand is a shift-by-constant so that we have // confidence that the shifts will get folded together. We could do this // xform in more cases, but it is unlikely to be profitable. - if (TrOp && I.isLogicalShift() && TrOp->isShift() && - isa(TrOp->getOperand(1))) { + const APInt *TrShiftAmt; + if (I.isLogicalShift() && + match(TI->getOperand(0), m_Shift(m_Value(), m_APInt(TrShiftAmt)))) { + auto *TrOp = cast(TI->getOperand(0)); + Type *SrcTy = TrOp->getType(); + // Okay, we'll do this xform. Make the shift of shift. - Constant *ShAmt = - ConstantExpr::getZExt(cast(Op1), TrOp->getType()); + Constant *ShAmt = ConstantExpr::getZExt(Op1, SrcTy); // (shift2 (shift1 & 0x00FF), c2) Value *NSh = Builder.CreateBinOp(I.getOpcode(), TrOp, ShAmt, I.getName()); @@ -723,36 +706,27 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, // part of the register be zeros. Emulate this by inserting an AND to // clear the top bits as needed. This 'and' will usually be zapped by // other xforms later if dead. - unsigned SrcSize = TrOp->getType()->getScalarSizeInBits(); - unsigned DstSize = TI->getType()->getScalarSizeInBits(); - APInt MaskV(APInt::getLowBitsSet(SrcSize, DstSize)); + unsigned SrcSize = SrcTy->getScalarSizeInBits(); + Constant *MaskV = + ConstantInt::get(SrcTy, APInt::getLowBitsSet(SrcSize, TypeBits)); // The mask we constructed says what the trunc would do if occurring // between the shifts. We want to know the effect *after* the second // shift. We know that it is a logical shift by a constant, so adjust the // mask as appropriate. - if (I.getOpcode() == Instruction::Shl) - MaskV <<= Op1C->getZExtValue(); - else { - assert(I.getOpcode() == Instruction::LShr && "Unknown logical shift"); - MaskV.lshrInPlace(Op1C->getZExtValue()); - } - + MaskV = ConstantExpr::get(I.getOpcode(), MaskV, ShAmt); // shift1 & 0x00FF - Value *And = Builder.CreateAnd(NSh, - ConstantInt::get(I.getContext(), MaskV), - TI->getName()); - + Value *And = Builder.CreateAnd(NSh, MaskV, TI->getName()); // Return the value truncated to the interesting size. - return new TruncInst(And, I.getType()); + return new TruncInst(And, Ty); } } if (Op0->hasOneUse()) { if (BinaryOperator *Op0BO = dyn_cast(Op0)) { // Turn ((X >> C) + Y) << C -> (X + (Y << C)) & (~0 << C) - Value *V1, *V2; - ConstantInt *CC; + Value *V1; + const APInt *CC; switch (Op0BO->getOpcode()) { default: break; case Instruction::Add: @@ -770,25 +744,22 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, Value *X = Builder.CreateBinOp(Op0BO->getOpcode(), YS, V1, Op0BO->getOperand(1)->getName()); unsigned Op1Val = Op1C->getLimitedValue(TypeBits); - APInt Bits = APInt::getHighBitsSet(TypeBits, TypeBits - Op1Val); - Constant *Mask = ConstantInt::get(I.getContext(), Bits); - if (VectorType *VT = dyn_cast(X->getType())) - Mask = ConstantVector::getSplat(VT->getElementCount(), Mask); + Constant *Mask = ConstantInt::get(Ty, Bits); return BinaryOperator::CreateAnd(X, Mask); } // Turn (Y + ((X >> C) & CC)) << C -> ((X & (CC << C)) + (Y << C)) Value *Op0BOOp1 = Op0BO->getOperand(1); if (isLeftShift && Op0BOOp1->hasOneUse() && - match(Op0BOOp1, - m_And(m_OneUse(m_Shr(m_Value(V1), m_Specific(Op1))), - m_ConstantInt(CC)))) { - Value *YS = // (Y << C) - Builder.CreateShl(Op0BO->getOperand(0), Op1, Op0BO->getName()); + match(Op0BOOp1, m_And(m_OneUse(m_Shr(m_Value(V1), m_Specific(Op1))), + m_APInt(CC)))) { + Value *YS = // (Y << C) + Builder.CreateShl(Op0BO->getOperand(0), Op1, Op0BO->getName()); // X & (CC << C) - Value *XM = Builder.CreateAnd(V1, ConstantExpr::getShl(CC, Op1), - V1->getName()+".mask"); + Value *XM = Builder.CreateAnd( + V1, ConstantExpr::getShl(ConstantInt::get(Ty, *CC), Op1), + V1->getName() + ".mask"); return BinaryOperator::Create(Op0BO->getOpcode(), YS, XM); } LLVM_FALLTHROUGH; @@ -805,25 +776,22 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, Value *X = Builder.CreateBinOp(Op0BO->getOpcode(), V1, YS, Op0BO->getOperand(0)->getName()); unsigned Op1Val = Op1C->getLimitedValue(TypeBits); - APInt Bits = APInt::getHighBitsSet(TypeBits, TypeBits - Op1Val); - Constant *Mask = ConstantInt::get(I.getContext(), Bits); - if (VectorType *VT = dyn_cast(X->getType())) - Mask = ConstantVector::getSplat(VT->getElementCount(), Mask); + Constant *Mask = ConstantInt::get(Ty, Bits); return BinaryOperator::CreateAnd(X, Mask); } // Turn (((X >> C)&CC) + Y) << C -> (X + (Y << C)) & (CC << C) if (isLeftShift && Op0BO->getOperand(0)->hasOneUse() && match(Op0BO->getOperand(0), - m_And(m_OneUse(m_Shr(m_Value(V1), m_Value(V2))), - m_ConstantInt(CC))) && V2 == Op1) { + m_And(m_OneUse(m_Shr(m_Value(V1), m_Specific(Op1))), + m_APInt(CC)))) { Value *YS = // (Y << C) - Builder.CreateShl(Op0BO->getOperand(1), Op1, Op0BO->getName()); + Builder.CreateShl(Op0BO->getOperand(1), Op1, Op0BO->getName()); // X & (CC << C) - Value *XM = Builder.CreateAnd(V1, ConstantExpr::getShl(CC, Op1), - V1->getName()+".mask"); - + Value *XM = Builder.CreateAnd( + V1, ConstantExpr::getShl(ConstantInt::get(Ty, *CC), Op1), + V1->getName() + ".mask"); return BinaryOperator::Create(Op0BO->getOpcode(), XM, YS); } @@ -831,7 +799,6 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, } } - // If the operand is a bitwise operator with a constant RHS, and the // shift is the only use, we can pull it out of the shift. const APInt *Op0C; @@ -915,7 +882,7 @@ Instruction *InstCombiner::FoldShiftByConstant(Value *Op0, Constant *Op1, return nullptr; } -Instruction *InstCombiner::visitShl(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) { const SimplifyQuery Q = SQ.getWithInstruction(&I); if (Value *V = SimplifyShlInst(I.getOperand(0), I.getOperand(1), @@ -955,10 +922,9 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, Mask)); } - // FIXME: we do not yet transform non-exact shr's. The backend (DAGCombine) - // needs a few fixes for the rotate pattern recognition first. const APInt *ShOp1; - if (match(Op0, m_Exact(m_Shr(m_Value(X), m_APInt(ShOp1))))) { + if (match(Op0, m_Exact(m_Shr(m_Value(X), m_APInt(ShOp1)))) && + ShOp1->ult(BitWidth)) { unsigned ShrAmt = ShOp1->getZExtValue(); if (ShrAmt < ShAmt) { // If C1 < C2: (X >>?,exact C1) << C2 --> X << (C2 - C1) @@ -978,7 +944,33 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { } } - if (match(Op0, m_Shl(m_Value(X), m_APInt(ShOp1)))) { + if (match(Op0, m_OneUse(m_Shr(m_Value(X), m_APInt(ShOp1)))) && + ShOp1->ult(BitWidth)) { + unsigned ShrAmt = ShOp1->getZExtValue(); + if (ShrAmt < ShAmt) { + // If C1 < C2: (X >>? C1) << C2 --> X << (C2 - C1) & (-1 << C2) + Constant *ShiftDiff = ConstantInt::get(Ty, ShAmt - ShrAmt); + auto *NewShl = BinaryOperator::CreateShl(X, ShiftDiff); + NewShl->setHasNoUnsignedWrap(I.hasNoUnsignedWrap()); + NewShl->setHasNoSignedWrap(I.hasNoSignedWrap()); + Builder.Insert(NewShl); + APInt Mask(APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt)); + return BinaryOperator::CreateAnd(NewShl, ConstantInt::get(Ty, Mask)); + } + if (ShrAmt > ShAmt) { + // If C1 > C2: (X >>? C1) << C2 --> X >>? (C1 - C2) & (-1 << C2) + Constant *ShiftDiff = ConstantInt::get(Ty, ShrAmt - ShAmt); + auto *OldShr = cast(Op0); + auto *NewShr = + BinaryOperator::Create(OldShr->getOpcode(), X, ShiftDiff); + NewShr->setIsExact(OldShr->isExact()); + Builder.Insert(NewShr); + APInt Mask(APInt::getHighBitsSet(BitWidth, BitWidth - ShAmt)); + return BinaryOperator::CreateAnd(NewShr, ConstantInt::get(Ty, Mask)); + } + } + + if (match(Op0, m_Shl(m_Value(X), m_APInt(ShOp1))) && ShOp1->ult(BitWidth)) { unsigned AmtSum = ShAmt + ShOp1->getZExtValue(); // Oversized shifts are simplified to zero in InstSimplify. if (AmtSum < BitWidth) @@ -1037,7 +1029,7 @@ Instruction *InstCombiner::visitShl(BinaryOperator &I) { return nullptr; } -Instruction *InstCombiner::visitLShr(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) { if (Value *V = SimplifyLShrInst(I.getOperand(0), I.getOperand(1), I.isExact(), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1139,6 +1131,12 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } } + // lshr i32 (X -nsw Y), 31 --> zext (X < Y) + Value *Y; + if (ShAmt == BitWidth - 1 && + match(Op0, m_OneUse(m_NSWSub(m_Value(X), m_Value(Y))))) + return new ZExtInst(Builder.CreateICmpSLT(X, Y), Ty); + if (match(Op0, m_LShr(m_Value(X), m_APInt(ShOp1)))) { unsigned AmtSum = ShAmt + ShOp1->getZExtValue(); // Oversized shifts are simplified to zero in InstSimplify. @@ -1167,7 +1165,7 @@ Instruction *InstCombiner::visitLShr(BinaryOperator &I) { } Instruction * -InstCombiner::foldVariableSignZeroExtensionOfVariableHighBitExtract( +InstCombinerImpl::foldVariableSignZeroExtensionOfVariableHighBitExtract( BinaryOperator &OldAShr) { assert(OldAShr.getOpcode() == Instruction::AShr && "Must be called with arithmetic right-shift instruction only."); @@ -1235,7 +1233,7 @@ InstCombiner::foldVariableSignZeroExtensionOfVariableHighBitExtract( return TruncInst::CreateTruncOrBitCast(NewAShr, OldAShr.getType()); } -Instruction *InstCombiner::visitAShr(BinaryOperator &I) { +Instruction *InstCombinerImpl::visitAShr(BinaryOperator &I) { if (Value *V = SimplifyAShrInst(I.getOperand(0), I.getOperand(1), I.isExact(), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1301,6 +1299,12 @@ Instruction *InstCombiner::visitAShr(BinaryOperator &I) { return new SExtInst(NewSh, Ty); } + // ashr i32 (X -nsw Y), 31 --> sext (X < Y) + Value *Y; + if (ShAmt == BitWidth - 1 && + match(Op0, m_OneUse(m_NSWSub(m_Value(X), m_Value(Y))))) + return new SExtInst(Builder.CreateICmpSLT(X, Y), Ty); + // If the shifted-out value is known-zero, then this is an exact shift. if (!I.isExact() && MaskedValueIsZero(Op0, APInt::getLowBitsSet(BitWidth, ShAmt), 0, &I)) { diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp index 7cfe4c8b5892..c265516213aa 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp @@ -12,29 +12,18 @@ //===----------------------------------------------------------------------===// #include "InstCombineInternal.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/IntrinsicsAMDGPU.h" -#include "llvm/IR/IntrinsicsX86.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/KnownBits.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" using namespace llvm; using namespace llvm::PatternMatch; #define DEBUG_TYPE "instcombine" -namespace { - -struct AMDGPUImageDMaskIntrinsic { - unsigned Intr; -}; - -#define GET_AMDGPUImageDMaskIntrinsicTable_IMPL -#include "InstCombineTables.inc" - -} // end anonymous namespace - /// Check to see if the specified operand of the specified instruction is a /// constant integer. If so, check to see if there are any bits set in the /// constant that are not demanded. If so, shrink the constant and return true. @@ -63,7 +52,7 @@ static bool ShrinkDemandedConstant(Instruction *I, unsigned OpNo, /// Inst is an integer instruction that SimplifyDemandedBits knows about. See if /// the instruction has any properties that allow us to simplify its operands. -bool InstCombiner::SimplifyDemandedInstructionBits(Instruction &Inst) { +bool InstCombinerImpl::SimplifyDemandedInstructionBits(Instruction &Inst) { unsigned BitWidth = Inst.getType()->getScalarSizeInBits(); KnownBits Known(BitWidth); APInt DemandedMask(APInt::getAllOnesValue(BitWidth)); @@ -79,22 +68,20 @@ bool InstCombiner::SimplifyDemandedInstructionBits(Instruction &Inst) { /// This form of SimplifyDemandedBits simplifies the specified instruction /// operand if possible, updating it in place. It returns true if it made any /// change and false otherwise. -bool InstCombiner::SimplifyDemandedBits(Instruction *I, unsigned OpNo, - const APInt &DemandedMask, - KnownBits &Known, - unsigned Depth) { +bool InstCombinerImpl::SimplifyDemandedBits(Instruction *I, unsigned OpNo, + const APInt &DemandedMask, + KnownBits &Known, unsigned Depth) { Use &U = I->getOperandUse(OpNo); Value *NewVal = SimplifyDemandedUseBits(U.get(), DemandedMask, Known, Depth, I); if (!NewVal) return false; if (Instruction* OpInst = dyn_cast(U)) salvageDebugInfo(*OpInst); - + replaceUse(U, NewVal); return true; } - /// This function attempts to replace V with a simpler value based on the /// demanded bits. When this function is called, it is known that only the bits /// set in DemandedMask of the result of V are ever used downstream. @@ -118,11 +105,12 @@ bool InstCombiner::SimplifyDemandedBits(Instruction *I, unsigned OpNo, /// operands based on the information about what bits are demanded. This returns /// some other non-null value if it found out that V is equal to another value /// in the context where the specified bits are demanded, but not for all users. -Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, - KnownBits &Known, unsigned Depth, - Instruction *CxtI) { +Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, + KnownBits &Known, + unsigned Depth, + Instruction *CxtI) { assert(V != nullptr && "Null pointer of Value???"); - assert(Depth <= 6 && "Limit Search Depth"); + assert(Depth <= MaxAnalysisRecursionDepth && "Limit Search Depth"); uint32_t BitWidth = DemandedMask.getBitWidth(); Type *VTy = V->getType(); assert( @@ -139,7 +127,10 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, if (DemandedMask.isNullValue()) // Not demanding any bits from V. return UndefValue::get(VTy); - if (Depth == 6) // Limit search depth. + if (Depth == MaxAnalysisRecursionDepth) + return nullptr; + + if (isa(VTy)) return nullptr; Instruction *I = dyn_cast(V); @@ -268,35 +259,44 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, return InsertNewInstWith(And, *I); } - // If the RHS is a constant, see if we can simplify it. - // FIXME: for XOR, we prefer to force bits to 1 if they will make a -1. - if (ShrinkDemandedConstant(I, 1, DemandedMask)) - return I; + // If the RHS is a constant, see if we can change it. Don't alter a -1 + // constant because that's a canonical 'not' op, and that is better for + // combining, SCEV, and codegen. + const APInt *C; + if (match(I->getOperand(1), m_APInt(C)) && !C->isAllOnesValue()) { + if ((*C | ~DemandedMask).isAllOnesValue()) { + // Force bits to 1 to create a 'not' op. + I->setOperand(1, ConstantInt::getAllOnesValue(VTy)); + return I; + } + // If we can't turn this into a 'not', try to shrink the constant. + if (ShrinkDemandedConstant(I, 1, DemandedMask)) + return I; + } // If our LHS is an 'and' and if it has one use, and if any of the bits we // are flipping are known to be set, then the xor is just resetting those // bits to zero. We can just knock out bits from the 'and' and the 'xor', // simplifying both of them. - if (Instruction *LHSInst = dyn_cast(I->getOperand(0))) + if (Instruction *LHSInst = dyn_cast(I->getOperand(0))) { + ConstantInt *AndRHS, *XorRHS; if (LHSInst->getOpcode() == Instruction::And && LHSInst->hasOneUse() && - isa(I->getOperand(1)) && - isa(LHSInst->getOperand(1)) && + match(I->getOperand(1), m_ConstantInt(XorRHS)) && + match(LHSInst->getOperand(1), m_ConstantInt(AndRHS)) && (LHSKnown.One & RHSKnown.One & DemandedMask) != 0) { - ConstantInt *AndRHS = cast(LHSInst->getOperand(1)); - ConstantInt *XorRHS = cast(I->getOperand(1)); APInt NewMask = ~(LHSKnown.One & RHSKnown.One & DemandedMask); Constant *AndC = - ConstantInt::get(I->getType(), NewMask & AndRHS->getValue()); + ConstantInt::get(I->getType(), NewMask & AndRHS->getValue()); Instruction *NewAnd = BinaryOperator::CreateAnd(I->getOperand(0), AndC); InsertNewInstWith(NewAnd, *I); Constant *XorC = - ConstantInt::get(I->getType(), NewMask & XorRHS->getValue()); + ConstantInt::get(I->getType(), NewMask & XorRHS->getValue()); Instruction *NewXor = BinaryOperator::CreateXor(NewAnd, XorC); return InsertNewInstWith(NewXor, *I); } - + } break; } case Instruction::Select: { @@ -339,7 +339,7 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, // we can. This helps not break apart (or helps put back together) // canonical patterns like min and max. auto CanonicalizeSelectConstant = [](Instruction *I, unsigned OpNo, - APInt DemandedMask) { + const APInt &DemandedMask) { const APInt *SelC; if (!match(I->getOperand(OpNo), m_APInt(SelC))) return false; @@ -367,8 +367,7 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, return I; // Only known if known in both the LHS and RHS. - Known.One = RHSKnown.One & LHSKnown.One; - Known.Zero = RHSKnown.Zero & LHSKnown.Zero; + Known = KnownBits::commonBits(LHSKnown, RHSKnown); break; } case Instruction::ZExt: @@ -391,7 +390,8 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, if (VectorType *DstVTy = dyn_cast(I->getType())) { if (VectorType *SrcVTy = dyn_cast(I->getOperand(0)->getType())) { - if (DstVTy->getNumElements() != SrcVTy->getNumElements()) + if (cast(DstVTy)->getNumElements() != + cast(SrcVTy)->getNumElements()) // Don't touch a bitcast between vectors of different element counts. return nullptr; } else @@ -669,8 +669,9 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, } break; } - case Instruction::SRem: - if (ConstantInt *Rem = dyn_cast(I->getOperand(1))) { + case Instruction::SRem: { + ConstantInt *Rem; + if (match(I->getOperand(1), m_ConstantInt(Rem))) { // X % -1 demands all the bits because we don't want to introduce // INT_MIN % -1 (== undef) by accident. if (Rem->isMinusOne()) @@ -713,6 +714,7 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, Known.makeNonNegative(); } break; + } case Instruction::URem: { KnownBits Known2(BitWidth); APInt AllOnes = APInt::getAllOnesValue(BitWidth); @@ -728,7 +730,6 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, bool KnownBitsComputed = false; if (IntrinsicInst *II = dyn_cast(I)) { switch (II->getIntrinsicID()) { - default: break; case Intrinsic::bswap: { // If the only bits demanded come from one byte of the bswap result, // just shift the input byte into position to eliminate the bswap. @@ -784,39 +785,14 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, KnownBitsComputed = true; break; } - case Intrinsic::x86_mmx_pmovmskb: - case Intrinsic::x86_sse_movmsk_ps: - case Intrinsic::x86_sse2_movmsk_pd: - case Intrinsic::x86_sse2_pmovmskb_128: - case Intrinsic::x86_avx_movmsk_ps_256: - case Intrinsic::x86_avx_movmsk_pd_256: - case Intrinsic::x86_avx2_pmovmskb: { - // MOVMSK copies the vector elements' sign bits to the low bits - // and zeros the high bits. - unsigned ArgWidth; - if (II->getIntrinsicID() == Intrinsic::x86_mmx_pmovmskb) { - ArgWidth = 8; // Arg is x86_mmx, but treated as <8 x i8>. - } else { - auto Arg = II->getArgOperand(0); - auto ArgType = cast(Arg->getType()); - ArgWidth = ArgType->getNumElements(); - } - - // If we don't need any of low bits then return zero, - // we know that DemandedMask is non-zero already. - APInt DemandedElts = DemandedMask.zextOrTrunc(ArgWidth); - if (DemandedElts.isNullValue()) - return ConstantInt::getNullValue(VTy); - - // We know that the upper bits are set to zero. - Known.Zero.setBitsFrom(ArgWidth); - KnownBitsComputed = true; + default: { + // Handle target specific intrinsics + Optional V = targetSimplifyDemandedUseBitsIntrinsic( + *II, DemandedMask, Known, KnownBitsComputed); + if (V.hasValue()) + return V.getValue(); break; } - case Intrinsic::x86_sse42_crc32_64_64: - Known.Zero.setBitsFrom(32); - KnownBitsComputed = true; - break; } } @@ -836,11 +812,9 @@ Value *InstCombiner::SimplifyDemandedUseBits(Value *V, APInt DemandedMask, /// Helper routine of SimplifyDemandedUseBits. It computes Known /// bits. It also tries to handle simplifications that can be done based on /// DemandedMask, but without modifying the Instruction. -Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I, - const APInt &DemandedMask, - KnownBits &Known, - unsigned Depth, - Instruction *CxtI) { +Value *InstCombinerImpl::SimplifyMultipleUseDemandedBits( + Instruction *I, const APInt &DemandedMask, KnownBits &Known, unsigned Depth, + Instruction *CxtI) { unsigned BitWidth = DemandedMask.getBitWidth(); Type *ITy = I->getType(); @@ -925,6 +899,33 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I, break; } + case Instruction::AShr: { + // Compute the Known bits to simplify things downstream. + computeKnownBits(I, Known, Depth, CxtI); + + // If this user is only demanding bits that we know, return the known + // constant. + if (DemandedMask.isSubsetOf(Known.Zero | Known.One)) + return Constant::getIntegerValue(ITy, Known.One); + + // If the right shift operand 0 is a result of a left shift by the same + // amount, this is probably a zero/sign extension, which may be unnecessary, + // if we do not demand any of the new sign bits. So, return the original + // operand instead. + const APInt *ShiftRC; + const APInt *ShiftLC; + Value *X; + unsigned BitWidth = DemandedMask.getBitWidth(); + if (match(I, + m_AShr(m_Shl(m_Value(X), m_APInt(ShiftLC)), m_APInt(ShiftRC))) && + ShiftLC == ShiftRC && + DemandedMask.isSubsetOf(APInt::getLowBitsSet( + BitWidth, BitWidth - ShiftRC->getZExtValue()))) { + return X; + } + + break; + } default: // Compute the Known bits to simplify things downstream. computeKnownBits(I, Known, Depth, CxtI); @@ -940,7 +941,6 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I, return nullptr; } - /// Helper routine of SimplifyDemandedUseBits. It tries to simplify /// "E1 = (X lsr C1) << C2", where the C1 and C2 are constant, into /// "E2 = X << (C2 - C1)" or "E2 = X >> (C1 - C2)", depending on the sign @@ -958,11 +958,9 @@ Value *InstCombiner::SimplifyMultipleUseDemandedBits(Instruction *I, /// /// As with SimplifyDemandedUseBits, it returns NULL if the simplification was /// not successful. -Value * -InstCombiner::simplifyShrShlDemandedBits(Instruction *Shr, const APInt &ShrOp1, - Instruction *Shl, const APInt &ShlOp1, - const APInt &DemandedMask, - KnownBits &Known) { +Value *InstCombinerImpl::simplifyShrShlDemandedBits( + Instruction *Shr, const APInt &ShrOp1, Instruction *Shl, + const APInt &ShlOp1, const APInt &DemandedMask, KnownBits &Known) { if (!ShlOp1 || !ShrOp1) return nullptr; // No-op. @@ -1022,156 +1020,9 @@ InstCombiner::simplifyShrShlDemandedBits(Instruction *Shr, const APInt &ShrOp1, return nullptr; } -/// Implement SimplifyDemandedVectorElts for amdgcn buffer and image intrinsics. -/// -/// Note: This only supports non-TFE/LWE image intrinsic calls; those have -/// struct returns. -Value *InstCombiner::simplifyAMDGCNMemoryIntrinsicDemanded(IntrinsicInst *II, - APInt DemandedElts, - int DMaskIdx) { - - // FIXME: Allow v3i16/v3f16 in buffer intrinsics when the types are fully supported. - if (DMaskIdx < 0 && - II->getType()->getScalarSizeInBits() != 32 && - DemandedElts.getActiveBits() == 3) - return nullptr; - - auto *IIVTy = cast(II->getType()); - unsigned VWidth = IIVTy->getNumElements(); - if (VWidth == 1) - return nullptr; - - IRBuilderBase::InsertPointGuard Guard(Builder); - Builder.SetInsertPoint(II); - - // Assume the arguments are unchanged and later override them, if needed. - SmallVector Args(II->arg_begin(), II->arg_end()); - - if (DMaskIdx < 0) { - // Buffer case. - - const unsigned ActiveBits = DemandedElts.getActiveBits(); - const unsigned UnusedComponentsAtFront = DemandedElts.countTrailingZeros(); - - // Start assuming the prefix of elements is demanded, but possibly clear - // some other bits if there are trailing zeros (unused components at front) - // and update offset. - DemandedElts = (1 << ActiveBits) - 1; - - if (UnusedComponentsAtFront > 0) { - static const unsigned InvalidOffsetIdx = 0xf; - - unsigned OffsetIdx; - switch (II->getIntrinsicID()) { - case Intrinsic::amdgcn_raw_buffer_load: - OffsetIdx = 1; - break; - case Intrinsic::amdgcn_s_buffer_load: - // If resulting type is vec3, there is no point in trimming the - // load with updated offset, as the vec3 would most likely be widened to - // vec4 anyway during lowering. - if (ActiveBits == 4 && UnusedComponentsAtFront == 1) - OffsetIdx = InvalidOffsetIdx; - else - OffsetIdx = 1; - break; - case Intrinsic::amdgcn_struct_buffer_load: - OffsetIdx = 2; - break; - default: - // TODO: handle tbuffer* intrinsics. - OffsetIdx = InvalidOffsetIdx; - break; - } - - if (OffsetIdx != InvalidOffsetIdx) { - // Clear demanded bits and update the offset. - DemandedElts &= ~((1 << UnusedComponentsAtFront) - 1); - auto *Offset = II->getArgOperand(OffsetIdx); - unsigned SingleComponentSizeInBits = - getDataLayout().getTypeSizeInBits(II->getType()->getScalarType()); - unsigned OffsetAdd = - UnusedComponentsAtFront * SingleComponentSizeInBits / 8; - auto *OffsetAddVal = ConstantInt::get(Offset->getType(), OffsetAdd); - Args[OffsetIdx] = Builder.CreateAdd(Offset, OffsetAddVal); - } - } - } else { - // Image case. - - ConstantInt *DMask = cast(II->getArgOperand(DMaskIdx)); - unsigned DMaskVal = DMask->getZExtValue() & 0xf; - - // Mask off values that are undefined because the dmask doesn't cover them - DemandedElts &= (1 << countPopulation(DMaskVal)) - 1; - - unsigned NewDMaskVal = 0; - unsigned OrigLoadIdx = 0; - for (unsigned SrcIdx = 0; SrcIdx < 4; ++SrcIdx) { - const unsigned Bit = 1 << SrcIdx; - if (!!(DMaskVal & Bit)) { - if (!!DemandedElts[OrigLoadIdx]) - NewDMaskVal |= Bit; - OrigLoadIdx++; - } - } - - if (DMaskVal != NewDMaskVal) - Args[DMaskIdx] = ConstantInt::get(DMask->getType(), NewDMaskVal); - } - - unsigned NewNumElts = DemandedElts.countPopulation(); - if (!NewNumElts) - return UndefValue::get(II->getType()); - - if (NewNumElts >= VWidth && DemandedElts.isMask()) { - if (DMaskIdx >= 0) - II->setArgOperand(DMaskIdx, Args[DMaskIdx]); - return nullptr; - } - - // Validate function argument and return types, extracting overloaded types - // along the way. - SmallVector OverloadTys; - if (!Intrinsic::getIntrinsicSignature(II->getCalledFunction(), OverloadTys)) - return nullptr; - - Module *M = II->getParent()->getParent()->getParent(); - Type *EltTy = IIVTy->getElementType(); - Type *NewTy = - (NewNumElts == 1) ? EltTy : FixedVectorType::get(EltTy, NewNumElts); - - OverloadTys[0] = NewTy; - Function *NewIntrin = - Intrinsic::getDeclaration(M, II->getIntrinsicID(), OverloadTys); - - CallInst *NewCall = Builder.CreateCall(NewIntrin, Args); - NewCall->takeName(II); - NewCall->copyMetadata(*II); - - if (NewNumElts == 1) { - return Builder.CreateInsertElement(UndefValue::get(II->getType()), NewCall, - DemandedElts.countTrailingZeros()); - } - - SmallVector EltMask; - unsigned NewLoadIdx = 0; - for (unsigned OrigLoadIdx = 0; OrigLoadIdx < VWidth; ++OrigLoadIdx) { - if (!!DemandedElts[OrigLoadIdx]) - EltMask.push_back(NewLoadIdx++); - else - EltMask.push_back(NewNumElts); - } - - Value *Shuffle = - Builder.CreateShuffleVector(NewCall, UndefValue::get(NewTy), EltMask); - - return Shuffle; -} - /// The specified value produces a vector with any number of elements. -/// This method analyzes which elements of the operand are undef and returns -/// that information in UndefElts. +/// This method analyzes which elements of the operand are undef or poison and +/// returns that information in UndefElts. /// /// DemandedElts contains the set of elements that are actually used by the /// caller, and by default (AllowMultipleUsers equals false) the value is @@ -1182,10 +1033,11 @@ Value *InstCombiner::simplifyAMDGCNMemoryIntrinsicDemanded(IntrinsicInst *II, /// If the information about demanded elements can be used to simplify the /// operation, the operation is simplified, then the resultant value is /// returned. This returns null if no change was made. -Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, - APInt &UndefElts, - unsigned Depth, - bool AllowMultipleUsers) { +Value *InstCombinerImpl::SimplifyDemandedVectorElts(Value *V, + APInt DemandedElts, + APInt &UndefElts, + unsigned Depth, + bool AllowMultipleUsers) { // Cannot analyze scalable type. The number of vector elements is not a // compile-time constant. if (isa(V->getType())) @@ -1196,14 +1048,14 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, assert((DemandedElts & ~EltMask) == 0 && "Invalid DemandedElts!"); if (isa(V)) { - // If the entire vector is undefined, just return this info. + // If the entire vector is undef or poison, just return this info. UndefElts = EltMask; return nullptr; } - if (DemandedElts.isNullValue()) { // If nothing is demanded, provide undef. + if (DemandedElts.isNullValue()) { // If nothing is demanded, provide poison. UndefElts = EltMask; - return UndefValue::get(V->getType()); + return PoisonValue::get(V->getType()); } UndefElts = 0; @@ -1215,11 +1067,11 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, return nullptr; Type *EltTy = cast(V->getType())->getElementType(); - Constant *Undef = UndefValue::get(EltTy); + Constant *Poison = PoisonValue::get(EltTy); SmallVector Elts; for (unsigned i = 0; i != VWidth; ++i) { - if (!DemandedElts[i]) { // If not demanded, set to undef. - Elts.push_back(Undef); + if (!DemandedElts[i]) { // If not demanded, set to poison. + Elts.push_back(Poison); UndefElts.setBit(i); continue; } @@ -1227,12 +1079,9 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, Constant *Elt = C->getAggregateElement(i); if (!Elt) return nullptr; - if (isa(Elt)) { // Already undef. - Elts.push_back(Undef); + Elts.push_back(Elt); + if (isa(Elt)) // Already undef or poison. UndefElts.setBit(i); - } else { // Otherwise, defined. - Elts.push_back(Elt); - } } // If we changed the constant, return it. @@ -1292,12 +1141,12 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, }; if (mayIndexStructType(cast(*I))) break; - + // Conservatively track the demanded elements back through any vector // operands we may have. We know there must be at least one, or we // wouldn't have a vector result to get here. Note that we intentionally // merge the undef bits here since gepping with either an undef base or - // index results in undef. + // index results in undef. for (unsigned i = 0; i < I->getNumOperands(); i++) { if (isa(I->getOperand(i))) { // If the entire vector is undefined, just return this info. @@ -1331,6 +1180,19 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, if (IdxNo < VWidth) PreInsertDemandedElts.clearBit(IdxNo); + // If we only demand the element that is being inserted and that element + // was extracted from the same index in another vector with the same type, + // replace this insert with that other vector. + // Note: This is attempted before the call to simplifyAndSetOp because that + // may change UndefElts to a value that does not match with Vec. + Value *Vec; + if (PreInsertDemandedElts == 0 && + match(I->getOperand(1), + m_ExtractElt(m_Value(Vec), m_SpecificInt(IdxNo))) && + Vec->getType() == I->getType()) { + return Vec; + } + simplifyAndSetOp(I, 0, PreInsertDemandedElts, UndefElts); // If this is inserting an element that isn't demanded, remove this @@ -1349,8 +1211,8 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, assert(Shuffle->getOperand(0)->getType() == Shuffle->getOperand(1)->getType() && "Expected shuffle operands to have same type"); - unsigned OpWidth = - cast(Shuffle->getOperand(0)->getType())->getNumElements(); + unsigned OpWidth = cast(Shuffle->getOperand(0)->getType()) + ->getNumElements(); // Handle trivial case of a splat. Only check the first element of LHS // operand. if (all_of(Shuffle->getShuffleMask(), [](int Elt) { return Elt == 0; }) && @@ -1451,7 +1313,8 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, // this constant vector to single insertelement instruction. // shufflevector V, C, -> // insertelement V, C[ci], ci-n - if (OpWidth == Shuffle->getType()->getNumElements()) { + if (OpWidth == + cast(Shuffle->getType())->getNumElements()) { Value *Op = nullptr; Constant *Value = nullptr; unsigned Idx = -1u; @@ -1538,7 +1401,7 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, // Vector->vector casts only. VectorType *VTy = dyn_cast(I->getOperand(0)->getType()); if (!VTy) break; - unsigned InVWidth = VTy->getNumElements(); + unsigned InVWidth = cast(VTy)->getNumElements(); APInt InputDemandedElts(InVWidth, 0); UndefElts2 = APInt(InVWidth, 0); unsigned Ratio; @@ -1621,227 +1484,19 @@ Value *InstCombiner::SimplifyDemandedVectorElts(Value *V, APInt DemandedElts, if (II->getIntrinsicID() == Intrinsic::masked_gather) simplifyAndSetOp(II, 0, DemandedPtrs, UndefElts2); simplifyAndSetOp(II, 3, DemandedPassThrough, UndefElts3); - + // Output elements are undefined if the element from both sources are. // TODO: can strengthen via mask as well. UndefElts = UndefElts2 & UndefElts3; break; } - case Intrinsic::x86_xop_vfrcz_ss: - case Intrinsic::x86_xop_vfrcz_sd: - // The instructions for these intrinsics are speced to zero upper bits not - // pass them through like other scalar intrinsics. So we shouldn't just - // use Arg0 if DemandedElts[0] is clear like we do for other intrinsics. - // Instead we should return a zero vector. - if (!DemandedElts[0]) { - Worklist.push(II); - return ConstantAggregateZero::get(II->getType()); - } - - // Only the lower element is used. - DemandedElts = 1; - simplifyAndSetOp(II, 0, DemandedElts, UndefElts); - - // Only the lower element is undefined. The high elements are zero. - UndefElts = UndefElts[0]; - break; - - // Unary scalar-as-vector operations that work column-wise. - case Intrinsic::x86_sse_rcp_ss: - case Intrinsic::x86_sse_rsqrt_ss: - simplifyAndSetOp(II, 0, DemandedElts, UndefElts); - - // If lowest element of a scalar op isn't used then use Arg0. - if (!DemandedElts[0]) { - Worklist.push(II); - return II->getArgOperand(0); - } - // TODO: If only low elt lower SQRT to FSQRT (with rounding/exceptions - // checks). - break; - - // Binary scalar-as-vector operations that work column-wise. The high - // elements come from operand 0. The low element is a function of both - // operands. - case Intrinsic::x86_sse_min_ss: - case Intrinsic::x86_sse_max_ss: - case Intrinsic::x86_sse_cmp_ss: - case Intrinsic::x86_sse2_min_sd: - case Intrinsic::x86_sse2_max_sd: - case Intrinsic::x86_sse2_cmp_sd: { - simplifyAndSetOp(II, 0, DemandedElts, UndefElts); - - // If lowest element of a scalar op isn't used then use Arg0. - if (!DemandedElts[0]) { - Worklist.push(II); - return II->getArgOperand(0); - } - - // Only lower element is used for operand 1. - DemandedElts = 1; - simplifyAndSetOp(II, 1, DemandedElts, UndefElts2); - - // Lower element is undefined if both lower elements are undefined. - // Consider things like undef&0. The result is known zero, not undef. - if (!UndefElts2[0]) - UndefElts.clearBit(0); - - break; - } - - // Binary scalar-as-vector operations that work column-wise. The high - // elements come from operand 0 and the low element comes from operand 1. - case Intrinsic::x86_sse41_round_ss: - case Intrinsic::x86_sse41_round_sd: { - // Don't use the low element of operand 0. - APInt DemandedElts2 = DemandedElts; - DemandedElts2.clearBit(0); - simplifyAndSetOp(II, 0, DemandedElts2, UndefElts); - - // If lowest element of a scalar op isn't used then use Arg0. - if (!DemandedElts[0]) { - Worklist.push(II); - return II->getArgOperand(0); - } - - // Only lower element is used for operand 1. - DemandedElts = 1; - simplifyAndSetOp(II, 1, DemandedElts, UndefElts2); - - // Take the high undef elements from operand 0 and take the lower element - // from operand 1. - UndefElts.clearBit(0); - UndefElts |= UndefElts2[0]; - break; - } - - // Three input scalar-as-vector operations that work column-wise. The high - // elements come from operand 0 and the low element is a function of all - // three inputs. - case Intrinsic::x86_avx512_mask_add_ss_round: - case Intrinsic::x86_avx512_mask_div_ss_round: - case Intrinsic::x86_avx512_mask_mul_ss_round: - case Intrinsic::x86_avx512_mask_sub_ss_round: - case Intrinsic::x86_avx512_mask_max_ss_round: - case Intrinsic::x86_avx512_mask_min_ss_round: - case Intrinsic::x86_avx512_mask_add_sd_round: - case Intrinsic::x86_avx512_mask_div_sd_round: - case Intrinsic::x86_avx512_mask_mul_sd_round: - case Intrinsic::x86_avx512_mask_sub_sd_round: - case Intrinsic::x86_avx512_mask_max_sd_round: - case Intrinsic::x86_avx512_mask_min_sd_round: - simplifyAndSetOp(II, 0, DemandedElts, UndefElts); - - // If lowest element of a scalar op isn't used then use Arg0. - if (!DemandedElts[0]) { - Worklist.push(II); - return II->getArgOperand(0); - } - - // Only lower element is used for operand 1 and 2. - DemandedElts = 1; - simplifyAndSetOp(II, 1, DemandedElts, UndefElts2); - simplifyAndSetOp(II, 2, DemandedElts, UndefElts3); - - // Lower element is undefined if all three lower elements are undefined. - // Consider things like undef&0. The result is known zero, not undef. - if (!UndefElts2[0] || !UndefElts3[0]) - UndefElts.clearBit(0); - - break; - - case Intrinsic::x86_sse2_packssdw_128: - case Intrinsic::x86_sse2_packsswb_128: - case Intrinsic::x86_sse2_packuswb_128: - case Intrinsic::x86_sse41_packusdw: - case Intrinsic::x86_avx2_packssdw: - case Intrinsic::x86_avx2_packsswb: - case Intrinsic::x86_avx2_packusdw: - case Intrinsic::x86_avx2_packuswb: - case Intrinsic::x86_avx512_packssdw_512: - case Intrinsic::x86_avx512_packsswb_512: - case Intrinsic::x86_avx512_packusdw_512: - case Intrinsic::x86_avx512_packuswb_512: { - auto *Ty0 = II->getArgOperand(0)->getType(); - unsigned InnerVWidth = cast(Ty0)->getNumElements(); - assert(VWidth == (InnerVWidth * 2) && "Unexpected input size"); - - unsigned NumLanes = Ty0->getPrimitiveSizeInBits() / 128; - unsigned VWidthPerLane = VWidth / NumLanes; - unsigned InnerVWidthPerLane = InnerVWidth / NumLanes; - - // Per lane, pack the elements of the first input and then the second. - // e.g. - // v8i16 PACK(v4i32 X, v4i32 Y) - (X[0..3],Y[0..3]) - // v32i8 PACK(v16i16 X, v16i16 Y) - (X[0..7],Y[0..7]),(X[8..15],Y[8..15]) - for (int OpNum = 0; OpNum != 2; ++OpNum) { - APInt OpDemandedElts(InnerVWidth, 0); - for (unsigned Lane = 0; Lane != NumLanes; ++Lane) { - unsigned LaneIdx = Lane * VWidthPerLane; - for (unsigned Elt = 0; Elt != InnerVWidthPerLane; ++Elt) { - unsigned Idx = LaneIdx + Elt + InnerVWidthPerLane * OpNum; - if (DemandedElts[Idx]) - OpDemandedElts.setBit((Lane * InnerVWidthPerLane) + Elt); - } - } - - // Demand elements from the operand. - APInt OpUndefElts(InnerVWidth, 0); - simplifyAndSetOp(II, OpNum, OpDemandedElts, OpUndefElts); - - // Pack the operand's UNDEF elements, one lane at a time. - OpUndefElts = OpUndefElts.zext(VWidth); - for (unsigned Lane = 0; Lane != NumLanes; ++Lane) { - APInt LaneElts = OpUndefElts.lshr(InnerVWidthPerLane * Lane); - LaneElts = LaneElts.getLoBits(InnerVWidthPerLane); - LaneElts <<= InnerVWidthPerLane * (2 * Lane + OpNum); - UndefElts |= LaneElts; - } - } - break; - } - - // PSHUFB - case Intrinsic::x86_ssse3_pshuf_b_128: - case Intrinsic::x86_avx2_pshuf_b: - case Intrinsic::x86_avx512_pshuf_b_512: - // PERMILVAR - case Intrinsic::x86_avx_vpermilvar_ps: - case Intrinsic::x86_avx_vpermilvar_ps_256: - case Intrinsic::x86_avx512_vpermilvar_ps_512: - case Intrinsic::x86_avx_vpermilvar_pd: - case Intrinsic::x86_avx_vpermilvar_pd_256: - case Intrinsic::x86_avx512_vpermilvar_pd_512: - // PERMV - case Intrinsic::x86_avx2_permd: - case Intrinsic::x86_avx2_permps: { - simplifyAndSetOp(II, 1, DemandedElts, UndefElts); - break; - } - - // SSE4A instructions leave the upper 64-bits of the 128-bit result - // in an undefined state. - case Intrinsic::x86_sse4a_extrq: - case Intrinsic::x86_sse4a_extrqi: - case Intrinsic::x86_sse4a_insertq: - case Intrinsic::x86_sse4a_insertqi: - UndefElts.setHighBits(VWidth / 2); - break; - case Intrinsic::amdgcn_buffer_load: - case Intrinsic::amdgcn_buffer_load_format: - case Intrinsic::amdgcn_raw_buffer_load: - case Intrinsic::amdgcn_raw_buffer_load_format: - case Intrinsic::amdgcn_raw_tbuffer_load: - case Intrinsic::amdgcn_s_buffer_load: - case Intrinsic::amdgcn_struct_buffer_load: - case Intrinsic::amdgcn_struct_buffer_load_format: - case Intrinsic::amdgcn_struct_tbuffer_load: - case Intrinsic::amdgcn_tbuffer_load: - return simplifyAMDGCNMemoryIntrinsicDemanded(II, DemandedElts); default: { - if (getAMDGPUImageDMaskIntrinsic(II->getIntrinsicID())) - return simplifyAMDGCNMemoryIntrinsicDemanded(II, DemandedElts, 0); - + // Handle target specific intrinsics + Optional V = targetSimplifyDemandedVectorEltsIntrinsic( + *II, DemandedElts, UndefElts, UndefElts2, UndefElts3, + simplifyAndSetOp); + if (V.hasValue()) + return V.getValue(); break; } } // switch on IntrinsicID diff --git a/llvm/lib/Transforms/InstCombine/InstCombineTables.td b/llvm/lib/Transforms/InstCombine/InstCombineTables.td deleted file mode 100644 index 98b2adc442fa..000000000000 --- a/llvm/lib/Transforms/InstCombine/InstCombineTables.td +++ /dev/null @@ -1,11 +0,0 @@ -include "llvm/TableGen/SearchableTable.td" -include "llvm/IR/Intrinsics.td" - -def AMDGPUImageDMaskIntrinsicTable : GenericTable { - let FilterClass = "AMDGPUImageDMaskIntrinsic"; - let Fields = ["Intr"]; - - let PrimaryKey = ["Intr"]; - let PrimaryKeyName = "getAMDGPUImageDMaskIntrinsic"; - let PrimaryKeyEarlyOut = 1; -} diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index ff70347569ab..06f22cdfb63d 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -18,6 +18,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/BasicBlock.h" @@ -35,6 +36,7 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/InstCombine/InstCombiner.h" #include #include #include @@ -45,6 +47,10 @@ using namespace PatternMatch; #define DEBUG_TYPE "instcombine" +STATISTIC(NumAggregateReconstructionsSimplified, + "Number of aggregate reconstructions turned into reuse of the " + "original aggregate"); + /// Return true if the value is cheaper to scalarize than it is to leave as a /// vector operation. IsConstantExtractIndex indicates whether we are extracting /// one known element from a vector constant. @@ -85,7 +91,8 @@ static bool cheapToScalarize(Value *V, bool IsConstantExtractIndex) { // If we have a PHI node with a vector type that is only used to feed // itself and be an operand of extractelement at a constant location, // try to replace the PHI of the vector type with a PHI of a scalar type. -Instruction *InstCombiner::scalarizePHI(ExtractElementInst &EI, PHINode *PN) { +Instruction *InstCombinerImpl::scalarizePHI(ExtractElementInst &EI, + PHINode *PN) { SmallVector Extracts; // The users we want the PHI to have are: // 1) The EI ExtractElement (we already know this) @@ -178,15 +185,19 @@ static Instruction *foldBitcastExtElt(ExtractElementInst &Ext, // extelt (bitcast VecX), IndexC --> bitcast X[IndexC] auto *SrcTy = cast(X->getType()); Type *DestTy = Ext.getType(); - unsigned NumSrcElts = SrcTy->getNumElements(); - unsigned NumElts = Ext.getVectorOperandType()->getNumElements(); + ElementCount NumSrcElts = SrcTy->getElementCount(); + ElementCount NumElts = + cast(Ext.getVectorOperandType())->getElementCount(); if (NumSrcElts == NumElts) if (Value *Elt = findScalarElement(X, ExtIndexC)) return new BitCastInst(Elt, DestTy); + assert(NumSrcElts.isScalable() == NumElts.isScalable() && + "Src and Dst must be the same sort of vector type"); + // If the source elements are wider than the destination, try to shift and // truncate a subset of scalar bits of an insert op. - if (NumSrcElts < NumElts) { + if (NumSrcElts.getKnownMinValue() < NumElts.getKnownMinValue()) { Value *Scalar; uint64_t InsIndexC; if (!match(X, m_InsertElt(m_Value(), m_Value(Scalar), @@ -197,7 +208,8 @@ static Instruction *foldBitcastExtElt(ExtractElementInst &Ext, // into. Example: if we inserted element 1 of a <2 x i64> and we are // extracting an i16 (narrowing ratio = 4), then this extract must be from 1 // of elements 4-7 of the bitcasted vector. - unsigned NarrowingRatio = NumElts / NumSrcElts; + unsigned NarrowingRatio = + NumElts.getKnownMinValue() / NumSrcElts.getKnownMinValue(); if (ExtIndexC / NarrowingRatio != InsIndexC) return nullptr; @@ -259,7 +271,7 @@ static Instruction *foldBitcastExtElt(ExtractElementInst &Ext, /// Find elements of V demanded by UserInstr. static APInt findDemandedEltsBySingleUser(Value *V, Instruction *UserInstr) { - unsigned VWidth = cast(V->getType())->getNumElements(); + unsigned VWidth = cast(V->getType())->getNumElements(); // Conservatively assume that all elements are needed. APInt UsedElts(APInt::getAllOnesValue(VWidth)); @@ -277,7 +289,7 @@ static APInt findDemandedEltsBySingleUser(Value *V, Instruction *UserInstr) { case Instruction::ShuffleVector: { ShuffleVectorInst *Shuffle = cast(UserInstr); unsigned MaskNumElts = - cast(UserInstr->getType())->getNumElements(); + cast(UserInstr->getType())->getNumElements(); UsedElts = APInt(VWidth, 0); for (unsigned i = 0; i < MaskNumElts; i++) { @@ -303,7 +315,7 @@ static APInt findDemandedEltsBySingleUser(Value *V, Instruction *UserInstr) { /// no user demands an element of V, then the corresponding bit /// remains unset in the returned value. static APInt findDemandedEltsByAllUsers(Value *V) { - unsigned VWidth = cast(V->getType())->getNumElements(); + unsigned VWidth = cast(V->getType())->getNumElements(); APInt UnionUsedElts(VWidth, 0); for (const Use &U : V->uses()) { @@ -321,7 +333,7 @@ static APInt findDemandedEltsByAllUsers(Value *V) { return UnionUsedElts; } -Instruction *InstCombiner::visitExtractElementInst(ExtractElementInst &EI) { +Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { Value *SrcVec = EI.getVectorOperand(); Value *Index = EI.getIndexOperand(); if (Value *V = SimplifyExtractElementInst(SrcVec, Index, @@ -333,17 +345,17 @@ Instruction *InstCombiner::visitExtractElementInst(ExtractElementInst &EI) { auto *IndexC = dyn_cast(Index); if (IndexC) { ElementCount EC = EI.getVectorOperandType()->getElementCount(); - unsigned NumElts = EC.Min; + unsigned NumElts = EC.getKnownMinValue(); // InstSimplify should handle cases where the index is invalid. // For fixed-length vector, it's invalid to extract out-of-range element. - if (!EC.Scalable && IndexC->getValue().uge(NumElts)) + if (!EC.isScalable() && IndexC->getValue().uge(NumElts)) return nullptr; // This instruction only demands the single element from the input vector. // Skip for scalable type, the number of elements is unknown at // compile-time. - if (!EC.Scalable && NumElts != 1) { + if (!EC.isScalable() && NumElts != 1) { // If the input vector has a single use, simplify it based on this use // property. if (SrcVec->hasOneUse()) { @@ -460,7 +472,7 @@ static bool collectSingleShuffleElements(Value *V, Value *LHS, Value *RHS, SmallVectorImpl &Mask) { assert(LHS->getType() == RHS->getType() && "Invalid CollectSingleShuffleElements"); - unsigned NumElts = cast(V->getType())->getNumElements(); + unsigned NumElts = cast(V->getType())->getNumElements(); if (isa(V)) { Mask.assign(NumElts, -1); @@ -502,7 +514,7 @@ static bool collectSingleShuffleElements(Value *V, Value *LHS, Value *RHS, unsigned ExtractedIdx = cast(EI->getOperand(1))->getZExtValue(); unsigned NumLHSElts = - cast(LHS->getType())->getNumElements(); + cast(LHS->getType())->getNumElements(); // This must be extracting from either LHS or RHS. if (EI->getOperand(0) == LHS || EI->getOperand(0) == RHS) { @@ -531,9 +543,9 @@ static bool collectSingleShuffleElements(Value *V, Value *LHS, Value *RHS, /// shufflevector to replace one or more insert/extract pairs. static void replaceExtractElements(InsertElementInst *InsElt, ExtractElementInst *ExtElt, - InstCombiner &IC) { - VectorType *InsVecType = InsElt->getType(); - VectorType *ExtVecType = ExtElt->getVectorOperandType(); + InstCombinerImpl &IC) { + auto *InsVecType = cast(InsElt->getType()); + auto *ExtVecType = cast(ExtElt->getVectorOperandType()); unsigned NumInsElts = InsVecType->getNumElements(); unsigned NumExtElts = ExtVecType->getNumElements(); @@ -614,7 +626,7 @@ using ShuffleOps = std::pair; static ShuffleOps collectShuffleElements(Value *V, SmallVectorImpl &Mask, Value *PermittedRHS, - InstCombiner &IC) { + InstCombinerImpl &IC) { assert(V->getType()->isVectorTy() && "Invalid shuffle!"); unsigned NumElts = cast(V->getType())->getNumElements(); @@ -661,7 +673,7 @@ static ShuffleOps collectShuffleElements(Value *V, SmallVectorImpl &Mask, } unsigned NumLHSElts = - cast(RHS->getType())->getNumElements(); + cast(RHS->getType())->getNumElements(); Mask[InsertedIdx % NumElts] = NumLHSElts + ExtractedIdx; return std::make_pair(LR.first, RHS); } @@ -670,7 +682,8 @@ static ShuffleOps collectShuffleElements(Value *V, SmallVectorImpl &Mask, // We've gone as far as we can: anything on the other side of the // extractelement will already have been converted into a shuffle. unsigned NumLHSElts = - cast(EI->getOperand(0)->getType())->getNumElements(); + cast(EI->getOperand(0)->getType()) + ->getNumElements(); for (unsigned i = 0; i != NumElts; ++i) Mask.push_back(i == InsertedIdx ? ExtractedIdx : NumLHSElts + i); return std::make_pair(EI->getOperand(0), PermittedRHS); @@ -692,6 +705,285 @@ static ShuffleOps collectShuffleElements(Value *V, SmallVectorImpl &Mask, return std::make_pair(V, nullptr); } +/// Look for chain of insertvalue's that fully define an aggregate, and trace +/// back the values inserted, see if they are all were extractvalue'd from +/// the same source aggregate from the exact same element indexes. +/// If they were, just reuse the source aggregate. +/// This potentially deals with PHI indirections. +Instruction *InstCombinerImpl::foldAggregateConstructionIntoAggregateReuse( + InsertValueInst &OrigIVI) { + Type *AggTy = OrigIVI.getType(); + unsigned NumAggElts; + switch (AggTy->getTypeID()) { + case Type::StructTyID: + NumAggElts = AggTy->getStructNumElements(); + break; + case Type::ArrayTyID: + NumAggElts = AggTy->getArrayNumElements(); + break; + default: + llvm_unreachable("Unhandled aggregate type?"); + } + + // Arbitrary aggregate size cut-off. Motivation for limit of 2 is to be able + // to handle clang C++ exception struct (which is hardcoded as {i8*, i32}), + // FIXME: any interesting patterns to be caught with larger limit? + assert(NumAggElts > 0 && "Aggregate should have elements."); + if (NumAggElts > 2) + return nullptr; + + static constexpr auto NotFound = None; + static constexpr auto FoundMismatch = nullptr; + + // Try to find a value of each element of an aggregate. + // FIXME: deal with more complex, not one-dimensional, aggregate types + SmallVector, 2> AggElts(NumAggElts, NotFound); + + // Do we know values for each element of the aggregate? + auto KnowAllElts = [&AggElts]() { + return all_of(AggElts, + [](Optional Elt) { return Elt != NotFound; }); + }; + + int Depth = 0; + + // Arbitrary `insertvalue` visitation depth limit. Let's be okay with + // every element being overwritten twice, which should never happen. + static const int DepthLimit = 2 * NumAggElts; + + // Recurse up the chain of `insertvalue` aggregate operands until either we've + // reconstructed full initializer or can't visit any more `insertvalue`'s. + for (InsertValueInst *CurrIVI = &OrigIVI; + Depth < DepthLimit && CurrIVI && !KnowAllElts(); + CurrIVI = dyn_cast(CurrIVI->getAggregateOperand()), + ++Depth) { + Value *InsertedValue = CurrIVI->getInsertedValueOperand(); + ArrayRef Indices = CurrIVI->getIndices(); + + // Don't bother with more than single-level aggregates. + if (Indices.size() != 1) + return nullptr; // FIXME: deal with more complex aggregates? + + // Now, we may have already previously recorded the value for this element + // of an aggregate. If we did, that means the CurrIVI will later be + // overwritten with the already-recorded value. But if not, let's record it! + Optional &Elt = AggElts[Indices.front()]; + Elt = Elt.getValueOr(InsertedValue); + + // FIXME: should we handle chain-terminating undef base operand? + } + + // Was that sufficient to deduce the full initializer for the aggregate? + if (!KnowAllElts()) + return nullptr; // Give up then. + + // We now want to find the source[s] of the aggregate elements we've found. + // And with "source" we mean the original aggregate[s] from which + // the inserted elements were extracted. This may require PHI translation. + + enum class AggregateDescription { + /// When analyzing the value that was inserted into an aggregate, we did + /// not manage to find defining `extractvalue` instruction to analyze. + NotFound, + /// When analyzing the value that was inserted into an aggregate, we did + /// manage to find defining `extractvalue` instruction[s], and everything + /// matched perfectly - aggregate type, element insertion/extraction index. + Found, + /// When analyzing the value that was inserted into an aggregate, we did + /// manage to find defining `extractvalue` instruction, but there was + /// a mismatch: either the source type from which the extraction was didn't + /// match the aggregate type into which the insertion was, + /// or the extraction/insertion channels mismatched, + /// or different elements had different source aggregates. + FoundMismatch + }; + auto Describe = [](Optional SourceAggregate) { + if (SourceAggregate == NotFound) + return AggregateDescription::NotFound; + if (*SourceAggregate == FoundMismatch) + return AggregateDescription::FoundMismatch; + return AggregateDescription::Found; + }; + + // Given the value \p Elt that was being inserted into element \p EltIdx of an + // aggregate AggTy, see if \p Elt was originally defined by an + // appropriate extractvalue (same element index, same aggregate type). + // If found, return the source aggregate from which the extraction was. + // If \p PredBB is provided, does PHI translation of an \p Elt first. + auto FindSourceAggregate = + [&](Value *Elt, unsigned EltIdx, Optional UseBB, + Optional PredBB) -> Optional { + // For now(?), only deal with, at most, a single level of PHI indirection. + if (UseBB && PredBB) + Elt = Elt->DoPHITranslation(*UseBB, *PredBB); + // FIXME: deal with multiple levels of PHI indirection? + + // Did we find an extraction? + auto *EVI = dyn_cast(Elt); + if (!EVI) + return NotFound; + + Value *SourceAggregate = EVI->getAggregateOperand(); + + // Is the extraction from the same type into which the insertion was? + if (SourceAggregate->getType() != AggTy) + return FoundMismatch; + // And the element index doesn't change between extraction and insertion? + if (EVI->getNumIndices() != 1 || EltIdx != EVI->getIndices().front()) + return FoundMismatch; + + return SourceAggregate; // AggregateDescription::Found + }; + + // Given elements AggElts that were constructing an aggregate OrigIVI, + // see if we can find appropriate source aggregate for each of the elements, + // and see it's the same aggregate for each element. If so, return it. + auto FindCommonSourceAggregate = + [&](Optional UseBB, + Optional PredBB) -> Optional { + Optional SourceAggregate; + + for (auto I : enumerate(AggElts)) { + assert(Describe(SourceAggregate) != AggregateDescription::FoundMismatch && + "We don't store nullptr in SourceAggregate!"); + assert((Describe(SourceAggregate) == AggregateDescription::Found) == + (I.index() != 0) && + "SourceAggregate should be valid after the the first element,"); + + // For this element, is there a plausible source aggregate? + // FIXME: we could special-case undef element, IFF we know that in the + // source aggregate said element isn't poison. + Optional SourceAggregateForElement = + FindSourceAggregate(*I.value(), I.index(), UseBB, PredBB); + + // Okay, what have we found? Does that correlate with previous findings? + + // Regardless of whether or not we have previously found source + // aggregate for previous elements (if any), if we didn't find one for + // this element, passthrough whatever we have just found. + if (Describe(SourceAggregateForElement) != AggregateDescription::Found) + return SourceAggregateForElement; + + // Okay, we have found source aggregate for this element. + // Let's see what we already know from previous elements, if any. + switch (Describe(SourceAggregate)) { + case AggregateDescription::NotFound: + // This is apparently the first element that we have examined. + SourceAggregate = SourceAggregateForElement; // Record the aggregate! + continue; // Great, now look at next element. + case AggregateDescription::Found: + // We have previously already successfully examined other elements. + // Is this the same source aggregate we've found for other elements? + if (*SourceAggregateForElement != *SourceAggregate) + return FoundMismatch; + continue; // Still the same aggregate, look at next element. + case AggregateDescription::FoundMismatch: + llvm_unreachable("Can't happen. We would have early-exited then."); + }; + } + + assert(Describe(SourceAggregate) == AggregateDescription::Found && + "Must be a valid Value"); + return *SourceAggregate; + }; + + Optional SourceAggregate; + + // Can we find the source aggregate without looking at predecessors? + SourceAggregate = FindCommonSourceAggregate(/*UseBB=*/None, /*PredBB=*/None); + if (Describe(SourceAggregate) != AggregateDescription::NotFound) { + if (Describe(SourceAggregate) == AggregateDescription::FoundMismatch) + return nullptr; // Conflicting source aggregates! + ++NumAggregateReconstructionsSimplified; + return replaceInstUsesWith(OrigIVI, *SourceAggregate); + } + + // Okay, apparently we need to look at predecessors. + + // We should be smart about picking the "use" basic block, which will be the + // merge point for aggregate, where we'll insert the final PHI that will be + // used instead of OrigIVI. Basic block of OrigIVI is *not* the right choice. + // We should look in which blocks each of the AggElts is being defined, + // they all should be defined in the same basic block. + BasicBlock *UseBB = nullptr; + + for (const Optional &Elt : AggElts) { + // If this element's value was not defined by an instruction, ignore it. + auto *I = dyn_cast(*Elt); + if (!I) + continue; + // Otherwise, in which basic block is this instruction located? + BasicBlock *BB = I->getParent(); + // If it's the first instruction we've encountered, record the basic block. + if (!UseBB) { + UseBB = BB; + continue; + } + // Otherwise, this must be the same basic block we've seen previously. + if (UseBB != BB) + return nullptr; + } + + // If *all* of the elements are basic-block-independent, meaning they are + // either function arguments, or constant expressions, then if we didn't + // handle them without predecessor-aware handling, we won't handle them now. + if (!UseBB) + return nullptr; + + // If we didn't manage to find source aggregate without looking at + // predecessors, and there are no predecessors to look at, then we're done. + if (pred_empty(UseBB)) + return nullptr; + + // Arbitrary predecessor count limit. + static const int PredCountLimit = 64; + + // Cache the (non-uniqified!) list of predecessors in a vector, + // checking the limit at the same time for efficiency. + SmallVector Preds; // May have duplicates! + for (BasicBlock *Pred : predecessors(UseBB)) { + // Don't bother if there are too many predecessors. + if (Preds.size() >= PredCountLimit) // FIXME: only count duplicates once? + return nullptr; + Preds.emplace_back(Pred); + } + + // For each predecessor, what is the source aggregate, + // from which all the elements were originally extracted from? + // Note that we want for the map to have stable iteration order! + SmallDenseMap SourceAggregates; + for (BasicBlock *Pred : Preds) { + std::pair IV = + SourceAggregates.insert({Pred, nullptr}); + // Did we already evaluate this predecessor? + if (!IV.second) + continue; + + // Let's hope that when coming from predecessor Pred, all elements of the + // aggregate produced by OrigIVI must have been originally extracted from + // the same aggregate. Is that so? Can we find said original aggregate? + SourceAggregate = FindCommonSourceAggregate(UseBB, Pred); + if (Describe(SourceAggregate) != AggregateDescription::Found) + return nullptr; // Give up. + IV.first->second = *SourceAggregate; + } + + // All good! Now we just need to thread the source aggregates here. + // Note that we have to insert the new PHI here, ourselves, because we can't + // rely on InstCombinerImpl::run() inserting it into the right basic block. + // Note that the same block can be a predecessor more than once, + // and we need to preserve that invariant for the PHI node. + BuilderTy::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(UseBB->getFirstNonPHI()); + auto *PHI = + Builder.CreatePHI(AggTy, Preds.size(), OrigIVI.getName() + ".merged"); + for (BasicBlock *Pred : Preds) + PHI->addIncoming(SourceAggregates[Pred], Pred); + + ++NumAggregateReconstructionsSimplified; + return replaceInstUsesWith(OrigIVI, PHI); +} + /// Try to find redundant insertvalue instructions, like the following ones: /// %0 = insertvalue { i8, i32 } undef, i8 %x, 0 /// %1 = insertvalue { i8, i32 } %0, i8 %y, 0 @@ -699,7 +991,7 @@ static ShuffleOps collectShuffleElements(Value *V, SmallVectorImpl &Mask, /// first one, making the first one redundant. /// It should be transformed to: /// %0 = insertvalue { i8, i32 } undef, i8 %y, 0 -Instruction *InstCombiner::visitInsertValueInst(InsertValueInst &I) { +Instruction *InstCombinerImpl::visitInsertValueInst(InsertValueInst &I) { bool IsRedundant = false; ArrayRef FirstIndices = I.getIndices(); @@ -724,6 +1016,10 @@ Instruction *InstCombiner::visitInsertValueInst(InsertValueInst &I) { if (IsRedundant) return replaceInstUsesWith(I, I.getOperand(0)); + + if (Instruction *NewI = foldAggregateConstructionIntoAggregateReuse(I)) + return NewI; + return nullptr; } @@ -854,7 +1150,8 @@ static Instruction *foldInsEltIntoSplat(InsertElementInst &InsElt) { // For example: // inselt (shuf (inselt undef, X, 0), undef, <0,undef,0,undef>), X, 1 // --> shuf (inselt undef, X, 0), undef, <0,0,0,undef> - unsigned NumMaskElts = Shuf->getType()->getNumElements(); + unsigned NumMaskElts = + cast(Shuf->getType())->getNumElements(); SmallVector NewMask(NumMaskElts); for (unsigned i = 0; i != NumMaskElts; ++i) NewMask[i] = i == IdxC ? 0 : Shuf->getMaskValue(i); @@ -892,7 +1189,8 @@ static Instruction *foldInsEltIntoIdentityShuffle(InsertElementInst &InsElt) { // that same index value. // For example: // inselt (shuf X, IdMask), (extelt X, IdxC), IdxC --> shuf X, IdMask' - unsigned NumMaskElts = Shuf->getType()->getNumElements(); + unsigned NumMaskElts = + cast(Shuf->getType())->getNumElements(); SmallVector NewMask(NumMaskElts); ArrayRef OldMask = Shuf->getShuffleMask(); for (unsigned i = 0; i != NumMaskElts; ++i) { @@ -1041,7 +1339,7 @@ static Instruction *foldConstantInsEltIntoShuffle(InsertElementInst &InsElt) { return nullptr; } -Instruction *InstCombiner::visitInsertElementInst(InsertElementInst &IE) { +Instruction *InstCombinerImpl::visitInsertElementInst(InsertElementInst &IE) { Value *VecOp = IE.getOperand(0); Value *ScalarOp = IE.getOperand(1); Value *IdxOp = IE.getOperand(2); @@ -1189,7 +1487,7 @@ static bool canEvaluateShuffled(Value *V, ArrayRef Mask, // Propagating an undefined shuffle mask element to integer div/rem is not // allowed because those opcodes can create immediate undefined behavior // from an undefined element in an operand. - if (llvm::any_of(Mask, [](int M){ return M == -1; })) + if (llvm::is_contained(Mask, -1)) return false; LLVM_FALLTHROUGH; case Instruction::Add: @@ -1222,7 +1520,7 @@ static bool canEvaluateShuffled(Value *V, ArrayRef Mask, // longer vector ops, but that may result in more expensive codegen. Type *ITy = I->getType(); if (ITy->isVectorTy() && - Mask.size() > cast(ITy)->getNumElements()) + Mask.size() > cast(ITy)->getNumElements()) return false; for (Value *Operand : I->operands()) { if (!canEvaluateShuffled(Operand, Mask, Depth - 1)) @@ -1380,7 +1678,8 @@ static Value *evaluateInDifferentElementOrder(Value *V, ArrayRef Mask) { case Instruction::GetElementPtr: { SmallVector NewOps; bool NeedsRebuild = - (Mask.size() != cast(I->getType())->getNumElements()); + (Mask.size() != + cast(I->getType())->getNumElements()); for (int i = 0, e = I->getNumOperands(); i != e; ++i) { Value *V; // Recursively call evaluateInDifferentElementOrder on vector arguments @@ -1435,7 +1734,7 @@ static Value *evaluateInDifferentElementOrder(Value *V, ArrayRef Mask) { static bool isShuffleExtractingFromLHS(ShuffleVectorInst &SVI, ArrayRef Mask) { unsigned LHSElems = - cast(SVI.getOperand(0)->getType())->getNumElements(); + cast(SVI.getOperand(0)->getType())->getNumElements(); unsigned MaskElems = Mask.size(); unsigned BegIdx = Mask.front(); unsigned EndIdx = Mask.back(); @@ -1525,7 +1824,7 @@ static Instruction *foldSelectShuffleWith1Binop(ShuffleVectorInst &Shuf) { is_contained(Mask, UndefMaskElem) && (Instruction::isIntDivRem(BOpcode) || Instruction::isShift(BOpcode)); if (MightCreatePoisonOrUB) - NewC = getSafeVectorConstantForBinop(BOpcode, NewC, true); + NewC = InstCombiner::getSafeVectorConstantForBinop(BOpcode, NewC, true); // shuf (bop X, C), X, M --> bop X, C' // shuf X, (bop X, C), M --> bop X, C' @@ -1567,7 +1866,8 @@ static Instruction *canonicalizeInsertSplat(ShuffleVectorInst &Shuf, // For example: // shuf (inselt undef, X, 2), undef, <2,2,undef> // --> shuf (inselt undef, X, 0), undef, <0,0,undef> - unsigned NumMaskElts = Shuf.getType()->getNumElements(); + unsigned NumMaskElts = + cast(Shuf.getType())->getNumElements(); SmallVector NewMask(NumMaskElts, 0); for (unsigned i = 0; i != NumMaskElts; ++i) if (Mask[i] == UndefMaskElem) @@ -1585,7 +1885,7 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf, // Canonicalize to choose from operand 0 first unless operand 1 is undefined. // Commuting undef to operand 0 conflicts with another canonicalization. - unsigned NumElts = Shuf.getType()->getNumElements(); + unsigned NumElts = cast(Shuf.getType())->getNumElements(); if (!isa(Shuf.getOperand(1)) && Shuf.getMaskValue(0) >= (int)NumElts) { // TODO: Can we assert that both operands of a shuffle-select are not undef @@ -1652,7 +1952,8 @@ static Instruction *foldSelectShuffle(ShuffleVectorInst &Shuf, is_contained(Mask, UndefMaskElem) && (Instruction::isIntDivRem(BOpc) || Instruction::isShift(BOpc)); if (MightCreatePoisonOrUB) - NewC = getSafeVectorConstantForBinop(BOpc, NewC, ConstantsAreOp1); + NewC = InstCombiner::getSafeVectorConstantForBinop(BOpc, NewC, + ConstantsAreOp1); Value *V; if (X == Y) { @@ -1719,8 +2020,8 @@ static Instruction *foldTruncShuffle(ShuffleVectorInst &Shuf, // and the source element type must be larger than the shuffle element type. Type *SrcType = X->getType(); if (!SrcType->isVectorTy() || !SrcType->isIntOrIntVectorTy() || - cast(SrcType)->getNumElements() != - cast(DestType)->getNumElements() || + cast(SrcType)->getNumElements() != + cast(DestType)->getNumElements() || SrcType->getScalarSizeInBits() % DestType->getScalarSizeInBits() != 0) return nullptr; @@ -1736,8 +2037,7 @@ static Instruction *foldTruncShuffle(ShuffleVectorInst &Shuf, if (Mask[i] == UndefMaskElem) continue; uint64_t LSBIndex = IsBigEndian ? (i + 1) * TruncRatio - 1 : i * TruncRatio; - assert(LSBIndex <= std::numeric_limits::max() && - "Overflowed 32-bits"); + assert(LSBIndex <= INT32_MAX && "Overflowed 32-bits"); if (Mask[i] != (int)LSBIndex) return nullptr; } @@ -1764,19 +2064,19 @@ static Instruction *narrowVectorSelect(ShuffleVectorInst &Shuf, // We need a narrow condition value. It must be extended with undef elements // and have the same number of elements as this shuffle. - unsigned NarrowNumElts = Shuf.getType()->getNumElements(); + unsigned NarrowNumElts = + cast(Shuf.getType())->getNumElements(); Value *NarrowCond; if (!match(Cond, m_OneUse(m_Shuffle(m_Value(NarrowCond), m_Undef()))) || - cast(NarrowCond->getType())->getNumElements() != + cast(NarrowCond->getType())->getNumElements() != NarrowNumElts || !cast(Cond)->isIdentityWithPadding()) return nullptr; // shuf (sel (shuf NarrowCond, undef, WideMask), X, Y), undef, NarrowMask) --> // sel NarrowCond, (shuf X, undef, NarrowMask), (shuf Y, undef, NarrowMask) - Value *Undef = UndefValue::get(X->getType()); - Value *NarrowX = Builder.CreateShuffleVector(X, Undef, Shuf.getShuffleMask()); - Value *NarrowY = Builder.CreateShuffleVector(Y, Undef, Shuf.getShuffleMask()); + Value *NarrowX = Builder.CreateShuffleVector(X, Shuf.getShuffleMask()); + Value *NarrowY = Builder.CreateShuffleVector(Y, Shuf.getShuffleMask()); return SelectInst::Create(NarrowCond, NarrowX, NarrowY); } @@ -1807,7 +2107,7 @@ static Instruction *foldIdentityExtractShuffle(ShuffleVectorInst &Shuf) { // new shuffle mask. Otherwise, copy the original mask element. Example: // shuf (shuf X, Y, ), undef, <0, undef, 2, 3> --> // shuf X, Y, - unsigned NumElts = Shuf.getType()->getNumElements(); + unsigned NumElts = cast(Shuf.getType())->getNumElements(); SmallVector NewMask(NumElts); assert(NumElts < Mask.size() && "Identity with extract must have less elements than its inputs"); @@ -1823,7 +2123,7 @@ static Instruction *foldIdentityExtractShuffle(ShuffleVectorInst &Shuf) { /// Try to replace a shuffle with an insertelement or try to replace a shuffle /// operand with the operand of an insertelement. static Instruction *foldShuffleWithInsert(ShuffleVectorInst &Shuf, - InstCombiner &IC) { + InstCombinerImpl &IC) { Value *V0 = Shuf.getOperand(0), *V1 = Shuf.getOperand(1); SmallVector Mask; Shuf.getShuffleMask(Mask); @@ -1832,7 +2132,7 @@ static Instruction *foldShuffleWithInsert(ShuffleVectorInst &Shuf, // TODO: This restriction could be removed if the insert has only one use // (because the transform would require a new length-changing shuffle). int NumElts = Mask.size(); - if (NumElts != (int)(cast(V0->getType())->getNumElements())) + if (NumElts != (int)(cast(V0->getType())->getNumElements())) return nullptr; // This is a specialization of a fold in SimplifyDemandedVectorElts. We may @@ -1844,7 +2144,7 @@ static Instruction *foldShuffleWithInsert(ShuffleVectorInst &Shuf, uint64_t IdxC; if (match(V0, m_InsertElt(m_Value(X), m_Value(), m_ConstantInt(IdxC)))) { // shuf (inselt X, ?, IdxC), ?, Mask --> shuf X, ?, Mask - if (none_of(Mask, [IdxC](int MaskElt) { return MaskElt == (int)IdxC; })) + if (!is_contained(Mask, (int)IdxC)) return IC.replaceOperand(Shuf, 0, X); } if (match(V1, m_InsertElt(m_Value(X), m_Value(), m_ConstantInt(IdxC)))) { @@ -1852,7 +2152,7 @@ static Instruction *foldShuffleWithInsert(ShuffleVectorInst &Shuf, // accesses to the 2nd vector input of the shuffle. IdxC += NumElts; // shuf ?, (inselt X, ?, IdxC), Mask --> shuf ?, X, Mask - if (none_of(Mask, [IdxC](int MaskElt) { return MaskElt == (int)IdxC; })) + if (!is_contained(Mask, (int)IdxC)) return IC.replaceOperand(Shuf, 1, X); } @@ -1927,9 +2227,10 @@ static Instruction *foldIdentityPaddedShuffles(ShuffleVectorInst &Shuf) { Value *X = Shuffle0->getOperand(0); Value *Y = Shuffle1->getOperand(0); if (X->getType() != Y->getType() || - !isPowerOf2_32(Shuf.getType()->getNumElements()) || - !isPowerOf2_32(Shuffle0->getType()->getNumElements()) || - !isPowerOf2_32(cast(X->getType())->getNumElements()) || + !isPowerOf2_32(cast(Shuf.getType())->getNumElements()) || + !isPowerOf2_32( + cast(Shuffle0->getType())->getNumElements()) || + !isPowerOf2_32(cast(X->getType())->getNumElements()) || isa(X) || isa(Y)) return nullptr; assert(isa(Shuffle0->getOperand(1)) && @@ -1940,8 +2241,8 @@ static Instruction *foldIdentityPaddedShuffles(ShuffleVectorInst &Shuf) { // operands directly by adjusting the shuffle mask to account for the narrower // types: // shuf (widen X), (widen Y), Mask --> shuf X, Y, Mask' - int NarrowElts = cast(X->getType())->getNumElements(); - int WideElts = Shuffle0->getType()->getNumElements(); + int NarrowElts = cast(X->getType())->getNumElements(); + int WideElts = cast(Shuffle0->getType())->getNumElements(); assert(WideElts > NarrowElts && "Unexpected types for identity with padding"); ArrayRef Mask = Shuf.getShuffleMask(); @@ -1974,7 +2275,7 @@ static Instruction *foldIdentityPaddedShuffles(ShuffleVectorInst &Shuf) { return new ShuffleVectorInst(X, Y, NewMask); } -Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { +Instruction *InstCombinerImpl::visitShuffleVectorInst(ShuffleVectorInst &SVI) { Value *LHS = SVI.getOperand(0); Value *RHS = SVI.getOperand(1); SimplifyQuery ShufQuery = SQ.getWithInstruction(&SVI); @@ -1982,9 +2283,13 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { SVI.getType(), ShufQuery)) return replaceInstUsesWith(SVI, V); + // Bail out for scalable vectors + if (isa(LHS->getType())) + return nullptr; + // shuffle x, x, mask --> shuffle x, undef, mask' - unsigned VWidth = SVI.getType()->getNumElements(); - unsigned LHSWidth = cast(LHS->getType())->getNumElements(); + unsigned VWidth = cast(SVI.getType())->getNumElements(); + unsigned LHSWidth = cast(LHS->getType())->getNumElements(); ArrayRef Mask = SVI.getShuffleMask(); Type *Int32Ty = Type::getInt32Ty(SVI.getContext()); @@ -1998,7 +2303,7 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { if (match(LHS, m_BitCast(m_Value(X))) && match(RHS, m_Undef()) && X->getType()->isVectorTy() && VWidth == LHSWidth) { // Try to create a scaled mask constant. - auto *XType = cast(X->getType()); + auto *XType = cast(X->getType()); unsigned XNumElts = XType->getNumElements(); SmallVector ScaledMask; if (XNumElts >= VWidth) { @@ -2106,7 +2411,7 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { if (isShuffleExtractingFromLHS(SVI, Mask)) { Value *V = LHS; unsigned MaskElems = Mask.size(); - VectorType *SrcTy = cast(V->getType()); + auto *SrcTy = cast(V->getType()); unsigned VecBitWidth = SrcTy->getPrimitiveSizeInBits().getFixedSize(); unsigned SrcElemBitWidth = DL.getTypeSizeInBits(SrcTy->getElementType()); assert(SrcElemBitWidth && "vector elements must have a bitwidth"); @@ -2138,8 +2443,7 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { SmallVector ShuffleMask(SrcNumElems, -1); for (unsigned I = 0, E = MaskElems, Idx = BegIdx; I != E; ++Idx, ++I) ShuffleMask[I] = Idx; - V = Builder.CreateShuffleVector(V, UndefValue::get(V->getType()), - ShuffleMask, + V = Builder.CreateShuffleVector(V, ShuffleMask, SVI.getName() + ".extract"); BegIdx = 0; } @@ -2224,11 +2528,11 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { if (LHSShuffle) { LHSOp0 = LHSShuffle->getOperand(0); LHSOp1 = LHSShuffle->getOperand(1); - LHSOp0Width = cast(LHSOp0->getType())->getNumElements(); + LHSOp0Width = cast(LHSOp0->getType())->getNumElements(); } if (RHSShuffle) { RHSOp0 = RHSShuffle->getOperand(0); - RHSOp0Width = cast(RHSOp0->getType())->getNumElements(); + RHSOp0Width = cast(RHSOp0->getType())->getNumElements(); } Value* newLHS = LHS; Value* newRHS = RHS; @@ -2331,17 +2635,9 @@ Instruction *InstCombiner::visitShuffleVectorInst(ShuffleVectorInst &SVI) { // If the result mask is equal to one of the original shuffle masks, // or is a splat, do the replacement. if (isSplat || newMask == LHSMask || newMask == RHSMask || newMask == Mask) { - SmallVector Elts; - for (unsigned i = 0, e = newMask.size(); i != e; ++i) { - if (newMask[i] < 0) { - Elts.push_back(UndefValue::get(Int32Ty)); - } else { - Elts.push_back(ConstantInt::get(Int32Ty, newMask[i])); - } - } if (!newRHS) newRHS = UndefValue::get(newLHS->getType()); - return new ShuffleVectorInst(newLHS, newRHS, ConstantVector::get(Elts)); + return new ShuffleVectorInst(newLHS, newRHS, newMask); } return MadeChange ? &SVI : nullptr; diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp index b3254c10a0b2..518e909e8ab4 100644 --- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -59,6 +59,7 @@ #include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/TargetFolder.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/BasicBlock.h" @@ -113,6 +114,9 @@ using namespace llvm::PatternMatch; #define DEBUG_TYPE "instcombine" +STATISTIC(NumWorklistIterations, + "Number of instruction combining iterations performed"); + STATISTIC(NumCombined , "Number of insts combined"); STATISTIC(NumConstProp, "Number of constant folds"); STATISTIC(NumDeadInst , "Number of dead inst eliminated"); @@ -123,8 +127,13 @@ STATISTIC(NumReassoc , "Number of reassociations"); DEBUG_COUNTER(VisitCounter, "instcombine-visit", "Controls which instructions are visited"); +// FIXME: these limits eventually should be as low as 2. static constexpr unsigned InstCombineDefaultMaxIterations = 1000; +#ifndef NDEBUG +static constexpr unsigned InstCombineDefaultInfiniteLoopThreshold = 100; +#else static constexpr unsigned InstCombineDefaultInfiniteLoopThreshold = 1000; +#endif static cl::opt EnableCodeSinking("instcombine-code-sinking", cl::desc("Enable code sinking"), @@ -155,7 +164,41 @@ MaxArraySize("instcombine-maxarray-size", cl::init(1024), static cl::opt ShouldLowerDbgDeclare("instcombine-lower-dbg-declare", cl::Hidden, cl::init(true)); -Value *InstCombiner::EmitGEPOffset(User *GEP) { +Optional +InstCombiner::targetInstCombineIntrinsic(IntrinsicInst &II) { + // Handle target specific intrinsics + if (II.getCalledFunction()->isTargetIntrinsic()) { + return TTI.instCombineIntrinsic(*this, II); + } + return None; +} + +Optional InstCombiner::targetSimplifyDemandedUseBitsIntrinsic( + IntrinsicInst &II, APInt DemandedMask, KnownBits &Known, + bool &KnownBitsComputed) { + // Handle target specific intrinsics + if (II.getCalledFunction()->isTargetIntrinsic()) { + return TTI.simplifyDemandedUseBitsIntrinsic(*this, II, DemandedMask, Known, + KnownBitsComputed); + } + return None; +} + +Optional InstCombiner::targetSimplifyDemandedVectorEltsIntrinsic( + IntrinsicInst &II, APInt DemandedElts, APInt &UndefElts, APInt &UndefElts2, + APInt &UndefElts3, + std::function + SimplifyAndSetOp) { + // Handle target specific intrinsics + if (II.getCalledFunction()->isTargetIntrinsic()) { + return TTI.simplifyDemandedVectorEltsIntrinsic( + *this, II, DemandedElts, UndefElts, UndefElts2, UndefElts3, + SimplifyAndSetOp); + } + return None; +} + +Value *InstCombinerImpl::EmitGEPOffset(User *GEP) { return llvm::EmitGEPOffset(&Builder, DL, GEP); } @@ -168,8 +211,8 @@ Value *InstCombiner::EmitGEPOffset(User *GEP) { /// legal to convert to, in order to open up more combining opportunities. /// NOTE: this treats i8, i16 and i32 specially, due to them being so common /// from frontend languages. -bool InstCombiner::shouldChangeType(unsigned FromWidth, - unsigned ToWidth) const { +bool InstCombinerImpl::shouldChangeType(unsigned FromWidth, + unsigned ToWidth) const { bool FromLegal = FromWidth == 1 || DL.isLegalInteger(FromWidth); bool ToLegal = ToWidth == 1 || DL.isLegalInteger(ToWidth); @@ -196,7 +239,7 @@ bool InstCombiner::shouldChangeType(unsigned FromWidth, /// to a larger illegal type. i1 is always treated as a legal type because it is /// a fundamental type in IR, and there are many specialized optimizations for /// i1 types. -bool InstCombiner::shouldChangeType(Type *From, Type *To) const { +bool InstCombinerImpl::shouldChangeType(Type *From, Type *To) const { // TODO: This could be extended to allow vectors. Datalayout changes might be // needed to properly support that. if (!From->isIntegerTy() || !To->isIntegerTy()) @@ -264,7 +307,8 @@ static void ClearSubclassDataAfterReassociation(BinaryOperator &I) { /// cast to eliminate one of the associative operations: /// (op (cast (op X, C2)), C1) --> (cast (op X, op (C1, C2))) /// (op (cast (op X, C2)), C1) --> (op (cast X), op (C1, C2)) -static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1, InstCombiner &IC) { +static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1, + InstCombinerImpl &IC) { auto *Cast = dyn_cast(BinOp1->getOperand(0)); if (!Cast || !Cast->hasOneUse()) return false; @@ -322,7 +366,7 @@ static bool simplifyAssocCastAssoc(BinaryOperator *BinOp1, InstCombiner &IC) { /// 5. Transform: "A op (B op C)" ==> "B op (C op A)" if "C op A" simplifies. /// 6. Transform: "(A op C1) op (B op C2)" ==> "(A op B) op (C1 op C2)" /// if C1 and C2 are constants. -bool InstCombiner::SimplifyAssociativeOrCommutative(BinaryOperator &I) { +bool InstCombinerImpl::SimplifyAssociativeOrCommutative(BinaryOperator &I) { Instruction::BinaryOps Opcode = I.getOpcode(); bool Changed = false; @@ -550,9 +594,10 @@ getBinOpsForFactorization(Instruction::BinaryOps TopOpcode, BinaryOperator *Op, /// This tries to simplify binary operations by factorizing out common terms /// (e. g. "(A*B)+(A*C)" -> "A*(B+C)"). -Value *InstCombiner::tryFactorization(BinaryOperator &I, - Instruction::BinaryOps InnerOpcode, - Value *A, Value *B, Value *C, Value *D) { +Value *InstCombinerImpl::tryFactorization(BinaryOperator &I, + Instruction::BinaryOps InnerOpcode, + Value *A, Value *B, Value *C, + Value *D) { assert(A && B && C && D && "All values must be provided"); Value *V = nullptr; @@ -655,7 +700,7 @@ Value *InstCombiner::tryFactorization(BinaryOperator &I, /// (eg "(A*B)+(A*C)" -> "A*(B+C)") or expanding out if this results in /// simplifications (eg: "A & (B | C) -> (A&B) | (A&C)" if this is a win). /// Returns the simplified value, or null if it didn't simplify. -Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) { +Value *InstCombinerImpl::SimplifyUsingDistributiveLaws(BinaryOperator &I) { Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); BinaryOperator *Op0 = dyn_cast(LHS); BinaryOperator *Op1 = dyn_cast(RHS); @@ -698,8 +743,10 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) { Value *A = Op0->getOperand(0), *B = Op0->getOperand(1), *C = RHS; Instruction::BinaryOps InnerOpcode = Op0->getOpcode(); // op' - Value *L = SimplifyBinOp(TopLevelOpcode, A, C, SQ.getWithInstruction(&I)); - Value *R = SimplifyBinOp(TopLevelOpcode, B, C, SQ.getWithInstruction(&I)); + // Disable the use of undef because it's not safe to distribute undef. + auto SQDistributive = SQ.getWithInstruction(&I).getWithoutUndef(); + Value *L = SimplifyBinOp(TopLevelOpcode, A, C, SQDistributive); + Value *R = SimplifyBinOp(TopLevelOpcode, B, C, SQDistributive); // Do "A op C" and "B op C" both simplify? if (L && R) { @@ -735,8 +782,10 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) { Value *A = LHS, *B = Op1->getOperand(0), *C = Op1->getOperand(1); Instruction::BinaryOps InnerOpcode = Op1->getOpcode(); // op' - Value *L = SimplifyBinOp(TopLevelOpcode, A, B, SQ.getWithInstruction(&I)); - Value *R = SimplifyBinOp(TopLevelOpcode, A, C, SQ.getWithInstruction(&I)); + // Disable the use of undef because it's not safe to distribute undef. + auto SQDistributive = SQ.getWithInstruction(&I).getWithoutUndef(); + Value *L = SimplifyBinOp(TopLevelOpcode, A, B, SQDistributive); + Value *R = SimplifyBinOp(TopLevelOpcode, A, C, SQDistributive); // Do "A op B" and "A op C" both simplify? if (L && R) { @@ -769,8 +818,9 @@ Value *InstCombiner::SimplifyUsingDistributiveLaws(BinaryOperator &I) { return SimplifySelectsFeedingBinaryOp(I, LHS, RHS); } -Value *InstCombiner::SimplifySelectsFeedingBinaryOp(BinaryOperator &I, - Value *LHS, Value *RHS) { +Value *InstCombinerImpl::SimplifySelectsFeedingBinaryOp(BinaryOperator &I, + Value *LHS, + Value *RHS) { Value *A, *B, *C, *D, *E, *F; bool LHSIsSelect = match(LHS, m_Select(m_Value(A), m_Value(B), m_Value(C))); bool RHSIsSelect = match(RHS, m_Select(m_Value(D), m_Value(E), m_Value(F))); @@ -820,9 +870,33 @@ Value *InstCombiner::SimplifySelectsFeedingBinaryOp(BinaryOperator &I, return SI; } +/// Freely adapt every user of V as-if V was changed to !V. +/// WARNING: only if canFreelyInvertAllUsersOf() said this can be done. +void InstCombinerImpl::freelyInvertAllUsersOf(Value *I) { + for (User *U : I->users()) { + switch (cast(U)->getOpcode()) { + case Instruction::Select: { + auto *SI = cast(U); + SI->swapValues(); + SI->swapProfMetadata(); + break; + } + case Instruction::Br: + cast(U)->swapSuccessors(); // swaps prof metadata too + break; + case Instruction::Xor: + replaceInstUsesWith(cast(*U), I); + break; + default: + llvm_unreachable("Got unexpected user - out of sync with " + "canFreelyInvertAllUsersOf() ?"); + } + } +} + /// Given a 'sub' instruction, return the RHS of the instruction if the LHS is a /// constant zero (which is the 'negate' form). -Value *InstCombiner::dyn_castNegVal(Value *V) const { +Value *InstCombinerImpl::dyn_castNegVal(Value *V) const { Value *NegV; if (match(V, m_Neg(m_Value(NegV)))) return NegV; @@ -883,7 +957,8 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO, return RI; } -Instruction *InstCombiner::FoldOpIntoSelect(Instruction &Op, SelectInst *SI) { +Instruction *InstCombinerImpl::FoldOpIntoSelect(Instruction &Op, + SelectInst *SI) { // Don't modify shared select instructions. if (!SI->hasOneUse()) return nullptr; @@ -908,7 +983,7 @@ Instruction *InstCombiner::FoldOpIntoSelect(Instruction &Op, SelectInst *SI) { return nullptr; // If vectors, verify that they have the same number of elements. - if (SrcTy && SrcTy->getNumElements() != DestTy->getNumElements()) + if (SrcTy && SrcTy->getElementCount() != DestTy->getElementCount()) return nullptr; } @@ -978,7 +1053,7 @@ static Value *foldOperationIntoPhiValue(BinaryOperator *I, Value *InV, return RI; } -Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { +Instruction *InstCombinerImpl::foldOpIntoPhi(Instruction &I, PHINode *PN) { unsigned NumPHIValues = PN->getNumIncomingValues(); if (NumPHIValues == 0) return nullptr; @@ -1004,7 +1079,9 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { BasicBlock *NonConstBB = nullptr; for (unsigned i = 0; i != NumPHIValues; ++i) { Value *InVal = PN->getIncomingValue(i); - if (isa(InVal) && !isa(InVal)) + // If I is a freeze instruction, count undef as a non-constant. + if (match(InVal, m_ImmConstant()) && + (!isa(I) || isGuaranteedNotToBeUndefOrPoison(InVal))) continue; if (isa(InVal)) return nullptr; // Itself a phi. @@ -1029,9 +1106,11 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { // operation in that block. However, if this is a critical edge, we would be // inserting the computation on some other paths (e.g. inside a loop). Only // do this if the pred block is unconditionally branching into the phi block. + // Also, make sure that the pred block is not dead code. if (NonConstBB != nullptr) { BranchInst *BI = dyn_cast(NonConstBB->getTerminator()); - if (!BI || !BI->isUnconditional()) return nullptr; + if (!BI || !BI->isUnconditional() || !DT.isReachableFromEntry(NonConstBB)) + return nullptr; } // Okay, we can do the transformation: create the new PHI node. @@ -1063,7 +1142,7 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { // FalseVInPred versus TrueVInPred. When we have individual nonzero // elements in the vector, we will incorrectly fold InC to // `TrueVInPred`. - if (InC && !isa(InC) && isa(InC)) + if (InC && isa(InC)) InV = InC->isNullValue() ? FalseVInPred : TrueVInPred; else { // Generate the select in the same block as PN's current incoming block. @@ -1097,6 +1176,15 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { Builder); NewPN->addIncoming(InV, PN->getIncomingBlock(i)); } + } else if (isa(&I)) { + for (unsigned i = 0; i != NumPHIValues; ++i) { + Value *InV; + if (NonConstBB == PN->getIncomingBlock(i)) + InV = Builder.CreateFreeze(PN->getIncomingValue(i), "phi.fr"); + else + InV = PN->getIncomingValue(i); + NewPN->addIncoming(InV, PN->getIncomingBlock(i)); + } } else { CastInst *CI = cast(&I); Type *RetTy = CI->getType(); @@ -1111,8 +1199,8 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { } } - for (auto UI = PN->user_begin(), E = PN->user_end(); UI != E;) { - Instruction *User = cast(*UI++); + for (User *U : make_early_inc_range(PN->users())) { + Instruction *User = cast(U); if (User == &I) continue; replaceInstUsesWith(*User, NewPN); eraseInstFromFunction(*User); @@ -1120,7 +1208,7 @@ Instruction *InstCombiner::foldOpIntoPhi(Instruction &I, PHINode *PN) { return replaceInstUsesWith(I, NewPN); } -Instruction *InstCombiner::foldBinOpIntoSelectOrPhi(BinaryOperator &I) { +Instruction *InstCombinerImpl::foldBinOpIntoSelectOrPhi(BinaryOperator &I) { if (!isa(I.getOperand(1))) return nullptr; @@ -1138,8 +1226,9 @@ Instruction *InstCombiner::foldBinOpIntoSelectOrPhi(BinaryOperator &I) { /// is a sequence of GEP indices into the pointed type that will land us at the /// specified offset. If so, fill them into NewIndices and return the resultant /// element type, otherwise return null. -Type *InstCombiner::FindElementAtOffset(PointerType *PtrTy, int64_t Offset, - SmallVectorImpl &NewIndices) { +Type * +InstCombinerImpl::FindElementAtOffset(PointerType *PtrTy, int64_t Offset, + SmallVectorImpl &NewIndices) { Type *Ty = PtrTy->getElementType(); if (!Ty->isSized()) return nullptr; @@ -1208,7 +1297,7 @@ static bool shouldMergeGEPs(GEPOperator &GEP, GEPOperator &Src) { /// Return a value X such that Val = X * Scale, or null if none. /// If the multiplication is known not to overflow, then NoSignedWrap is set. -Value *InstCombiner::Descale(Value *Val, APInt Scale, bool &NoSignedWrap) { +Value *InstCombinerImpl::Descale(Value *Val, APInt Scale, bool &NoSignedWrap) { assert(isa(Val->getType()) && "Can only descale integers!"); assert(cast(Val->getType())->getBitWidth() == Scale.getBitWidth() && "Scale not compatible with value!"); @@ -1448,9 +1537,8 @@ Value *InstCombiner::Descale(Value *Val, APInt Scale, bool &NoSignedWrap) { } while (true); } -Instruction *InstCombiner::foldVectorBinop(BinaryOperator &Inst) { - // FIXME: some of this is likely fine for scalable vectors - if (!isa(Inst.getType())) +Instruction *InstCombinerImpl::foldVectorBinop(BinaryOperator &Inst) { + if (!isa(Inst.getType())) return nullptr; BinaryOperator::BinaryOps Opcode = Inst.getOpcode(); @@ -1539,13 +1627,15 @@ Instruction *InstCombiner::foldVectorBinop(BinaryOperator &Inst) { // intends to move shuffles closer to other shuffles and binops closer to // other binops, so they can be folded. It may also enable demanded elements // transforms. - unsigned NumElts = cast(Inst.getType())->getNumElements(); Constant *C; - if (match(&Inst, + auto *InstVTy = dyn_cast(Inst.getType()); + if (InstVTy && + match(&Inst, m_c_BinOp(m_OneUse(m_Shuffle(m_Value(V1), m_Undef(), m_Mask(Mask))), - m_Constant(C))) && - cast(V1->getType())->getNumElements() <= NumElts) { - assert(Inst.getType()->getScalarType() == V1->getType()->getScalarType() && + m_ImmConstant(C))) && + cast(V1->getType())->getNumElements() <= + InstVTy->getNumElements()) { + assert(InstVTy->getScalarType() == V1->getType()->getScalarType() && "Shuffle should not change scalar type"); // Find constant NewC that has property: @@ -1560,6 +1650,7 @@ Instruction *InstCombiner::foldVectorBinop(BinaryOperator &Inst) { UndefValue *UndefScalar = UndefValue::get(C->getType()->getScalarType()); SmallVector NewVecC(SrcVecNumElts, UndefScalar); bool MayChange = true; + unsigned NumElts = InstVTy->getNumElements(); for (unsigned I = 0; I < NumElts; ++I) { Constant *CElt = C->getAggregateElement(I); if (ShMask[I] >= 0) { @@ -1648,9 +1739,8 @@ Instruction *InstCombiner::foldVectorBinop(BinaryOperator &Inst) { // values followed by a splat followed by the 2nd binary operation: // bo (splat X), (bo Y, OtherOp) --> bo (splat (bo X, Y)), OtherOp Value *NewBO = Builder.CreateBinOp(Opcode, X, Y); - UndefValue *Undef = UndefValue::get(Inst.getType()); SmallVector NewMask(MaskC.size(), SplatIndex); - Value *NewSplat = Builder.CreateShuffleVector(NewBO, Undef, NewMask); + Value *NewSplat = Builder.CreateShuffleVector(NewBO, NewMask); Instruction *R = BinaryOperator::Create(Opcode, NewSplat, OtherOp); // Intersect FMF on both new binops. Other (poison-generating) flags are @@ -1670,7 +1760,7 @@ Instruction *InstCombiner::foldVectorBinop(BinaryOperator &Inst) { /// Try to narrow the width of a binop if at least 1 operand is an extend of /// of a value. This requires a potentially expensive known bits check to make /// sure the narrow op does not overflow. -Instruction *InstCombiner::narrowMathIfNoOverflow(BinaryOperator &BO) { +Instruction *InstCombinerImpl::narrowMathIfNoOverflow(BinaryOperator &BO) { // We need at least one extended operand. Value *Op0 = BO.getOperand(0), *Op1 = BO.getOperand(1); @@ -1750,7 +1840,7 @@ static Instruction *foldSelectGEP(GetElementPtrInst &GEP, // gep (select Cond, TrueC, FalseC), IndexC --> select Cond, TrueC', FalseC' // Propagate 'inbounds' and metadata from existing instructions. // Note: using IRBuilder to create the constants for efficiency. - SmallVector IndexC(GEP.idx_begin(), GEP.idx_end()); + SmallVector IndexC(GEP.indices()); bool IsInBounds = GEP.isInBounds(); Value *NewTrueC = IsInBounds ? Builder.CreateInBoundsGEP(TrueC, IndexC) : Builder.CreateGEP(TrueC, IndexC); @@ -1759,8 +1849,8 @@ static Instruction *foldSelectGEP(GetElementPtrInst &GEP, return SelectInst::Create(Cond, NewTrueC, NewFalseC, "", nullptr, Sel); } -Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { - SmallVector Ops(GEP.op_begin(), GEP.op_end()); +Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) { + SmallVector Ops(GEP.operands()); Type *GEPType = GEP.getType(); Type *GEPEltType = GEP.getSourceElementType(); bool IsGEPSrcEleScalable = isa(GEPEltType); @@ -2130,7 +2220,7 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { // GEP (bitcast i8* X to [0 x i8]*), i32 0, ... ? if (CATy->getElementType() == StrippedPtrEltTy) { // -> GEP i8* X, ... - SmallVector Idx(GEP.idx_begin()+1, GEP.idx_end()); + SmallVector Idx(drop_begin(GEP.indices())); GetElementPtrInst *Res = GetElementPtrInst::Create( StrippedPtrEltTy, StrippedPtr, Idx, GEP.getName()); Res->setIsInBounds(GEP.isInBounds()); @@ -2166,7 +2256,7 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { // -> // %0 = GEP [10 x i8] addrspace(1)* X, ... // addrspacecast i8 addrspace(1)* %0 to i8* - SmallVector Idx(GEP.idx_begin(), GEP.idx_end()); + SmallVector Idx(GEP.indices()); Value *NewGEP = GEP.isInBounds() ? Builder.CreateInBoundsGEP(StrippedPtrEltTy, StrippedPtr, @@ -2308,15 +2398,15 @@ Instruction *InstCombiner::visitGetElementPtrInst(GetElementPtrInst &GEP) { // gep (bitcast [c x ty]* X to *), Y, Z --> gep X, Y, Z auto areMatchingArrayAndVecTypes = [](Type *ArrTy, Type *VecTy, const DataLayout &DL) { - auto *VecVTy = cast(VecTy); + auto *VecVTy = cast(VecTy); return ArrTy->getArrayElementType() == VecVTy->getElementType() && ArrTy->getArrayNumElements() == VecVTy->getNumElements() && DL.getTypeAllocSize(ArrTy) == DL.getTypeAllocSize(VecTy); }; if (GEP.getNumOperands() == 3 && - ((GEPEltType->isArrayTy() && SrcEltType->isVectorTy() && + ((GEPEltType->isArrayTy() && isa(SrcEltType) && areMatchingArrayAndVecTypes(GEPEltType, SrcEltType, DL)) || - (GEPEltType->isVectorTy() && SrcEltType->isArrayTy() && + (isa(GEPEltType) && SrcEltType->isArrayTy() && areMatchingArrayAndVecTypes(SrcEltType, GEPEltType, DL)))) { // Create a new GEP here, as using `setOperand()` followed by @@ -2511,7 +2601,7 @@ static bool isAllocSiteRemovable(Instruction *AI, return true; } -Instruction *InstCombiner::visitAllocSite(Instruction &MI) { +Instruction *InstCombinerImpl::visitAllocSite(Instruction &MI) { // If we have a malloc call which is only used in any amount of comparisons to // null and free calls, delete the calls and replace the comparisons with true // or false as appropriate. @@ -2526,10 +2616,10 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { // If we are removing an alloca with a dbg.declare, insert dbg.value calls // before each store. - TinyPtrVector DIIs; + SmallVector DVIs; std::unique_ptr DIB; if (isa(MI)) { - DIIs = FindDbgAddrUses(&MI); + findDbgUsers(DVIs, &MI); DIB.reset(new DIBuilder(*MI.getModule(), /*AllowUnresolved=*/false)); } @@ -2563,8 +2653,9 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { ConstantInt::get(Type::getInt1Ty(C->getContext()), C->isFalseWhenEqual())); } else if (auto *SI = dyn_cast(I)) { - for (auto *DII : DIIs) - ConvertDebugDeclareToDebugValue(DII, SI, *DIB); + for (auto *DVI : DVIs) + if (DVI->isAddressOfVariable()) + ConvertDebugDeclareToDebugValue(DVI, SI, *DIB); } else { // Casts, GEP, or anything else: we're about to delete this instruction, // so it can not have any valid uses. @@ -2581,8 +2672,31 @@ Instruction *InstCombiner::visitAllocSite(Instruction &MI) { None, "", II->getParent()); } - for (auto *DII : DIIs) - eraseInstFromFunction(*DII); + // Remove debug intrinsics which describe the value contained within the + // alloca. In addition to removing dbg.{declare,addr} which simply point to + // the alloca, remove dbg.value(, ..., DW_OP_deref)'s as well, e.g.: + // + // ``` + // define void @foo(i32 %0) { + // %a = alloca i32 ; Deleted. + // store i32 %0, i32* %a + // dbg.value(i32 %0, "arg0") ; Not deleted. + // dbg.value(i32* %a, "arg0", DW_OP_deref) ; Deleted. + // call void @trivially_inlinable_no_op(i32* %a) + // ret void + // } + // ``` + // + // This may not be required if we stop describing the contents of allocas + // using dbg.value(, ..., DW_OP_deref), but we currently do this in + // the LowerDbgDeclare utility. + // + // If there is a dead store to `%a` in @trivially_inlinable_no_op, the + // "arg0" dbg.value may be stale after the call. However, failing to remove + // the DW_OP_deref dbg.value causes large gaps in location coverage. + for (auto *DVI : DVIs) + if (DVI->isAddressOfVariable() || DVI->getExpression()->startsWithDeref()) + DVI->eraseFromParent(); return eraseInstFromFunction(MI); } @@ -2670,7 +2784,7 @@ static Instruction *tryToMoveFreeBeforeNullTest(CallInst &FI, return &FI; } -Instruction *InstCombiner::visitFree(CallInst &FI) { +Instruction *InstCombinerImpl::visitFree(CallInst &FI) { Value *Op = FI.getArgOperand(0); // free undef -> unreachable. @@ -2711,7 +2825,7 @@ static bool isMustTailCall(Value *V) { return false; } -Instruction *InstCombiner::visitReturnInst(ReturnInst &RI) { +Instruction *InstCombinerImpl::visitReturnInst(ReturnInst &RI) { if (RI.getNumOperands() == 0) // ret void return nullptr; @@ -2734,7 +2848,31 @@ Instruction *InstCombiner::visitReturnInst(ReturnInst &RI) { return nullptr; } -Instruction *InstCombiner::visitUnconditionalBranchInst(BranchInst &BI) { +Instruction *InstCombinerImpl::visitUnreachableInst(UnreachableInst &I) { + // Try to remove the previous instruction if it must lead to unreachable. + // This includes instructions like stores and "llvm.assume" that may not get + // removed by simple dead code elimination. + Instruction *Prev = I.getPrevNonDebugInstruction(); + if (Prev && !Prev->isEHPad() && + isGuaranteedToTransferExecutionToSuccessor(Prev)) { + // Temporarily disable removal of volatile stores preceding unreachable, + // pending a potential LangRef change permitting volatile stores to trap. + // TODO: Either remove this code, or properly integrate the check into + // isGuaranteedToTransferExecutionToSuccessor(). + if (auto *SI = dyn_cast(Prev)) + if (SI->isVolatile()) + return nullptr; + + // A value may still have uses before we process it here (for example, in + // another unreachable block), so convert those to undef. + replaceInstUsesWith(*Prev, UndefValue::get(Prev->getType())); + eraseInstFromFunction(*Prev); + return &I; + } + return nullptr; +} + +Instruction *InstCombinerImpl::visitUnconditionalBranchInst(BranchInst &BI) { assert(BI.isUnconditional() && "Only for unconditional branches."); // If this store is the second-to-last instruction in the basic block @@ -2763,7 +2901,7 @@ Instruction *InstCombiner::visitUnconditionalBranchInst(BranchInst &BI) { return nullptr; } -Instruction *InstCombiner::visitBranchInst(BranchInst &BI) { +Instruction *InstCombinerImpl::visitBranchInst(BranchInst &BI) { if (BI.isUnconditional()) return visitUnconditionalBranchInst(BI); @@ -2799,7 +2937,7 @@ Instruction *InstCombiner::visitBranchInst(BranchInst &BI) { return nullptr; } -Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) { +Instruction *InstCombinerImpl::visitSwitchInst(SwitchInst &SI) { Value *Cond = SI.getCondition(); Value *Op0; ConstantInt *AddRHS; @@ -2830,7 +2968,7 @@ Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) { unsigned NewWidth = Known.getBitWidth() - std::max(LeadingKnownZeros, LeadingKnownOnes); // Shrink the condition operand if the new type is smaller than the old type. - // But do not shrink to a non-standard type, because backend can't generate + // But do not shrink to a non-standard type, because backend can't generate // good code for that yet. // TODO: We can make it aggressive again after fixing PR39569. if (NewWidth > 0 && NewWidth < Known.getBitWidth() && @@ -2849,7 +2987,7 @@ Instruction *InstCombiner::visitSwitchInst(SwitchInst &SI) { return nullptr; } -Instruction *InstCombiner::visitExtractValueInst(ExtractValueInst &EV) { +Instruction *InstCombinerImpl::visitExtractValueInst(ExtractValueInst &EV) { Value *Agg = EV.getAggregateOperand(); if (!EV.hasIndices()) @@ -2994,10 +3132,11 @@ static bool isCatchAll(EHPersonality Personality, Constant *TypeInfo) { case EHPersonality::GNU_CXX_SjLj: case EHPersonality::GNU_ObjC: case EHPersonality::MSVC_X86SEH: - case EHPersonality::MSVC_Win64SEH: + case EHPersonality::MSVC_TableSEH: case EHPersonality::MSVC_CXX: case EHPersonality::CoreCLR: case EHPersonality::Wasm_CXX: + case EHPersonality::XL_CXX: return TypeInfo->isNullValue(); } llvm_unreachable("invalid enum"); @@ -3010,7 +3149,7 @@ static bool shorter_filter(const Value *LHS, const Value *RHS) { cast(RHS->getType())->getNumElements(); } -Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) { +Instruction *InstCombinerImpl::visitLandingPadInst(LandingPadInst &LI) { // The logic here should be correct for any real-world personality function. // However if that turns out not to be true, the offending logic can always // be conditioned on the personality function, like the catch-all logic is. @@ -3319,12 +3458,46 @@ Instruction *InstCombiner::visitLandingPadInst(LandingPadInst &LI) { return nullptr; } -Instruction *InstCombiner::visitFreeze(FreezeInst &I) { +Instruction *InstCombinerImpl::visitFreeze(FreezeInst &I) { Value *Op0 = I.getOperand(0); if (Value *V = SimplifyFreezeInst(Op0, SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); + // freeze (phi const, x) --> phi const, (freeze x) + if (auto *PN = dyn_cast(Op0)) { + if (Instruction *NV = foldOpIntoPhi(I, PN)) + return NV; + } + + if (match(Op0, m_Undef())) { + // If I is freeze(undef), see its uses and fold it to the best constant. + // - or: pick -1 + // - select's condition: pick the value that leads to choosing a constant + // - other ops: pick 0 + Constant *BestValue = nullptr; + Constant *NullValue = Constant::getNullValue(I.getType()); + for (const auto *U : I.users()) { + Constant *C = NullValue; + + if (match(U, m_Or(m_Value(), m_Value()))) + C = Constant::getAllOnesValue(I.getType()); + else if (const auto *SI = dyn_cast(U)) { + if (SI->getCondition() == &I) { + APInt CondVal(1, isa(SI->getFalseValue()) ? 0 : 1); + C = Constant::getIntegerValue(I.getType(), CondVal); + } + } + + if (!BestValue) + BestValue = C; + else if (BestValue != C) + BestValue = NullValue; + } + + return replaceInstUsesWith(I, BestValue); + } + return nullptr; } @@ -3430,7 +3603,7 @@ static bool TryToSinkInstruction(Instruction *I, BasicBlock *DestBlock) { return true; } -bool InstCombiner::run() { +bool InstCombinerImpl::run() { while (!Worklist.isEmpty()) { // Walk deferred instructions in reverse order, and push them to the // worklist, which means they'll end up popped from the worklist in-order. @@ -3492,7 +3665,9 @@ bool InstCombiner::run() { else UserParent = UserInst->getParent(); - if (UserParent != BB) { + // Try sinking to another block. If that block is unreachable, then do + // not bother. SimplifyCFG should handle it. + if (UserParent != BB && DT.isReachableFromEntry(UserParent)) { // See if the user is one of our successors that has only one // predecessor, so that we don't have to split the critical edge. bool ShouldSink = UserParent->getUniquePredecessor() == BB; @@ -3526,7 +3701,8 @@ bool InstCombiner::run() { // Now that we have an instruction, try combining it to simplify it. Builder.SetInsertPoint(I); - Builder.SetCurrentDebugLocation(I->getDebugLoc()); + Builder.CollectMetadataToCopy( + I, {LLVMContext::MD_dbg, LLVMContext::MD_annotation}); #ifndef NDEBUG std::string OrigI; @@ -3541,8 +3717,8 @@ bool InstCombiner::run() { LLVM_DEBUG(dbgs() << "IC: Old = " << *I << '\n' << " New = " << *Result << '\n'); - if (I->getDebugLoc()) - Result->setDebugLoc(I->getDebugLoc()); + Result->copyMetadata(*I, + {LLVMContext::MD_dbg, LLVMContext::MD_annotation}); // Everything uses the new instruction now. I->replaceAllUsesWith(Result); @@ -3553,10 +3729,14 @@ bool InstCombiner::run() { BasicBlock *InstParent = I->getParent(); BasicBlock::iterator InsertPos = I->getIterator(); - // If we replace a PHI with something that isn't a PHI, fix up the - // insertion point. - if (!isa(Result) && isa(InsertPos)) - InsertPos = InstParent->getFirstInsertionPt(); + // Are we replace a PHI with something that isn't a PHI, or vice versa? + if (isa(Result) != isa(I)) { + // We need to fix up the insertion point. + if (isa(I)) // PHI -> Non-PHI + InsertPos = InstParent->getFirstInsertionPt(); + else // Non-PHI -> PHI + InsertPos = InstParent->getFirstNonPHI()->getIterator(); + } InstParent->getInstList().insert(InsertPos, Result); @@ -3586,6 +3766,55 @@ bool InstCombiner::run() { return MadeIRChange; } +// Track the scopes used by !alias.scope and !noalias. In a function, a +// @llvm.experimental.noalias.scope.decl is only useful if that scope is used +// by both sets. If not, the declaration of the scope can be safely omitted. +// The MDNode of the scope can be omitted as well for the instructions that are +// part of this function. We do not do that at this point, as this might become +// too time consuming to do. +class AliasScopeTracker { + SmallPtrSet UsedAliasScopesAndLists; + SmallPtrSet UsedNoAliasScopesAndLists; + +public: + void analyse(Instruction *I) { + // This seems to be faster than checking 'mayReadOrWriteMemory()'. + if (!I->hasMetadataOtherThanDebugLoc()) + return; + + auto Track = [](Metadata *ScopeList, auto &Container) { + const auto *MDScopeList = dyn_cast_or_null(ScopeList); + if (!MDScopeList || !Container.insert(MDScopeList).second) + return; + for (auto &MDOperand : MDScopeList->operands()) + if (auto *MDScope = dyn_cast(MDOperand)) + Container.insert(MDScope); + }; + + Track(I->getMetadata(LLVMContext::MD_alias_scope), UsedAliasScopesAndLists); + Track(I->getMetadata(LLVMContext::MD_noalias), UsedNoAliasScopesAndLists); + } + + bool isNoAliasScopeDeclDead(Instruction *Inst) { + NoAliasScopeDeclInst *Decl = dyn_cast(Inst); + if (!Decl) + return false; + + assert(Decl->use_empty() && + "llvm.experimental.noalias.scope.decl in use ?"); + const MDNode *MDSL = Decl->getScopeList(); + assert(MDSL->getNumOperands() == 1 && + "llvm.experimental.noalias.scope should refer to a single scope"); + auto &MDOperand = MDSL->getOperand(0); + if (auto *MD = dyn_cast(MDOperand)) + return !UsedAliasScopesAndLists.contains(MD) || + !UsedNoAliasScopesAndLists.contains(MD); + + // Not an MDNode ? throw away. + return true; + } +}; + /// Populate the IC worklist from a function, by walking it in depth-first /// order and adding all reachable code to the worklist. /// @@ -3604,6 +3833,7 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, SmallVector InstrsForInstCombineWorklist; DenseMap FoldedConstants; + AliasScopeTracker SeenAliasScopes; do { BasicBlock *BB = Worklist.pop_back_val(); @@ -3650,8 +3880,10 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, // Skip processing debug intrinsics in InstCombine. Processing these call instructions // consumes non-trivial amount of time and provides no value for the optimization. - if (!isa(Inst)) + if (!isa(Inst)) { InstrsForInstCombineWorklist.push_back(Inst); + SeenAliasScopes.analyse(Inst); + } } // Recursively visit successors. If this is a branch or switch on a @@ -3671,8 +3903,7 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, } } - for (BasicBlock *SuccBB : successors(TI)) - Worklist.push_back(SuccBB); + append_range(Worklist, successors(TI)); } while (!Worklist.empty()); // Remove instructions inside unreachable blocks. This prevents the @@ -3682,8 +3913,12 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, if (Visited.count(&BB)) continue; - unsigned NumDeadInstInBB = removeAllNonTerminatorAndEHPadInstructions(&BB); - MadeIRChange |= NumDeadInstInBB > 0; + unsigned NumDeadInstInBB; + unsigned NumDeadDbgInstInBB; + std::tie(NumDeadInstInBB, NumDeadDbgInstInBB) = + removeAllNonTerminatorAndEHPadInstructions(&BB); + + MadeIRChange |= NumDeadInstInBB + NumDeadDbgInstInBB > 0; NumDeadInst += NumDeadInstInBB; } @@ -3696,7 +3931,8 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, for (Instruction *Inst : reverse(InstrsForInstCombineWorklist)) { // DCE instruction if trivially dead. As we iterate in reverse program // order here, we will clean up whole chains of dead instructions. - if (isInstructionTriviallyDead(Inst, TLI)) { + if (isInstructionTriviallyDead(Inst, TLI) || + SeenAliasScopes.isNoAliasScopeDeclDead(Inst)) { ++NumDeadInst; LLVM_DEBUG(dbgs() << "IC: DCE: " << *Inst << '\n'); salvageDebugInfo(*Inst); @@ -3713,8 +3949,8 @@ static bool prepareICWorklistFromFunction(Function &F, const DataLayout &DL, static bool combineInstructionsOverFunction( Function &F, InstCombineWorklist &Worklist, AliasAnalysis *AA, - AssumptionCache &AC, TargetLibraryInfo &TLI, DominatorTree &DT, - OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI, + AssumptionCache &AC, TargetLibraryInfo &TLI, TargetTransformInfo &TTI, + DominatorTree &DT, OptimizationRemarkEmitter &ORE, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, unsigned MaxIterations, LoopInfo *LI) { auto &DL = F.getParent()->getDataLayout(); MaxIterations = std::min(MaxIterations, LimitMaxIterations.getValue()); @@ -3738,6 +3974,7 @@ static bool combineInstructionsOverFunction( // Iterate while there is work to do. unsigned Iteration = 0; while (true) { + ++NumWorklistIterations; ++Iteration; if (Iteration > InfiniteLoopDetectionThreshold) { @@ -3758,8 +3995,8 @@ static bool combineInstructionsOverFunction( MadeIRChange |= prepareICWorklistFromFunction(F, DL, &TLI, Worklist); - InstCombiner IC(Worklist, Builder, F.hasMinSize(), AA, - AC, TLI, DT, ORE, BFI, PSI, DL, LI); + InstCombinerImpl IC(Worklist, Builder, F.hasMinSize(), AA, AC, TLI, TTI, DT, + ORE, BFI, PSI, DL, LI); IC.MaxArraySizeForCombine = MaxArraySize; if (!IC.run()) @@ -3782,6 +4019,7 @@ PreservedAnalyses InstCombinePass::run(Function &F, auto &DT = AM.getResult(F); auto &TLI = AM.getResult(F); auto &ORE = AM.getResult(F); + auto &TTI = AM.getResult(F); auto *LI = AM.getCachedResult(F); @@ -3792,8 +4030,8 @@ PreservedAnalyses InstCombinePass::run(Function &F, auto *BFI = (PSI && PSI->hasProfileSummary()) ? &AM.getResult(F) : nullptr; - if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, DT, ORE, BFI, - PSI, MaxIterations, LI)) + if (!combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE, + BFI, PSI, MaxIterations, LI)) // No changes, all analyses are preserved. return PreservedAnalyses::all(); @@ -3811,6 +4049,7 @@ void InstructionCombiningPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); AU.addRequired(); AU.addRequired(); AU.addPreserved(); @@ -3829,6 +4068,7 @@ bool InstructionCombiningPass::runOnFunction(Function &F) { auto AA = &getAnalysis().getAAResults(); auto &AC = getAnalysis().getAssumptionCache(F); auto &TLI = getAnalysis().getTLI(F); + auto &TTI = getAnalysis().getTTI(F); auto &DT = getAnalysis().getDomTree(); auto &ORE = getAnalysis().getORE(); @@ -3842,8 +4082,8 @@ bool InstructionCombiningPass::runOnFunction(Function &F) { &getAnalysis().getBFI() : nullptr; - return combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, DT, ORE, BFI, - PSI, MaxIterations, LI); + return combineInstructionsOverFunction(F, Worklist, AA, AC, TLI, TTI, DT, ORE, + BFI, PSI, MaxIterations, LI); } char InstructionCombiningPass::ID = 0; @@ -3862,6 +4102,7 @@ INITIALIZE_PASS_BEGIN(InstructionCombiningPass, "instcombine", "Combine redundant instructions", false, false) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) diff --git a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp index ee09a4d9db7e..f4e471706d3c 100644 --- a/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/AddressSanitizer.cpp @@ -105,6 +105,7 @@ static const uint64_t kSystemZ_ShadowOffset64 = 1ULL << 52; static const uint64_t kMIPS32_ShadowOffset32 = 0x0aaa0000; static const uint64_t kMIPS64_ShadowOffset64 = 1ULL << 37; static const uint64_t kAArch64_ShadowOffset64 = 1ULL << 36; +static const uint64_t kRISCV64_ShadowOffset64 = 0x20000000; static const uint64_t kFreeBSD_ShadowOffset32 = 1ULL << 30; static const uint64_t kFreeBSD_ShadowOffset64 = 1ULL << 46; static const uint64_t kNetBSD_ShadowOffset32 = 1ULL << 30; @@ -129,56 +130,48 @@ static const size_t kMaxStackMallocSize = 1 << 16; // 64K static const uintptr_t kCurrentStackFrameMagic = 0x41B58AB3; static const uintptr_t kRetiredStackFrameMagic = 0x45E0360E; -static const char *const kAsanModuleCtorName = "asan.module_ctor"; -static const char *const kAsanModuleDtorName = "asan.module_dtor"; +const char kAsanModuleCtorName[] = "asan.module_ctor"; +const char kAsanModuleDtorName[] = "asan.module_dtor"; static const uint64_t kAsanCtorAndDtorPriority = 1; // On Emscripten, the system needs more than one priorities for constructors. static const uint64_t kAsanEmscriptenCtorAndDtorPriority = 50; -static const char *const kAsanReportErrorTemplate = "__asan_report_"; -static const char *const kAsanRegisterGlobalsName = "__asan_register_globals"; -static const char *const kAsanUnregisterGlobalsName = - "__asan_unregister_globals"; -static const char *const kAsanRegisterImageGlobalsName = - "__asan_register_image_globals"; -static const char *const kAsanUnregisterImageGlobalsName = - "__asan_unregister_image_globals"; -static const char *const kAsanRegisterElfGlobalsName = - "__asan_register_elf_globals"; -static const char *const kAsanUnregisterElfGlobalsName = - "__asan_unregister_elf_globals"; -static const char *const kAsanPoisonGlobalsName = "__asan_before_dynamic_init"; -static const char *const kAsanUnpoisonGlobalsName = "__asan_after_dynamic_init"; -static const char *const kAsanInitName = "__asan_init"; -static const char *const kAsanVersionCheckNamePrefix = - "__asan_version_mismatch_check_v"; -static const char *const kAsanPtrCmp = "__sanitizer_ptr_cmp"; -static const char *const kAsanPtrSub = "__sanitizer_ptr_sub"; -static const char *const kAsanHandleNoReturnName = "__asan_handle_no_return"; +const char kAsanReportErrorTemplate[] = "__asan_report_"; +const char kAsanRegisterGlobalsName[] = "__asan_register_globals"; +const char kAsanUnregisterGlobalsName[] = "__asan_unregister_globals"; +const char kAsanRegisterImageGlobalsName[] = "__asan_register_image_globals"; +const char kAsanUnregisterImageGlobalsName[] = + "__asan_unregister_image_globals"; +const char kAsanRegisterElfGlobalsName[] = "__asan_register_elf_globals"; +const char kAsanUnregisterElfGlobalsName[] = "__asan_unregister_elf_globals"; +const char kAsanPoisonGlobalsName[] = "__asan_before_dynamic_init"; +const char kAsanUnpoisonGlobalsName[] = "__asan_after_dynamic_init"; +const char kAsanInitName[] = "__asan_init"; +const char kAsanVersionCheckNamePrefix[] = "__asan_version_mismatch_check_v"; +const char kAsanPtrCmp[] = "__sanitizer_ptr_cmp"; +const char kAsanPtrSub[] = "__sanitizer_ptr_sub"; +const char kAsanHandleNoReturnName[] = "__asan_handle_no_return"; static const int kMaxAsanStackMallocSizeClass = 10; -static const char *const kAsanStackMallocNameTemplate = "__asan_stack_malloc_"; -static const char *const kAsanStackFreeNameTemplate = "__asan_stack_free_"; -static const char *const kAsanGenPrefix = "___asan_gen_"; -static const char *const kODRGenPrefix = "__odr_asan_gen_"; -static const char *const kSanCovGenPrefix = "__sancov_gen_"; -static const char *const kAsanSetShadowPrefix = "__asan_set_shadow_"; -static const char *const kAsanPoisonStackMemoryName = - "__asan_poison_stack_memory"; -static const char *const kAsanUnpoisonStackMemoryName = - "__asan_unpoison_stack_memory"; +const char kAsanStackMallocNameTemplate[] = "__asan_stack_malloc_"; +const char kAsanStackFreeNameTemplate[] = "__asan_stack_free_"; +const char kAsanGenPrefix[] = "___asan_gen_"; +const char kODRGenPrefix[] = "__odr_asan_gen_"; +const char kSanCovGenPrefix[] = "__sancov_gen_"; +const char kAsanSetShadowPrefix[] = "__asan_set_shadow_"; +const char kAsanPoisonStackMemoryName[] = "__asan_poison_stack_memory"; +const char kAsanUnpoisonStackMemoryName[] = "__asan_unpoison_stack_memory"; // ASan version script has __asan_* wildcard. Triple underscore prevents a // linker (gold) warning about attempting to export a local symbol. -static const char *const kAsanGlobalsRegisteredFlagName = - "___asan_globals_registered"; +const char kAsanGlobalsRegisteredFlagName[] = "___asan_globals_registered"; -static const char *const kAsanOptionDetectUseAfterReturn = +const char kAsanOptionDetectUseAfterReturn[] = "__asan_option_detect_stack_use_after_return"; -static const char *const kAsanShadowMemoryDynamicAddress = +const char kAsanShadowMemoryDynamicAddress[] = "__asan_shadow_memory_dynamic_address"; -static const char *const kAsanAllocaPoison = "__asan_alloca_poison"; -static const char *const kAsanAllocasUnpoison = "__asan_allocas_unpoison"; +const char kAsanAllocaPoison[] = "__asan_alloca_poison"; +const char kAsanAllocasUnpoison[] = "__asan_allocas_unpoison"; // Accesses sizes are powers of two: 1, 2, 4, 8, 16. static const size_t kNumberOfAccessSizes = 5; @@ -434,6 +427,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsKasan) { bool IsAndroid = TargetTriple.isAndroid(); bool IsIOS = TargetTriple.isiOS() || TargetTriple.isWatchOS(); + bool IsMacOS = TargetTriple.isMacOSX(); bool IsFreeBSD = TargetTriple.isOSFreeBSD(); bool IsNetBSD = TargetTriple.isOSNetBSD(); bool IsPS4CPU = TargetTriple.isPS4CPU(); @@ -446,6 +440,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, bool IsMIPS64 = TargetTriple.isMIPS64(); bool IsArmOrThumb = TargetTriple.isARM() || TargetTriple.isThumb(); bool IsAArch64 = TargetTriple.getArch() == Triple::aarch64; + bool IsRISCV64 = TargetTriple.getArch() == Triple::riscv64; bool IsWindows = TargetTriple.isOSWindows(); bool IsFuchsia = TargetTriple.isOSFuchsia(); bool IsMyriad = TargetTriple.getVendor() == llvm::Triple::Myriad; @@ -510,8 +505,12 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, Mapping.Offset = kMIPS64_ShadowOffset64; else if (IsIOS) Mapping.Offset = kDynamicShadowSentinel; + else if (IsMacOS && IsAArch64) + Mapping.Offset = kDynamicShadowSentinel; else if (IsAArch64) Mapping.Offset = kAArch64_ShadowOffset64; + else if (IsRISCV64) + Mapping.Offset = kRISCV64_ShadowOffset64; else Mapping.Offset = kDefaultShadowOffset64; } @@ -530,6 +529,7 @@ static ShadowMapping getShadowMapping(Triple &TargetTriple, int LongSize, // we could OR the constant in a single instruction, but it's more // efficient to load it once and use indexed addressing. Mapping.OrShadowOffset = !IsAArch64 && !IsPPC64 && !IsSystemZ && !IsPS4CPU && + !IsRISCV64 && !(Mapping.Offset & (Mapping.Offset - 1)) && Mapping.Offset != kDynamicShadowSentinel; bool IsAndroidWithIfuncSupport = @@ -792,7 +792,7 @@ private: StringRef InternalSuffix); Instruction *CreateAsanModuleDtor(Module &M); - bool canInstrumentAliasedGlobal(const GlobalAlias &GA) const; + const GlobalVariable *getExcludedAliasedGlobal(const GlobalAlias &GA) const; bool shouldInstrumentGlobal(GlobalVariable *G) const; bool ShouldUseMachOGlobalsSection() const; StringRef getGlobalMetadataSection() const; @@ -908,10 +908,6 @@ struct FunctionStackPoisoner : public InstVisitor { AllocaInst *DynamicAllocaLayout = nullptr; IntrinsicInst *LocalEscapeCall = nullptr; - // Maps Value to an AllocaInst from which the Value is originated. - using AllocaForValueMapTy = DenseMap; - AllocaForValueMapTy AllocaForValue; - bool HasInlineAsm = false; bool HasReturnsTwiceCall = false; @@ -965,8 +961,14 @@ struct FunctionStackPoisoner : public InstVisitor { void createDynamicAllocasInitStorage(); // ----------------------- Visitors. - /// Collect all Ret instructions. - void visitReturnInst(ReturnInst &RI) { RetVec.push_back(&RI); } + /// Collect all Ret instructions, or the musttail call instruction if it + /// precedes the return instruction. + void visitReturnInst(ReturnInst &RI) { + if (CallInst *CI = RI.getParent()->getTerminatingMustTailCall()) + RetVec.push_back(CI); + else + RetVec.push_back(&RI); + } /// Collect all Resume instructions. void visitResumeInst(ResumeInst &RI) { RetVec.push_back(&RI); } @@ -1000,10 +1002,10 @@ struct FunctionStackPoisoner : public InstVisitor { // Unpoison dynamic allocas redzones. void unpoisonDynamicAllocas() { - for (auto &Ret : RetVec) + for (Instruction *Ret : RetVec) unpoisonDynamicAllocasBeforeInst(Ret, DynamicAllocaLayout); - for (auto &StackRestoreInst : StackRestoreVec) + for (Instruction *StackRestoreInst : StackRestoreVec) unpoisonDynamicAllocasBeforeInst(StackRestoreInst, StackRestoreInst->getOperand(0)); } @@ -1062,8 +1064,9 @@ struct FunctionStackPoisoner : public InstVisitor { !ConstantInt::isValueValidForType(IntptrTy, SizeValue)) return; // Find alloca instruction that corresponds to llvm.lifetime argument. - AllocaInst *AI = - llvm::findAllocaForValue(II.getArgOperand(1), AllocaForValue); + // Currently we can only handle lifetime markers pointing to the + // beginning of the alloca. + AllocaInst *AI = findAllocaForValue(II.getArgOperand(1), true); if (!AI) { HasUntracedLifetimeIntrinsic = true; return; @@ -1558,7 +1561,7 @@ void AddressSanitizer::instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis, if (ClOpt && ClOptGlobals) { // If initialization order checking is disabled, a simple access to a // dynamically initialized global is always valid. - GlobalVariable *G = dyn_cast(GetUnderlyingObject(Addr, DL)); + GlobalVariable *G = dyn_cast(getUnderlyingObject(Addr)); if (G && (!ClInitializers || GlobalIsLinkerInitialized(G)) && isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) { NumOptimizedAccessesToGlobalVar++; @@ -1568,7 +1571,7 @@ void AddressSanitizer::instrumentMop(ObjectSizeOffsetVisitor &ObjSizeVis, if (ClOpt && ClOptStack) { // A direct inbounds access to a stack variable is always valid. - if (isa(GetUnderlyingObject(Addr, DL)) && + if (isa(getUnderlyingObject(Addr)) && isSafeAccess(ObjSizeVis, Addr, O.TypeSize)) { NumOptimizedAccessesToStackVar++; return; @@ -1784,20 +1787,22 @@ void ModuleAddressSanitizer::createInitializerPoisonCalls( } } -bool ModuleAddressSanitizer::canInstrumentAliasedGlobal( - const GlobalAlias &GA) const { +const GlobalVariable * +ModuleAddressSanitizer::getExcludedAliasedGlobal(const GlobalAlias &GA) const { // In case this function should be expanded to include rules that do not just // apply when CompileKernel is true, either guard all existing rules with an // 'if (CompileKernel) { ... }' or be absolutely sure that all these rules // should also apply to user space. assert(CompileKernel && "Only expecting to be called when compiling kernel"); + const Constant *C = GA.getAliasee(); + // When compiling the kernel, globals that are aliased by symbols prefixed // by "__" are special and cannot be padded with a redzone. if (GA.getName().startswith("__")) - return false; + return dyn_cast(C->stripPointerCastsAndAliases()); - return true; + return nullptr; } bool ModuleAddressSanitizer::shouldInstrumentGlobal(GlobalVariable *G) const { @@ -1868,6 +1873,14 @@ bool ModuleAddressSanitizer::shouldInstrumentGlobal(GlobalVariable *G) const { return false; } + // Do not instrument user-defined sections (with names resembling + // valid C identifiers) + if (TargetTriple.isOSBinFormatELF()) { + if (llvm::all_of(Section, + [](char c) { return llvm::isAlnum(c) || c == '_'; })) + return false; + } + // On COFF, if the section name contains '$', it is highly likely that the // user is using section sorting to create an array of globals similar to // the way initialization callbacks are registered in .init_array and @@ -1952,9 +1965,10 @@ StringRef ModuleAddressSanitizer::getGlobalMetadataSection() const { case Triple::ELF: return "asan_globals"; case Triple::MachO: return "__DATA,__asan_globals,regular"; case Triple::Wasm: + case Triple::GOFF: case Triple::XCOFF: report_fatal_error( - "ModuleAddressSanitizer not implemented for object file format."); + "ModuleAddressSanitizer not implemented for object file format"); case Triple::UnknownObjectFormat: break; } @@ -2103,23 +2117,10 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF( SetComdatForGlobalMetadata(G, Metadata, UniqueModuleId); } - // This should never be called when there are no globals, by the logic that - // computes the UniqueModuleId string, which is "" when there are no globals. - // It's important that this path is only used when there are actually some - // globals, because that means that there will certainly be a live - // `asan_globals` input section at link time and thus `__start_asan_globals` - // and `__stop_asan_globals` symbols will definitely be defined at link time. - // This means there's no need for the references to them to be weak, which - // enables better code generation because ExternalWeakLinkage implies - // isInterposable() and thus requires GOT indirection for PIC. Since these - // are known-defined hidden/dso_local symbols, direct PIC accesses without - // dynamic relocation are always sufficient. - assert(!MetadataGlobals.empty()); - assert(!UniqueModuleId.empty()); - // Update llvm.compiler.used, adding the new metadata globals. This is // needed so that during LTO these variables stay alive. - appendToCompilerUsed(M, MetadataGlobals); + if (!MetadataGlobals.empty()) + appendToCompilerUsed(M, MetadataGlobals); // RegisteredFlag serves two purposes. First, we can pass it to dladdr() // to look up the loaded image that contains it. Second, we can store in it @@ -2132,18 +2133,15 @@ void ModuleAddressSanitizer::InstrumentGlobalsELF( ConstantInt::get(IntptrTy, 0), kAsanGlobalsRegisteredFlagName); RegisteredFlag->setVisibility(GlobalVariable::HiddenVisibility); - // Create start and stop symbols. These are known to be defined by - // the linker, see comment above. - auto MakeStartStopGV = [&](const char *Prefix) { - GlobalVariable *StartStop = - new GlobalVariable(M, IntptrTy, false, GlobalVariable::ExternalLinkage, - nullptr, Prefix + getGlobalMetadataSection()); - StartStop->setVisibility(GlobalVariable::HiddenVisibility); - assert(StartStop->isImplicitDSOLocal()); - return StartStop; - }; - GlobalVariable *StartELFMetadata = MakeStartStopGV("__start_"); - GlobalVariable *StopELFMetadata = MakeStartStopGV("__stop_"); + // Create start and stop symbols. + GlobalVariable *StartELFMetadata = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, + "__start_" + getGlobalMetadataSection()); + StartELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); + GlobalVariable *StopELFMetadata = new GlobalVariable( + M, IntptrTy, false, GlobalVariable::ExternalWeakLinkage, nullptr, + "__stop_" + getGlobalMetadataSection()); + StopELFMetadata->setVisibility(GlobalVariable::HiddenVisibility); // Create a call to register the globals with the runtime. IRB.CreateCall(AsanRegisterElfGlobals, @@ -2256,14 +2254,12 @@ bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M, *CtorComdat = false; // Build set of globals that are aliased by some GA, where - // canInstrumentAliasedGlobal(GA) returns false. + // getExcludedAliasedGlobal(GA) returns the relevant GlobalVariable. SmallPtrSet AliasedGlobalExclusions; if (CompileKernel) { for (auto &GA : M.aliases()) { - if (const auto *GV = dyn_cast(GA.getAliasee())) { - if (!canInstrumentAliasedGlobal(GA)) - AliasedGlobalExclusions.insert(GV); - } + if (const GlobalVariable *GV = getExcludedAliasedGlobal(GA)) + AliasedGlobalExclusions.insert(GV); } } @@ -2349,12 +2345,9 @@ bool ModuleAddressSanitizer::InstrumentGlobals(IRBuilder<> &IRB, Module &M, NewGlobal->setSection("__TEXT,__asan_cstring,regular"); } - // Transfer the debug info. The payload starts at offset zero so we can - // copy the debug info over as is. - SmallVector GVs; - G->getDebugInfo(GVs); - for (auto *GV : GVs) - NewGlobal->addDebugInfo(GV); + // Transfer the debug info and type metadata. The payload starts at offset + // zero so we can copy the metadata over as is. + NewGlobal->copyMetadata(G, 0); Value *Indices2[2]; Indices2[0] = IRB.getInt32(0); @@ -3112,7 +3105,8 @@ void FunctionStackPoisoner::processStaticAllocas() { int StackMallocIdx = -1; DebugLoc EntryDebugLocation; if (auto SP = F.getSubprogram()) - EntryDebugLocation = DebugLoc::get(SP->getScopeLine(), 0, SP); + EntryDebugLocation = + DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); Instruction *InsBefore = AllocaVec[0]; IRBuilder<> IRB(InsBefore); @@ -3320,7 +3314,7 @@ void FunctionStackPoisoner::processStaticAllocas() { SmallVector ShadowAfterReturn; // (Un)poison the stack before all ret instructions. - for (auto Ret : RetVec) { + for (Instruction *Ret : RetVec) { IRBuilder<> IRBRet(Ret); // Mark the current frame as retired. IRBRet.CreateStore(ConstantInt::get(IntptrTy, kRetiredStackFrameMagic), diff --git a/llvm/lib/Transforms/Instrumentation/CFGMST.h b/llvm/lib/Transforms/Instrumentation/CFGMST.h index 9addb5d1ba93..6580b6d7d73e 100644 --- a/llvm/lib/Transforms/Instrumentation/CFGMST.h +++ b/llvm/lib/Transforms/Instrumentation/CFGMST.h @@ -20,7 +20,6 @@ #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/CFG.h" #include "llvm/Support/BranchProbability.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -30,9 +29,6 @@ #define DEBUG_TYPE "cfgmst" using namespace llvm; -static cl::opt PGOInstrumentEntry( - "pgo-instrument-entry", cl::init(false), cl::Hidden, - cl::desc("Force to instrument function entry basicblock.")); namespace llvm { @@ -107,7 +103,7 @@ public: const BasicBlock *Entry = &(F.getEntryBlock()); uint64_t EntryWeight = (BFI != nullptr ? BFI->getEntryFreq() : 2); // If we want to instrument the entry count, lower the weight to 0. - if (PGOInstrumentEntry) + if (InstrumentFuncEntry) EntryWeight = 0; Edge *EntryIncoming = nullptr, *EntryOutgoing = nullptr, *ExitOutgoing = nullptr, *ExitIncoming = nullptr; @@ -282,14 +278,19 @@ public: BranchProbabilityInfo *BPI; BlockFrequencyInfo *BFI; + // If function entry will be always instrumented. + bool InstrumentFuncEntry; + public: - CFGMST(Function &Func, BranchProbabilityInfo *BPI_ = nullptr, + CFGMST(Function &Func, bool InstrumentFuncEntry_, + BranchProbabilityInfo *BPI_ = nullptr, BlockFrequencyInfo *BFI_ = nullptr) - : F(Func), BPI(BPI_), BFI(BFI_) { + : F(Func), BPI(BPI_), BFI(BFI_), + InstrumentFuncEntry(InstrumentFuncEntry_) { buildEdges(); sortEdgesByWeight(); computeMinimumSpanningTree(); - if (PGOInstrumentEntry && (AllEdges.size() > 1)) + if (AllEdges.size() > 1 && InstrumentFuncEntry) std::iter_swap(std::move(AllEdges.begin()), std::move(AllEdges.begin() + AllEdges.size() - 1)); } diff --git a/llvm/lib/Transforms/Instrumentation/CGProfile.cpp b/llvm/lib/Transforms/Instrumentation/CGProfile.cpp index 0cc0d9b07387..9acd82c005e6 100644 --- a/llvm/lib/Transforms/Instrumentation/CGProfile.cpp +++ b/llvm/lib/Transforms/Instrumentation/CGProfile.cpp @@ -53,7 +53,8 @@ static bool runCGProfilePass( InstrProfSymtab Symtab; auto UpdateCounts = [&](TargetTransformInfo &TTI, Function *F, Function *CalledF, uint64_t NewCount) { - if (!CalledF || !TTI.isLoweredToCall(CalledF)) + if (!CalledF || !TTI.isLoweredToCall(CalledF) || + CalledF->hasDLLImportStorageClass()) return; uint64_t &Count = Counts[std::make_pair(F, CalledF)]; Count = SaturatingAdd(Count, NewCount); diff --git a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp index a99c58b74fb1..927c34180db9 100644 --- a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp +++ b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp @@ -260,10 +260,9 @@ class CHRScope { if (TailRegionSet.count(Parent)) return false; - assert(llvm::find_if(RegInfos, - [&Parent](const RegInfo &RI) { - return Parent == RI.R; - }) != RegInfos.end() && + assert(llvm::any_of( + RegInfos, + [&Parent](const RegInfo &RI) { return Parent == RI.R; }) && "Must be in head"); return true; }); @@ -732,7 +731,7 @@ static Instruction* getBranchInsertPoint(RegInfo &RI) { } } for (Instruction &I : *EntryBB) { - if (EntryBlockSelectSet.count(&I) > 0) { + if (EntryBlockSelectSet.contains(&I)) { assert(&I == HoistPoint && "HoistPoint must be the first one in Selects"); break; @@ -950,10 +949,9 @@ void CHR::checkScopeHoistable(CHRScope *Scope) { << "Dropped select due to unhoistable branch"; }); } - Selects.erase(std::remove_if(Selects.begin(), Selects.end(), - [EntryBB](SelectInst *SI) { - return SI->getParent() == EntryBB; - }), Selects.end()); + llvm::erase_if(Selects, [EntryBB](SelectInst *SI) { + return SI->getParent() == EntryBB; + }); Unhoistables.clear(); InsertPoint = Branch; } @@ -1249,7 +1247,7 @@ SmallVector CHR::splitScope( SmallVector SubSplits = splitScope( Sub, Split, &SplitConditionValues, SplitInsertPoint, Output, SplitUnhoistables); - NewSubs.insert(NewSubs.end(), SubSplits.begin(), SubSplits.end()); + llvm::append_range(NewSubs, SubSplits); } Split->Subs = NewSubs; } @@ -1306,17 +1304,17 @@ void CHR::classifyBiasedScopes(CHRScope *Scope, CHRScope *OutermostScope) { for (RegInfo &RI : Scope->RegInfos) { if (RI.HasBranch) { Region *R = RI.R; - if (TrueBiasedRegionsGlobal.count(R) > 0) + if (TrueBiasedRegionsGlobal.contains(R)) OutermostScope->TrueBiasedRegions.insert(R); - else if (FalseBiasedRegionsGlobal.count(R) > 0) + else if (FalseBiasedRegionsGlobal.contains(R)) OutermostScope->FalseBiasedRegions.insert(R); else llvm_unreachable("Must be biased"); } for (SelectInst *SI : RI.Selects) { - if (TrueBiasedSelectsGlobal.count(SI) > 0) + if (TrueBiasedSelectsGlobal.contains(SI)) OutermostScope->TrueBiasedSelects.insert(SI); - else if (FalseBiasedSelectsGlobal.count(SI) > 0) + else if (FalseBiasedSelectsGlobal.contains(SI)) OutermostScope->FalseBiasedSelects.insert(SI); else llvm_unreachable("Must be biased"); @@ -1399,8 +1397,8 @@ void CHR::setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope) { DenseSet HoistStops; bool IsHoisted = false; if (RI.HasBranch) { - assert((OutermostScope->TrueBiasedRegions.count(R) > 0 || - OutermostScope->FalseBiasedRegions.count(R) > 0) && + assert((OutermostScope->TrueBiasedRegions.contains(R) || + OutermostScope->FalseBiasedRegions.contains(R)) && "Must be truthy or falsy"); auto *BI = cast(R->getEntry()->getTerminator()); // Note checkHoistValue fills in HoistStops. @@ -1412,8 +1410,8 @@ void CHR::setCHRRegions(CHRScope *Scope, CHRScope *OutermostScope) { IsHoisted = true; } for (SelectInst *SI : RI.Selects) { - assert((OutermostScope->TrueBiasedSelects.count(SI) > 0 || - OutermostScope->FalseBiasedSelects.count(SI) > 0) && + assert((OutermostScope->TrueBiasedSelects.contains(SI) || + OutermostScope->FalseBiasedSelects.contains(SI)) && "Must be true or false biased"); // Note checkHoistValue fills in HoistStops. DenseMap Visited; @@ -1609,9 +1607,7 @@ static void insertTrivialPHIs(CHRScope *Scope, // Insert a trivial phi for I (phi [&I, P0], [&I, P1], ...) at // ExitBlock. Replace I with the new phi in UI unless UI is another // phi at ExitBlock. - unsigned PredCount = std::distance(pred_begin(ExitBlock), - pred_end(ExitBlock)); - PHINode *PN = PHINode::Create(I.getType(), PredCount, "", + PHINode *PN = PHINode::Create(I.getType(), pred_size(ExitBlock), "", &ExitBlock->front()); for (BasicBlock *Pred : predecessors(ExitBlock)) { PN->addIncoming(&I, Pred); diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp index 284631900731..1b14b8d56994 100644 --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -46,6 +46,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Instrumentation/DataFlowSanitizer.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -78,6 +79,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" @@ -104,10 +106,18 @@ using namespace llvm; +// This must be consistent with ShadowWidthBits. +static const Align kShadowTLSAlignment = Align(2); + +// The size of TLS variables. These constants must be kept in sync with the ones +// in dfsan.cpp. +static const unsigned kArgTLSSize = 800; +static const unsigned kRetvalTLSSize = 800; + // External symbol to be used when generating the shadow address for // architectures with multiple VMAs. Instead of using a constant integer // the runtime will set the external mask based on the VMA range. -static const char *const kDFSanExternShadowPtrMask = "__dfsan_shadow_ptr_mask"; +const char kDFSanExternShadowPtrMask[] = "__dfsan_shadow_ptr_mask"; // The -dfsan-preserve-alignment flag controls whether this pass assumes that // alignment requirements provided by the input IR are correct. For example, @@ -167,8 +177,8 @@ static cl::opt ClDebugNonzeroLabels( // // If this flag is set to true, the user must provide definitions for the // following callback functions: -// void __dfsan_load_callback(dfsan_label Label); -// void __dfsan_store_callback(dfsan_label Label); +// void __dfsan_load_callback(dfsan_label Label, void* addr); +// void __dfsan_store_callback(dfsan_label Label, void* addr); // void __dfsan_mem_transfer_callback(dfsan_label *Start, size_t Len); // void __dfsan_cmp_callback(dfsan_label CombinedLabel); static cl::opt ClEventCallbacks( @@ -176,6 +186,21 @@ static cl::opt ClEventCallbacks( cl::desc("Insert calls to __dfsan_*_callback functions on data events."), cl::Hidden, cl::init(false)); +// Use a distinct bit for each base label, enabling faster unions with less +// instrumentation. Limits the max number of base labels to 16. +static cl::opt ClFast16Labels( + "dfsan-fast-16-labels", + cl::desc("Use more efficient instrumentation, limiting the number of " + "labels to 16."), + cl::Hidden, cl::init(false)); + +// Controls whether the pass tracks the control flow of select instructions. +static cl::opt ClTrackSelectControlFlow( + "dfsan-track-select-control-flow", + cl::desc("Propagate labels from condition values of select instructions " + "to results."), + cl::Hidden, cl::init(true)); + static StringRef GetGlobalTypeString(const GlobalValue &G) { // Types of GlobalVariables are always pointer types. Type *GType = G.getValueType(); @@ -292,7 +317,7 @@ AttributeList TransformFunctionAttributes( llvm::makeArrayRef(ArgumentAttributes)); } -class DataFlowSanitizer : public ModulePass { +class DataFlowSanitizer { friend struct DFSanFunction; friend class DFSanVisitor; @@ -336,20 +361,16 @@ class DataFlowSanitizer : public ModulePass { Module *Mod; LLVMContext *Ctx; - IntegerType *ShadowTy; - PointerType *ShadowPtrTy; + Type *Int8Ptr; + /// The shadow type for all primitive types and vector types. + IntegerType *PrimitiveShadowTy; + PointerType *PrimitiveShadowPtrTy; IntegerType *IntptrTy; - ConstantInt *ZeroShadow; + ConstantInt *ZeroPrimitiveShadow; ConstantInt *ShadowPtrMask; ConstantInt *ShadowPtrMul; Constant *ArgTLS; Constant *RetvalTLS; - void *(*GetArgTLSPtr)(); - void *(*GetRetvalTLSPtr)(); - FunctionType *GetArgTLSTy; - FunctionType *GetRetvalTLSTy; - Constant *GetArgTLS; - Constant *GetRetvalTLS; Constant *ExternalShadowMask; FunctionType *DFSanUnionFnTy; FunctionType *DFSanUnionLoadFnTy; @@ -357,11 +378,13 @@ class DataFlowSanitizer : public ModulePass { FunctionType *DFSanSetLabelFnTy; FunctionType *DFSanNonzeroLabelFnTy; FunctionType *DFSanVarargWrapperFnTy; - FunctionType *DFSanLoadStoreCmpCallbackFnTy; + FunctionType *DFSanCmpCallbackFnTy; + FunctionType *DFSanLoadStoreCallbackFnTy; FunctionType *DFSanMemTransferCallbackFnTy; FunctionCallee DFSanUnionFn; FunctionCallee DFSanCheckedUnionFn; FunctionCallee DFSanUnionLoadFn; + FunctionCallee DFSanUnionLoadFast16LabelsFn; FunctionCallee DFSanUnimplementedFn; FunctionCallee DFSanSetLabelFn; FunctionCallee DFSanNonzeroLabelFn; @@ -392,15 +415,43 @@ class DataFlowSanitizer : public ModulePass { void initializeCallbackFunctions(Module &M); void initializeRuntimeFunctions(Module &M); -public: - static char ID; + bool init(Module &M); + + /// Returns whether the pass tracks labels for struct fields and array + /// indices. Support only fast16 mode in TLS ABI mode. + bool shouldTrackFieldsAndIndices(); + + /// Returns a zero constant with the shadow type of OrigTy. + /// + /// getZeroShadow({T1,T2,...}) = {getZeroShadow(T1),getZeroShadow(T2,...} + /// getZeroShadow([n x T]) = [n x getZeroShadow(T)] + /// getZeroShadow(other type) = i16(0) + /// + /// Note that a zero shadow is always i16(0) when shouldTrackFieldsAndIndices + /// returns false. + Constant *getZeroShadow(Type *OrigTy); + /// Returns a zero constant with the shadow type of V's type. + Constant *getZeroShadow(Value *V); + + /// Checks if V is a zero shadow. + bool isZeroShadow(Value *V); + + /// Returns the shadow type of OrigTy. + /// + /// getShadowTy({T1,T2,...}) = {getShadowTy(T1),getShadowTy(T2),...} + /// getShadowTy([n x T]) = [n x getShadowTy(T)] + /// getShadowTy(other type) = i16 + /// + /// Note that a shadow type is always i16 when shouldTrackFieldsAndIndices + /// returns false. + Type *getShadowTy(Type *OrigTy); + /// Returns the shadow type of of V's type. + Type *getShadowTy(Value *V); - DataFlowSanitizer( - const std::vector &ABIListFiles = std::vector(), - void *(*getArgTLS)() = nullptr, void *(*getRetValTLS)() = nullptr); +public: + DataFlowSanitizer(const std::vector &ABIListFiles); - bool doInitialization(Module &M) override; - bool runOnModule(Module &M) override; + bool runImpl(Module &M); }; struct DFSanFunction { @@ -409,8 +460,6 @@ struct DFSanFunction { DominatorTree DT; DataFlowSanitizer::InstrumentedABI IA; bool IsNativeABI; - Value *ArgTLSPtr = nullptr; - Value *RetvalTLSPtr = nullptr; AllocaInst *LabelReturnAlloca = nullptr; DenseMap ValShadowMap; DenseMap AllocaShadowMap; @@ -419,12 +468,17 @@ struct DFSanFunction { std::vector NonZeroChecks; bool AvoidNewBlocks; - struct CachedCombinedShadow { - BasicBlock *Block; + struct CachedShadow { + BasicBlock *Block; // The block where Shadow is defined. Value *Shadow; }; - DenseMap, CachedCombinedShadow> - CachedCombinedShadows; + /// Maps a value to its latest shadow value in terms of domination tree. + DenseMap, CachedShadow> CachedShadows; + /// Maps a value to its latest collapsed shadow value it was converted to in + /// terms of domination tree. When ClDebugNonzeroLabels is on, this cache is + /// used at a post process where CFG blocks are split. So it does not cache + /// BasicBlock like CachedShadows, but uses domination between values. + DenseMap CachedCollapsedShadows; DenseMap> ShadowElements; DFSanFunction(DataFlowSanitizer &DFS, Function *F, bool IsNativeABI) @@ -435,17 +489,56 @@ struct DFSanFunction { AvoidNewBlocks = F->size() > 1000; } - Value *getArgTLSPtr(); - Value *getArgTLS(unsigned Index, Instruction *Pos); - Value *getRetvalTLS(); + /// Computes the shadow address for a given function argument. + /// + /// Shadow = ArgTLS+ArgOffset. + Value *getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB); + + /// Computes the shadow address for a retval. + Value *getRetvalTLS(Type *T, IRBuilder<> &IRB); + Value *getShadow(Value *V); void setShadow(Instruction *I, Value *Shadow); + /// Generates IR to compute the union of the two given shadows, inserting it + /// before Pos. The combined value is with primitive type. Value *combineShadows(Value *V1, Value *V2, Instruction *Pos); + /// Combines the shadow values of V1 and V2, then converts the combined value + /// with primitive type into a shadow value with the original type T. + Value *combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos); Value *combineOperandShadows(Instruction *Inst); Value *loadShadow(Value *ShadowAddr, uint64_t Size, uint64_t Align, Instruction *Pos); - void storeShadow(Value *Addr, uint64_t Size, Align Alignment, Value *Shadow, - Instruction *Pos); + void storePrimitiveShadow(Value *Addr, uint64_t Size, Align Alignment, + Value *PrimitiveShadow, Instruction *Pos); + /// Applies PrimitiveShadow to all primitive subtypes of T, returning + /// the expanded shadow value. + /// + /// EFP({T1,T2, ...}, PS) = {EFP(T1,PS),EFP(T2,PS),...} + /// EFP([n x T], PS) = [n x EFP(T,PS)] + /// EFP(other types, PS) = PS + Value *expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, + Instruction *Pos); + /// Collapses Shadow into a single primitive shadow value, unioning all + /// primitive shadow values in the process. Returns the final primitive + /// shadow value. + /// + /// CTP({V1,V2, ...}) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP([V1,V2,...]) = UNION(CFP(V1,PS),CFP(V2,PS),...) + /// CTP(other types, PS) = PS + Value *collapseToPrimitiveShadow(Value *Shadow, Instruction *Pos); + +private: + /// Collapses the shadow with aggregate type into a single primitive shadow + /// value. + template + Value *collapseAggregateShadow(AggregateType *AT, Value *Shadow, + IRBuilder<> &IRB); + + Value *collapseToPrimitiveShadow(Value *Shadow, IRBuilder<> &IRB); + + /// Returns the shadow value of an argument A. + Value *getShadowForTLSArgument(Argument *A); }; class DFSanVisitor : public InstVisitor { @@ -485,25 +578,10 @@ public: } // end anonymous namespace -char DataFlowSanitizer::ID; - -INITIALIZE_PASS(DataFlowSanitizer, "dfsan", - "DataFlowSanitizer: dynamic data flow analysis.", false, false) - -ModulePass * -llvm::createDataFlowSanitizerPass(const std::vector &ABIListFiles, - void *(*getArgTLS)(), - void *(*getRetValTLS)()) { - return new DataFlowSanitizer(ABIListFiles, getArgTLS, getRetValTLS); -} - DataFlowSanitizer::DataFlowSanitizer( - const std::vector &ABIListFiles, void *(*getArgTLS)(), - void *(*getRetValTLS)()) - : ModulePass(ID), GetArgTLSPtr(getArgTLS), GetRetvalTLSPtr(getRetValTLS) { + const std::vector &ABIListFiles) { std::vector AllABIListFiles(std::move(ABIListFiles)); - AllABIListFiles.insert(AllABIListFiles.end(), ClABIListFiles.begin(), - ClABIListFiles.end()); + llvm::append_range(AllABIListFiles, ClABIListFiles); // FIXME: should we propagate vfs::FileSystem to this constructor? ABIList.set( SpecialCaseList::createOrDie(AllABIListFiles, *vfs::getRealFileSystem())); @@ -511,12 +589,12 @@ DataFlowSanitizer::DataFlowSanitizer( FunctionType *DataFlowSanitizer::getArgsFunctionType(FunctionType *T) { SmallVector ArgTypes(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), ShadowTy); + ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); if (T->isVarArg()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - RetType = StructType::get(RetType, ShadowTy); + RetType = StructType::get(RetType, PrimitiveShadowTy); return FunctionType::get(RetType, ArgTypes, T->isVarArg()); } @@ -525,10 +603,10 @@ FunctionType *DataFlowSanitizer::getTrampolineFunctionType(FunctionType *T) { SmallVector ArgTypes; ArgTypes.push_back(T->getPointerTo()); ArgTypes.append(T->param_begin(), T->param_end()); - ArgTypes.append(T->getNumParams(), ShadowTy); + ArgTypes.append(T->getNumParams(), PrimitiveShadowTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); return FunctionType::get(T->getReturnType(), ArgTypes, false); } @@ -554,18 +632,174 @@ TransformedFunction DataFlowSanitizer::getCustomFunctionType(FunctionType *T) { } } for (unsigned i = 0, e = T->getNumParams(); i != e; ++i) - ArgTypes.push_back(ShadowTy); + ArgTypes.push_back(PrimitiveShadowTy); if (T->isVarArg()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); Type *RetType = T->getReturnType(); if (!RetType->isVoidTy()) - ArgTypes.push_back(ShadowPtrTy); + ArgTypes.push_back(PrimitiveShadowPtrTy); return TransformedFunction( T, FunctionType::get(T->getReturnType(), ArgTypes, T->isVarArg()), ArgumentIndexMapping); } -bool DataFlowSanitizer::doInitialization(Module &M) { +bool DataFlowSanitizer::isZeroShadow(Value *V) { + if (!shouldTrackFieldsAndIndices()) + return ZeroPrimitiveShadow == V; + + Type *T = V->getType(); + if (!isa(T) && !isa(T)) { + if (const ConstantInt *CI = dyn_cast(V)) + return CI->isZero(); + return false; + } + + return isa(V); +} + +bool DataFlowSanitizer::shouldTrackFieldsAndIndices() { + return getInstrumentedABI() == DataFlowSanitizer::IA_TLS && ClFast16Labels; +} + +Constant *DataFlowSanitizer::getZeroShadow(Type *OrigTy) { + if (!shouldTrackFieldsAndIndices()) + return ZeroPrimitiveShadow; + + if (!isa(OrigTy) && !isa(OrigTy)) + return ZeroPrimitiveShadow; + Type *ShadowTy = getShadowTy(OrigTy); + return ConstantAggregateZero::get(ShadowTy); +} + +Constant *DataFlowSanitizer::getZeroShadow(Value *V) { + return getZeroShadow(V->getType()); +} + +static Value *expandFromPrimitiveShadowRecursive( + Value *Shadow, SmallVector &Indices, Type *SubShadowTy, + Value *PrimitiveShadow, IRBuilder<> &IRB) { + if (!isa(SubShadowTy) && !isa(SubShadowTy)) + return IRB.CreateInsertValue(Shadow, PrimitiveShadow, Indices); + + if (ArrayType *AT = dyn_cast(SubShadowTy)) { + for (unsigned Idx = 0; Idx < AT->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = expandFromPrimitiveShadowRecursive( + Shadow, Indices, AT->getElementType(), PrimitiveShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + + if (StructType *ST = dyn_cast(SubShadowTy)) { + for (unsigned Idx = 0; Idx < ST->getNumElements(); Idx++) { + Indices.push_back(Idx); + Shadow = expandFromPrimitiveShadowRecursive( + Shadow, Indices, ST->getElementType(Idx), PrimitiveShadow, IRB); + Indices.pop_back(); + } + return Shadow; + } + llvm_unreachable("Unexpected shadow type"); +} + +Value *DFSanFunction::expandFromPrimitiveShadow(Type *T, Value *PrimitiveShadow, + Instruction *Pos) { + Type *ShadowTy = DFS.getShadowTy(T); + + if (!isa(ShadowTy) && !isa(ShadowTy)) + return PrimitiveShadow; + + if (DFS.isZeroShadow(PrimitiveShadow)) + return DFS.getZeroShadow(ShadowTy); + + IRBuilder<> IRB(Pos); + SmallVector Indices; + Value *Shadow = UndefValue::get(ShadowTy); + Shadow = expandFromPrimitiveShadowRecursive(Shadow, Indices, ShadowTy, + PrimitiveShadow, IRB); + + // Caches the primitive shadow value that built the shadow value. + CachedCollapsedShadows[Shadow] = PrimitiveShadow; + return Shadow; +} + +template +Value *DFSanFunction::collapseAggregateShadow(AggregateType *AT, Value *Shadow, + IRBuilder<> &IRB) { + if (!AT->getNumElements()) + return DFS.ZeroPrimitiveShadow; + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = collapseToPrimitiveShadow(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < AT->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = collapseToPrimitiveShadow(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; +} + +Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, + IRBuilder<> &IRB) { + Type *ShadowTy = Shadow->getType(); + if (!isa(ShadowTy) && !isa(ShadowTy)) + return Shadow; + if (ArrayType *AT = dyn_cast(ShadowTy)) + return collapseAggregateShadow<>(AT, Shadow, IRB); + if (StructType *ST = dyn_cast(ShadowTy)) + return collapseAggregateShadow<>(ST, Shadow, IRB); + llvm_unreachable("Unexpected shadow type"); +} + +Value *DFSanFunction::collapseToPrimitiveShadow(Value *Shadow, + Instruction *Pos) { + Type *ShadowTy = Shadow->getType(); + if (!isa(ShadowTy) && !isa(ShadowTy)) + return Shadow; + + assert(DFS.shouldTrackFieldsAndIndices()); + + // Checks if the cached collapsed shadow value dominates Pos. + Value *&CS = CachedCollapsedShadows[Shadow]; + if (CS && DT.dominates(CS, Pos)) + return CS; + + IRBuilder<> IRB(Pos); + Value *PrimitiveShadow = collapseToPrimitiveShadow(Shadow, IRB); + // Caches the converted primitive shadow value. + CS = PrimitiveShadow; + return PrimitiveShadow; +} + +Type *DataFlowSanitizer::getShadowTy(Type *OrigTy) { + if (!shouldTrackFieldsAndIndices()) + return PrimitiveShadowTy; + + if (!OrigTy->isSized()) + return PrimitiveShadowTy; + if (isa(OrigTy)) + return PrimitiveShadowTy; + if (isa(OrigTy)) + return PrimitiveShadowTy; + if (ArrayType *AT = dyn_cast(OrigTy)) + return ArrayType::get(getShadowTy(AT->getElementType()), + AT->getNumElements()); + if (StructType *ST = dyn_cast(OrigTy)) { + SmallVector Elements; + for (unsigned I = 0, N = ST->getNumElements(); I < N; ++I) + Elements.push_back(getShadowTy(ST->getElementType(I))); + return StructType::get(*Ctx, Elements); + } + return PrimitiveShadowTy; +} + +Type *DataFlowSanitizer::getShadowTy(Value *V) { + return getShadowTy(V->getType()); +} + +bool DataFlowSanitizer::init(Module &M) { Triple TargetTriple(M.getTargetTriple()); bool IsX86_64 = TargetTriple.getArch() == Triple::x86_64; bool IsMIPS64 = TargetTriple.isMIPS64(); @@ -576,10 +810,11 @@ bool DataFlowSanitizer::doInitialization(Module &M) { Mod = &M; Ctx = &M.getContext(); - ShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); - ShadowPtrTy = PointerType::getUnqual(ShadowTy); + Int8Ptr = Type::getInt8PtrTy(*Ctx); + PrimitiveShadowTy = IntegerType::get(*Ctx, ShadowWidthBits); + PrimitiveShadowPtrTy = PointerType::getUnqual(PrimitiveShadowTy); IntptrTy = DL.getIntPtrType(*Ctx); - ZeroShadow = ConstantInt::getSigned(ShadowTy, 0); + ZeroPrimitiveShadow = ConstantInt::getSigned(PrimitiveShadowTy, 0); ShadowPtrMul = ConstantInt::getSigned(IntptrTy, ShadowWidthBytes); if (IsX86_64) ShadowPtrMask = ConstantInt::getSigned(IntptrTy, ~0x700000000000LL); @@ -591,44 +826,34 @@ bool DataFlowSanitizer::doInitialization(Module &M) { else report_fatal_error("unsupported triple"); - Type *DFSanUnionArgs[2] = { ShadowTy, ShadowTy }; + Type *DFSanUnionArgs[2] = {PrimitiveShadowTy, PrimitiveShadowTy}; DFSanUnionFnTy = - FunctionType::get(ShadowTy, DFSanUnionArgs, /*isVarArg=*/ false); - Type *DFSanUnionLoadArgs[2] = { ShadowPtrTy, IntptrTy }; - DFSanUnionLoadFnTy = - FunctionType::get(ShadowTy, DFSanUnionLoadArgs, /*isVarArg=*/ false); + FunctionType::get(PrimitiveShadowTy, DFSanUnionArgs, /*isVarArg=*/false); + Type *DFSanUnionLoadArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; + DFSanUnionLoadFnTy = FunctionType::get(PrimitiveShadowTy, DFSanUnionLoadArgs, + /*isVarArg=*/false); DFSanUnimplementedFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - Type *DFSanSetLabelArgs[3] = { ShadowTy, Type::getInt8PtrTy(*Ctx), IntptrTy }; + Type *DFSanSetLabelArgs[3] = {PrimitiveShadowTy, Type::getInt8PtrTy(*Ctx), + IntptrTy}; DFSanSetLabelFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanSetLabelArgs, /*isVarArg=*/false); - DFSanNonzeroLabelFnTy = FunctionType::get( - Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); + DFSanNonzeroLabelFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), None, /*isVarArg=*/false); DFSanVarargWrapperFnTy = FunctionType::get( Type::getVoidTy(*Ctx), Type::getInt8PtrTy(*Ctx), /*isVarArg=*/false); - DFSanLoadStoreCmpCallbackFnTy = - FunctionType::get(Type::getVoidTy(*Ctx), ShadowTy, /*isVarArg=*/false); - Type *DFSanMemTransferCallbackArgs[2] = {ShadowPtrTy, IntptrTy}; + DFSanCmpCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), PrimitiveShadowTy, + /*isVarArg=*/false); + Type *DFSanLoadStoreCallbackArgs[2] = {PrimitiveShadowTy, Int8Ptr}; + DFSanLoadStoreCallbackFnTy = + FunctionType::get(Type::getVoidTy(*Ctx), DFSanLoadStoreCallbackArgs, + /*isVarArg=*/false); + Type *DFSanMemTransferCallbackArgs[2] = {PrimitiveShadowPtrTy, IntptrTy}; DFSanMemTransferCallbackFnTy = FunctionType::get(Type::getVoidTy(*Ctx), DFSanMemTransferCallbackArgs, /*isVarArg=*/false); - if (GetArgTLSPtr) { - Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); - ArgTLS = nullptr; - GetArgTLSTy = FunctionType::get(PointerType::getUnqual(ArgTLSTy), false); - GetArgTLS = ConstantExpr::getIntToPtr( - ConstantInt::get(IntptrTy, uintptr_t(GetArgTLSPtr)), - PointerType::getUnqual(GetArgTLSTy)); - } - if (GetRetvalTLSPtr) { - RetvalTLS = nullptr; - GetRetvalTLSTy = FunctionType::get(PointerType::getUnqual(ShadowTy), false); - GetRetvalTLS = ConstantExpr::getIntToPtr( - ConstantInt::get(IntptrTy, uintptr_t(GetRetvalTLSPtr)), - PointerType::getUnqual(GetRetvalTLSTy)); - } - ColdCallWeights = MDBuilder(*Ctx).createBranchWeights(1, 1000); return true; } @@ -729,14 +954,21 @@ Constant *DataFlowSanitizer::getOrBuildTrampolineFunction(FunctionType *FT, else RI = ReturnInst::Create(*Ctx, CI, BB); + // F is called by a wrapped custom function with primitive shadows. So + // its arguments and return value need conversion. DFSanFunction DFSF(*this, F, /*IsNativeABI=*/true); Function::arg_iterator ValAI = F->arg_begin(), ShadowAI = AI; ++ValAI; - for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) - DFSF.ValShadowMap[&*ValAI] = &*ShadowAI; + for (unsigned N = FT->getNumParams(); N != 0; ++ValAI, ++ShadowAI, --N) { + Value *Shadow = + DFSF.expandFromPrimitiveShadow(ValAI->getType(), &*ShadowAI, CI); + DFSF.ValShadowMap[&*ValAI] = Shadow; + } DFSanVisitor(DFSF).visitCallInst(*CI); - if (!FT->getReturnType()->isVoidTy()) - new StoreInst(DFSF.getShadow(RI->getReturnValue()), - &*std::prev(F->arg_end()), RI); + if (!FT->getReturnType()->isVoidTy()) { + Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow( + DFSF.getShadow(RI->getReturnValue()), RI); + new StoreInst(PrimitiveShadow, &*std::prev(F->arg_end()), RI); + } } return cast(C.getCallee()); @@ -781,6 +1013,17 @@ void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) { DFSanUnionLoadFn = Mod->getOrInsertFunction("__dfsan_union_load", DFSanUnionLoadFnTy, AL); } + { + AttributeList AL; + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::NoUnwind); + AL = AL.addAttribute(M.getContext(), AttributeList::FunctionIndex, + Attribute::ReadOnly); + AL = AL.addAttribute(M.getContext(), AttributeList::ReturnIndex, + Attribute::ZExt); + DFSanUnionLoadFast16LabelsFn = Mod->getOrInsertFunction( + "__dfsan_union_load_fast16labels", DFSanUnionLoadFnTy, AL); + } DFSanUnimplementedFn = Mod->getOrInsertFunction("__dfsan_unimplemented", DFSanUnimplementedFnTy); { @@ -798,16 +1041,18 @@ void DataFlowSanitizer::initializeRuntimeFunctions(Module &M) { // Initializes event callback functions and declare them in the module void DataFlowSanitizer::initializeCallbackFunctions(Module &M) { DFSanLoadCallbackFn = Mod->getOrInsertFunction("__dfsan_load_callback", - DFSanLoadStoreCmpCallbackFnTy); - DFSanStoreCallbackFn = Mod->getOrInsertFunction( - "__dfsan_store_callback", DFSanLoadStoreCmpCallbackFnTy); + DFSanLoadStoreCallbackFnTy); + DFSanStoreCallbackFn = Mod->getOrInsertFunction("__dfsan_store_callback", + DFSanLoadStoreCallbackFnTy); DFSanMemTransferCallbackFn = Mod->getOrInsertFunction( "__dfsan_mem_transfer_callback", DFSanMemTransferCallbackFnTy); - DFSanCmpCallbackFn = Mod->getOrInsertFunction("__dfsan_cmp_callback", - DFSanLoadStoreCmpCallbackFnTy); + DFSanCmpCallbackFn = + Mod->getOrInsertFunction("__dfsan_cmp_callback", DFSanCmpCallbackFnTy); } -bool DataFlowSanitizer::runOnModule(Module &M) { +bool DataFlowSanitizer::runImpl(Module &M) { + init(M); + if (ABIList.isIn(M, "skip")) return false; @@ -816,20 +1061,18 @@ bool DataFlowSanitizer::runOnModule(Module &M) { bool Changed = false; - if (!GetArgTLSPtr) { - Type *ArgTLSTy = ArrayType::get(ShadowTy, 64); - ArgTLS = Mod->getOrInsertGlobal("__dfsan_arg_tls", ArgTLSTy); - if (GlobalVariable *G = dyn_cast(ArgTLS)) { - Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; - G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); - } + Type *ArgTLSTy = ArrayType::get(Type::getInt64Ty(*Ctx), kArgTLSSize / 8); + ArgTLS = Mod->getOrInsertGlobal("__dfsan_arg_tls", ArgTLSTy); + if (GlobalVariable *G = dyn_cast(ArgTLS)) { + Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; + G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); } - if (!GetRetvalTLSPtr) { - RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", ShadowTy); - if (GlobalVariable *G = dyn_cast(RetvalTLS)) { - Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; - G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); - } + Type *RetvalTLSTy = + ArrayType::get(Type::getInt64Ty(*Ctx), kRetvalTLSSize / 8); + RetvalTLS = Mod->getOrInsertGlobal("__dfsan_retval_tls", RetvalTLSTy); + if (GlobalVariable *G = dyn_cast(RetvalTLS)) { + Changed |= G->getThreadLocalMode() != GlobalVariable::InitialExecTLSModel; + G->setThreadLocalMode(GlobalVariable::InitialExecTLSModel); } ExternalShadowMask = @@ -845,6 +1088,7 @@ bool DataFlowSanitizer::runOnModule(Module &M) { &i != DFSanUnionFn.getCallee()->stripPointerCasts() && &i != DFSanCheckedUnionFn.getCallee()->stripPointerCasts() && &i != DFSanUnionLoadFn.getCallee()->stripPointerCasts() && + &i != DFSanUnionLoadFast16LabelsFn.getCallee()->stripPointerCasts() && &i != DFSanUnimplementedFn.getCallee()->stripPointerCasts() && &i != DFSanSetLabelFn.getCallee()->stripPointerCasts() && &i != DFSanNonzeroLabelFn.getCallee()->stripPointerCasts() && @@ -1044,7 +1288,9 @@ bool DataFlowSanitizer::runOnModule(Module &M) { while (isa(Pos) || isa(Pos)) Pos = Pos->getNextNode(); IRBuilder<> IRB(Pos); - Value *Ne = IRB.CreateICmpNE(V, DFSF.DFS.ZeroShadow); + Value *PrimitiveShadow = DFSF.collapseToPrimitiveShadow(V, Pos); + Value *Ne = + IRB.CreateICmpNE(PrimitiveShadow, DFSF.DFS.ZeroPrimitiveShadow); BranchInst *BI = cast(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, ColdCallWeights)); IRBuilder<> ThenIRB(BI); @@ -1057,50 +1303,61 @@ bool DataFlowSanitizer::runOnModule(Module &M) { M.global_size() != InitialGlobalSize || M.size() != InitialModuleSize; } -Value *DFSanFunction::getArgTLSPtr() { - if (ArgTLSPtr) - return ArgTLSPtr; - if (DFS.ArgTLS) - return ArgTLSPtr = DFS.ArgTLS; +Value *DFSanFunction::getArgTLS(Type *T, unsigned ArgOffset, IRBuilder<> &IRB) { + Value *Base = IRB.CreatePointerCast(DFS.ArgTLS, DFS.IntptrTy); + if (ArgOffset) + Base = IRB.CreateAdd(Base, ConstantInt::get(DFS.IntptrTy, ArgOffset)); + return IRB.CreateIntToPtr(Base, PointerType::get(DFS.getShadowTy(T), 0), + "_dfsarg"); +} - IRBuilder<> IRB(&F->getEntryBlock().front()); - return ArgTLSPtr = IRB.CreateCall(DFS.GetArgTLSTy, DFS.GetArgTLS, {}); +Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) { + return IRB.CreatePointerCast( + DFS.RetvalTLS, PointerType::get(DFS.getShadowTy(T), 0), "_dfsret"); } -Value *DFSanFunction::getRetvalTLS() { - if (RetvalTLSPtr) - return RetvalTLSPtr; - if (DFS.RetvalTLS) - return RetvalTLSPtr = DFS.RetvalTLS; +Value *DFSanFunction::getShadowForTLSArgument(Argument *A) { + unsigned ArgOffset = 0; + const DataLayout &DL = F->getParent()->getDataLayout(); + for (auto &FArg : F->args()) { + if (!FArg.getType()->isSized()) { + if (A == &FArg) + break; + continue; + } - IRBuilder<> IRB(&F->getEntryBlock().front()); - return RetvalTLSPtr = - IRB.CreateCall(DFS.GetRetvalTLSTy, DFS.GetRetvalTLS, {}); -} + unsigned Size = DL.getTypeAllocSize(DFS.getShadowTy(&FArg)); + if (A != &FArg) { + ArgOffset += alignTo(Size, kShadowTLSAlignment); + if (ArgOffset > kArgTLSSize) + break; // ArgTLS overflows, uses a zero shadow. + continue; + } -Value *DFSanFunction::getArgTLS(unsigned Idx, Instruction *Pos) { - IRBuilder<> IRB(Pos); - return IRB.CreateConstGEP2_64(ArrayType::get(DFS.ShadowTy, 64), - getArgTLSPtr(), 0, Idx); + if (ArgOffset + Size > kArgTLSSize) + break; // ArgTLS overflows, uses a zero shadow. + + Instruction *ArgTLSPos = &*F->getEntryBlock().begin(); + IRBuilder<> IRB(ArgTLSPos); + Value *ArgShadowPtr = getArgTLS(FArg.getType(), ArgOffset, IRB); + return IRB.CreateAlignedLoad(DFS.getShadowTy(&FArg), ArgShadowPtr, + kShadowTLSAlignment); + } + + return DFS.getZeroShadow(A); } Value *DFSanFunction::getShadow(Value *V) { if (!isa(V) && !isa(V)) - return DFS.ZeroShadow; + return DFS.getZeroShadow(V); Value *&Shadow = ValShadowMap[V]; if (!Shadow) { if (Argument *A = dyn_cast(V)) { if (IsNativeABI) - return DFS.ZeroShadow; + return DFS.getZeroShadow(V); switch (IA) { case DataFlowSanitizer::IA_TLS: { - Value *ArgTLSPtr = getArgTLSPtr(); - Instruction *ArgTLSPos = - DFS.ArgTLS ? &*F->getEntryBlock().begin() - : cast(ArgTLSPtr)->getNextNode(); - IRBuilder<> IRB(ArgTLSPos); - Shadow = - IRB.CreateLoad(DFS.ShadowTy, getArgTLS(A->getArgNo(), ArgTLSPos)); + Shadow = getShadowForTLSArgument(A); break; } case DataFlowSanitizer::IA_Args: { @@ -1109,13 +1366,13 @@ Value *DFSanFunction::getShadow(Value *V) { while (ArgIdx--) ++i; Shadow = &*i; - assert(Shadow->getType() == DFS.ShadowTy); + assert(Shadow->getType() == DFS.PrimitiveShadowTy); break; } } NonZeroChecks.push_back(Shadow); } else { - Shadow = DFS.ZeroShadow; + Shadow = DFS.getZeroShadow(V); } } return Shadow; @@ -1123,7 +1380,8 @@ Value *DFSanFunction::getShadow(Value *V) { void DFSanFunction::setShadow(Instruction *I, Value *Shadow) { assert(!ValShadowMap.count(I)); - assert(Shadow->getType() == DFS.ShadowTy); + assert(DFS.shouldTrackFieldsAndIndices() || + Shadow->getType() == DFS.PrimitiveShadowTy); ValShadowMap[I] = Shadow; } @@ -1140,47 +1398,60 @@ Value *DataFlowSanitizer::getShadowAddress(Value *Addr, Instruction *Pos) { IRB.CreateAnd(IRB.CreatePtrToInt(Addr, IntptrTy), IRB.CreatePtrToInt(ShadowPtrMaskValue, IntptrTy)), ShadowPtrMul), - ShadowPtrTy); + PrimitiveShadowPtrTy); +} + +Value *DFSanFunction::combineShadowsThenConvert(Type *T, Value *V1, Value *V2, + Instruction *Pos) { + Value *PrimitiveValue = combineShadows(V1, V2, Pos); + return expandFromPrimitiveShadow(T, PrimitiveValue, Pos); } // Generates IR to compute the union of the two given shadows, inserting it -// before Pos. Returns the computed union Value. +// before Pos. The combined value is with primitive type. Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { - if (V1 == DFS.ZeroShadow) - return V2; - if (V2 == DFS.ZeroShadow) - return V1; + if (DFS.isZeroShadow(V1)) + return collapseToPrimitiveShadow(V2, Pos); + if (DFS.isZeroShadow(V2)) + return collapseToPrimitiveShadow(V1, Pos); if (V1 == V2) - return V1; + return collapseToPrimitiveShadow(V1, Pos); auto V1Elems = ShadowElements.find(V1); auto V2Elems = ShadowElements.find(V2); if (V1Elems != ShadowElements.end() && V2Elems != ShadowElements.end()) { if (std::includes(V1Elems->second.begin(), V1Elems->second.end(), V2Elems->second.begin(), V2Elems->second.end())) { - return V1; + return collapseToPrimitiveShadow(V1, Pos); } else if (std::includes(V2Elems->second.begin(), V2Elems->second.end(), V1Elems->second.begin(), V1Elems->second.end())) { - return V2; + return collapseToPrimitiveShadow(V2, Pos); } } else if (V1Elems != ShadowElements.end()) { if (V1Elems->second.count(V2)) - return V1; + return collapseToPrimitiveShadow(V1, Pos); } else if (V2Elems != ShadowElements.end()) { if (V2Elems->second.count(V1)) - return V2; + return collapseToPrimitiveShadow(V2, Pos); } auto Key = std::make_pair(V1, V2); if (V1 > V2) std::swap(Key.first, Key.second); - CachedCombinedShadow &CCS = CachedCombinedShadows[Key]; + CachedShadow &CCS = CachedShadows[Key]; if (CCS.Block && DT.dominates(CCS.Block, Pos->getParent())) return CCS.Shadow; + // Converts inputs shadows to shadows with primitive types. + Value *PV1 = collapseToPrimitiveShadow(V1, Pos); + Value *PV2 = collapseToPrimitiveShadow(V2, Pos); + IRBuilder<> IRB(Pos); - if (AvoidNewBlocks) { - CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {V1, V2}); + if (ClFast16Labels) { + CCS.Block = Pos->getParent(); + CCS.Shadow = IRB.CreateOr(PV1, PV2); + } else if (AvoidNewBlocks) { + CallInst *Call = IRB.CreateCall(DFS.DFSanCheckedUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); @@ -1189,19 +1460,20 @@ Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { CCS.Shadow = Call; } else { BasicBlock *Head = Pos->getParent(); - Value *Ne = IRB.CreateICmpNE(V1, V2); + Value *Ne = IRB.CreateICmpNE(PV1, PV2); BranchInst *BI = cast(SplitBlockAndInsertIfThen( Ne, Pos, /*Unreachable=*/false, DFS.ColdCallWeights, &DT)); IRBuilder<> ThenIRB(BI); - CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {V1, V2}); + CallInst *Call = ThenIRB.CreateCall(DFS.DFSanUnionFn, {PV1, PV2}); Call->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); Call->addParamAttr(0, Attribute::ZExt); Call->addParamAttr(1, Attribute::ZExt); BasicBlock *Tail = BI->getSuccessor(0); - PHINode *Phi = PHINode::Create(DFS.ShadowTy, 2, "", &Tail->front()); + PHINode *Phi = + PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); Phi->addIncoming(Call, Call->getParent()); - Phi->addIncoming(V1, Head); + Phi->addIncoming(PV1, Head); CCS.Block = Tail; CCS.Shadow = Phi; @@ -1228,13 +1500,13 @@ Value *DFSanFunction::combineShadows(Value *V1, Value *V2, Instruction *Pos) { // the computed union Value. Value *DFSanFunction::combineOperandShadows(Instruction *Inst) { if (Inst->getNumOperands() == 0) - return DFS.ZeroShadow; + return DFS.getZeroShadow(Inst); Value *Shadow = getShadow(Inst->getOperand(0)); for (unsigned i = 1, n = Inst->getNumOperands(); i != n; ++i) { Shadow = combineShadows(Shadow, getShadow(Inst->getOperand(i)), Inst); } - return Shadow; + return expandFromPrimitiveShadow(Inst->getType(), Shadow, Inst); } Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) { @@ -1244,20 +1516,21 @@ Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) { } // Generates IR to load shadow corresponding to bytes [Addr, Addr+Size), where -// Addr has alignment Align, and take the union of each of those shadows. +// Addr has alignment Align, and take the union of each of those shadows. The +// returned shadow always has primitive type. Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, Instruction *Pos) { if (AllocaInst *AI = dyn_cast(Addr)) { const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - return IRB.CreateLoad(DFS.ShadowTy, i->second); + return IRB.CreateLoad(DFS.PrimitiveShadowTy, i->second); } } const llvm::Align ShadowAlign(Align * DFS.ShadowWidthBytes); SmallVector Objs; - GetUnderlyingObjects(Addr, Objs, Pos->getModule()->getDataLayout()); + getUnderlyingObjects(Addr, Objs); bool AllConstants = true; for (const Value *Obj : Objs) { if (isa(Obj) || isa(Obj)) @@ -1269,26 +1542,51 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, break; } if (AllConstants) - return DFS.ZeroShadow; + return DFS.ZeroPrimitiveShadow; Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); switch (Size) { case 0: - return DFS.ZeroShadow; + return DFS.ZeroPrimitiveShadow; case 1: { - LoadInst *LI = new LoadInst(DFS.ShadowTy, ShadowAddr, "", Pos); + LoadInst *LI = new LoadInst(DFS.PrimitiveShadowTy, ShadowAddr, "", Pos); LI->setAlignment(ShadowAlign); return LI; } case 2: { IRBuilder<> IRB(Pos); - Value *ShadowAddr1 = IRB.CreateGEP(DFS.ShadowTy, ShadowAddr, + Value *ShadowAddr1 = IRB.CreateGEP(DFS.PrimitiveShadowTy, ShadowAddr, ConstantInt::get(DFS.IntptrTy, 1)); return combineShadows( - IRB.CreateAlignedLoad(DFS.ShadowTy, ShadowAddr, ShadowAlign), - IRB.CreateAlignedLoad(DFS.ShadowTy, ShadowAddr1, ShadowAlign), Pos); + IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr, ShadowAlign), + IRB.CreateAlignedLoad(DFS.PrimitiveShadowTy, ShadowAddr1, ShadowAlign), + Pos); } } + + if (ClFast16Labels && Size % (64 / DFS.ShadowWidthBits) == 0) { + // First OR all the WideShadows, then OR individual shadows within the + // combined WideShadow. This is fewer instructions than ORing shadows + // individually. + IRBuilder<> IRB(Pos); + Value *WideAddr = + IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); + Value *CombinedWideShadow = + IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); + for (uint64_t Ofs = 64 / DFS.ShadowWidthBits; Ofs != Size; + Ofs += 64 / DFS.ShadowWidthBits) { + WideAddr = IRB.CreateGEP(Type::getInt64Ty(*DFS.Ctx), WideAddr, + ConstantInt::get(DFS.IntptrTy, 1)); + Value *NextWideShadow = + IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); + CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, NextWideShadow); + } + for (unsigned Width = 32; Width >= DFS.ShadowWidthBits; Width >>= 1) { + Value *ShrShadow = IRB.CreateLShr(CombinedWideShadow, Width); + CombinedWideShadow = IRB.CreateOr(CombinedWideShadow, ShrShadow); + } + return IRB.CreateTrunc(CombinedWideShadow, DFS.PrimitiveShadowTy); + } if (!AvoidNewBlocks && Size % (64 / DFS.ShadowWidthBits) == 0) { // Fast path for the common case where each byte has identical shadow: load // shadow 64 bits at a time, fall out to a __dfsan_union_load call if any @@ -1307,7 +1605,7 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, IRB.CreateBitCast(ShadowAddr, Type::getInt64PtrTy(*DFS.Ctx)); Value *WideShadow = IRB.CreateAlignedLoad(IRB.getInt64Ty(), WideAddr, ShadowAlign); - Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.ShadowTy); + Value *TruncShadow = IRB.CreateTrunc(WideShadow, DFS.PrimitiveShadowTy); Value *ShlShadow = IRB.CreateShl(WideShadow, DFS.ShadowWidthBits); Value *ShrShadow = IRB.CreateLShr(WideShadow, 64 - DFS.ShadowWidthBits); Value *RotShadow = IRB.CreateOr(ShlShadow, ShrShadow); @@ -1348,15 +1646,18 @@ Value *DFSanFunction::loadShadow(Value *Addr, uint64_t Size, uint64_t Align, LastBr->setSuccessor(0, Tail); FallbackIRB.CreateBr(Tail); - PHINode *Shadow = PHINode::Create(DFS.ShadowTy, 2, "", &Tail->front()); + PHINode *Shadow = + PHINode::Create(DFS.PrimitiveShadowTy, 2, "", &Tail->front()); Shadow->addIncoming(FallbackCall, FallbackBB); Shadow->addIncoming(TruncShadow, LastBr->getParent()); return Shadow; } IRBuilder<> IRB(Pos); + FunctionCallee &UnionLoadFn = + ClFast16Labels ? DFS.DFSanUnionLoadFast16LabelsFn : DFS.DFSanUnionLoadFn; CallInst *FallbackCall = IRB.CreateCall( - DFS.DFSanUnionLoadFn, {ShadowAddr, ConstantInt::get(DFS.IntptrTy, Size)}); + UnionLoadFn, {ShadowAddr, ConstantInt::get(DFS.IntptrTy, Size)}); FallbackCall->addAttribute(AttributeList::ReturnIndex, Attribute::ZExt); return FallbackCall; } @@ -1365,34 +1666,39 @@ void DFSanVisitor::visitLoadInst(LoadInst &LI) { auto &DL = LI.getModule()->getDataLayout(); uint64_t Size = DL.getTypeStoreSize(LI.getType()); if (Size == 0) { - DFSF.setShadow(&LI, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&LI, DFSF.DFS.getZeroShadow(&LI)); return; } Align Alignment = ClPreserveAlignment ? LI.getAlign() : Align(1); - Value *Shadow = + Value *PrimitiveShadow = DFSF.loadShadow(LI.getPointerOperand(), Size, Alignment.value(), &LI); if (ClCombinePointerLabelsOnLoad) { Value *PtrShadow = DFSF.getShadow(LI.getPointerOperand()); - Shadow = DFSF.combineShadows(Shadow, PtrShadow, &LI); + PrimitiveShadow = DFSF.combineShadows(PrimitiveShadow, PtrShadow, &LI); } - if (Shadow != DFSF.DFS.ZeroShadow) - DFSF.NonZeroChecks.push_back(Shadow); + if (!DFSF.DFS.isZeroShadow(PrimitiveShadow)) + DFSF.NonZeroChecks.push_back(PrimitiveShadow); + Value *Shadow = + DFSF.expandFromPrimitiveShadow(LI.getType(), PrimitiveShadow, &LI); DFSF.setShadow(&LI, Shadow); if (ClEventCallbacks) { IRBuilder<> IRB(&LI); - IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, Shadow); + Value *Addr8 = IRB.CreateBitCast(LI.getPointerOperand(), DFSF.DFS.Int8Ptr); + IRB.CreateCall(DFSF.DFS.DFSanLoadCallbackFn, {PrimitiveShadow, Addr8}); } } -void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, Align Alignment, - Value *Shadow, Instruction *Pos) { +void DFSanFunction::storePrimitiveShadow(Value *Addr, uint64_t Size, + Align Alignment, + Value *PrimitiveShadow, + Instruction *Pos) { if (AllocaInst *AI = dyn_cast(Addr)) { const auto i = AllocaShadowMap.find(AI); if (i != AllocaShadowMap.end()) { IRBuilder<> IRB(Pos); - IRB.CreateStore(Shadow, i->second); + IRB.CreateStore(PrimitiveShadow, i->second); return; } } @@ -1400,7 +1706,7 @@ void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, Align Alignment, const Align ShadowAlign(Alignment.value() * DFS.ShadowWidthBytes); IRBuilder<> IRB(Pos); Value *ShadowAddr = DFS.getShadowAddress(Addr, Pos); - if (Shadow == DFS.ZeroShadow) { + if (DFS.isZeroShadow(PrimitiveShadow)) { IntegerType *ShadowTy = IntegerType::get(*DFS.Ctx, Size * DFS.ShadowWidthBits); Value *ExtZeroShadow = ConstantInt::get(ShadowTy, 0); @@ -1413,11 +1719,13 @@ void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, Align Alignment, const unsigned ShadowVecSize = 128 / DFS.ShadowWidthBits; uint64_t Offset = 0; if (Size >= ShadowVecSize) { - auto *ShadowVecTy = FixedVectorType::get(DFS.ShadowTy, ShadowVecSize); + auto *ShadowVecTy = + FixedVectorType::get(DFS.PrimitiveShadowTy, ShadowVecSize); Value *ShadowVec = UndefValue::get(ShadowVecTy); for (unsigned i = 0; i != ShadowVecSize; ++i) { ShadowVec = IRB.CreateInsertElement( - ShadowVec, Shadow, ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); + ShadowVec, PrimitiveShadow, + ConstantInt::get(Type::getInt32Ty(*DFS.Ctx), i)); } Value *ShadowVecAddr = IRB.CreateBitCast(ShadowAddr, PointerType::getUnqual(ShadowVecTy)); @@ -1432,8 +1740,8 @@ void DFSanFunction::storeShadow(Value *Addr, uint64_t Size, Align Alignment, } while (Size > 0) { Value *CurShadowAddr = - IRB.CreateConstGEP1_32(DFS.ShadowTy, ShadowAddr, Offset); - IRB.CreateAlignedStore(Shadow, CurShadowAddr, ShadowAlign); + IRB.CreateConstGEP1_32(DFS.PrimitiveShadowTy, ShadowAddr, Offset); + IRB.CreateAlignedStore(PrimitiveShadow, CurShadowAddr, ShadowAlign); --Size; ++Offset; } @@ -1448,14 +1756,19 @@ void DFSanVisitor::visitStoreInst(StoreInst &SI) { const Align Alignment = ClPreserveAlignment ? SI.getAlign() : Align(1); Value* Shadow = DFSF.getShadow(SI.getValueOperand()); + Value *PrimitiveShadow; if (ClCombinePointerLabelsOnStore) { Value *PtrShadow = DFSF.getShadow(SI.getPointerOperand()); - Shadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); + PrimitiveShadow = DFSF.combineShadows(Shadow, PtrShadow, &SI); + } else { + PrimitiveShadow = DFSF.collapseToPrimitiveShadow(Shadow, &SI); } - DFSF.storeShadow(SI.getPointerOperand(), Size, Alignment, Shadow, &SI); + DFSF.storePrimitiveShadow(SI.getPointerOperand(), Size, Alignment, + PrimitiveShadow, &SI); if (ClEventCallbacks) { IRBuilder<> IRB(&SI); - IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, Shadow); + Value *Addr8 = IRB.CreateBitCast(SI.getPointerOperand(), DFSF.DFS.Int8Ptr); + IRB.CreateCall(DFSF.DFS.DFSanStoreCallbackFn, {PrimitiveShadow, Addr8}); } } @@ -1494,11 +1807,29 @@ void DFSanVisitor::visitShuffleVectorInst(ShuffleVectorInst &I) { } void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) { - visitOperandShadowInst(I); + if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *Agg = I.getAggregateOperand(); + Value *AggShadow = DFSF.getShadow(Agg); + Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices()); + DFSF.setShadow(&I, ResShadow); } void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) { - visitOperandShadowInst(I); + if (!DFSF.DFS.shouldTrackFieldsAndIndices()) { + visitOperandShadowInst(I); + return; + } + + IRBuilder<> IRB(&I); + Value *AggShadow = DFSF.getShadow(I.getAggregateOperand()); + Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand()); + Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices()); + DFSF.setShadow(&I, Res); } void DFSanVisitor::visitAllocaInst(AllocaInst &I) { @@ -1517,31 +1848,32 @@ void DFSanVisitor::visitAllocaInst(AllocaInst &I) { } if (AllLoadsStores) { IRBuilder<> IRB(&I); - DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.ShadowTy); + DFSF.AllocaShadowMap[&I] = IRB.CreateAlloca(DFSF.DFS.PrimitiveShadowTy); } - DFSF.setShadow(&I, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&I, DFSF.DFS.ZeroPrimitiveShadow); } void DFSanVisitor::visitSelectInst(SelectInst &I) { Value *CondShadow = DFSF.getShadow(I.getCondition()); Value *TrueShadow = DFSF.getShadow(I.getTrueValue()); Value *FalseShadow = DFSF.getShadow(I.getFalseValue()); + Value *ShadowSel = nullptr; if (isa(I.getCondition()->getType())) { - DFSF.setShadow( - &I, - DFSF.combineShadows( - CondShadow, DFSF.combineShadows(TrueShadow, FalseShadow, &I), &I)); + ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow, + FalseShadow, &I); } else { - Value *ShadowSel; if (TrueShadow == FalseShadow) { ShadowSel = TrueShadow; } else { ShadowSel = SelectInst::Create(I.getCondition(), TrueShadow, FalseShadow, "", &I); } - DFSF.setShadow(&I, DFSF.combineShadows(CondShadow, ShadowSel, &I)); } + DFSF.setShadow(&I, ClTrackSelectControlFlow + ? DFSF.combineShadowsThenConvert( + I.getType(), CondShadow, ShadowSel, &I) + : ShadowSel); } void DFSanVisitor::visitMemSetInst(MemSetInst &I) { @@ -1585,7 +1917,15 @@ void DFSanVisitor::visitReturnInst(ReturnInst &RI) { case DataFlowSanitizer::IA_TLS: { Value *S = DFSF.getShadow(RI.getReturnValue()); IRBuilder<> IRB(&RI); - IRB.CreateStore(S, DFSF.getRetvalTLS()); + Type *RT = DFSF.F->getFunctionType()->getReturnType(); + unsigned Size = + getDataLayout().getTypeAllocSize(DFSF.DFS.getShadowTy(RT)); + if (Size <= kRetvalTLSSize) { + // If the size overflows, stores nothing. At callsite, oversized return + // shadows are set to zero. + IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB), + kShadowTLSAlignment); + } break; } case DataFlowSanitizer::IA_Args: { @@ -1625,11 +1965,11 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { CB.setCalledFunction(F); IRB.CreateCall(DFSF.DFS.DFSanUnimplementedFn, IRB.CreateGlobalStringPtr(F->getName())); - DFSF.setShadow(&CB, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Discard: CB.setCalledFunction(F); - DFSF.setShadow(&CB, DFSF.DFS.ZeroShadow); + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); return; case DataFlowSanitizer::WK_Functional: CB.setCalledFunction(F); @@ -1681,10 +2021,11 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { i = CB.arg_begin(); const unsigned ShadowArgStart = Args.size(); for (unsigned n = FT->getNumParams(); n != 0; ++i, --n) - Args.push_back(DFSF.getShadow(*i)); + Args.push_back( + DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB)); if (FT->isVarArg()) { - auto *LabelVATy = ArrayType::get(DFSF.DFS.ShadowTy, + auto *LabelVATy = ArrayType::get(DFSF.DFS.PrimitiveShadowTy, CB.arg_size() - FT->getNumParams()); auto *LabelVAAlloca = new AllocaInst( LabelVATy, getDataLayout().getAllocaAddrSpace(), @@ -1692,7 +2033,9 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { for (unsigned n = 0; i != CB.arg_end(); ++i, ++n) { auto LabelVAPtr = IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, n); - IRB.CreateStore(DFSF.getShadow(*i), LabelVAPtr); + IRB.CreateStore( + DFSF.collapseToPrimitiveShadow(DFSF.getShadow(*i), &CB), + LabelVAPtr); } Args.push_back(IRB.CreateStructGEP(LabelVATy, LabelVAAlloca, 0)); @@ -1701,9 +2044,9 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (!FT->getReturnType()->isVoidTy()) { if (!DFSF.LabelReturnAlloca) { DFSF.LabelReturnAlloca = - new AllocaInst(DFSF.DFS.ShadowTy, - getDataLayout().getAllocaAddrSpace(), - "labelreturn", &DFSF.F->getEntryBlock().front()); + new AllocaInst(DFSF.DFS.PrimitiveShadowTy, + getDataLayout().getAllocaAddrSpace(), + "labelreturn", &DFSF.F->getEntryBlock().front()); } Args.push_back(DFSF.LabelReturnAlloca); } @@ -1718,17 +2061,19 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { // Update the parameter attributes of the custom call instruction to // zero extend the shadow parameters. This is required for targets - // which consider ShadowTy an illegal type. + // which consider PrimitiveShadowTy an illegal type. for (unsigned n = 0; n < FT->getNumParams(); n++) { const unsigned ArgNo = ShadowArgStart + n; - if (CustomCI->getArgOperand(ArgNo)->getType() == DFSF.DFS.ShadowTy) + if (CustomCI->getArgOperand(ArgNo)->getType() == + DFSF.DFS.PrimitiveShadowTy) CustomCI->addParamAttr(ArgNo, Attribute::ZExt); } if (!FT->getReturnType()->isVoidTy()) { - LoadInst *LabelLoad = - IRB.CreateLoad(DFSF.DFS.ShadowTy, DFSF.LabelReturnAlloca); - DFSF.setShadow(CustomCI, LabelLoad); + LoadInst *LabelLoad = IRB.CreateLoad(DFSF.DFS.PrimitiveShadowTy, + DFSF.LabelReturnAlloca); + DFSF.setShadow(CustomCI, DFSF.expandFromPrimitiveShadow( + FT->getReturnType(), LabelLoad, &CB)); } CI->replaceAllUsesWith(CustomCI); @@ -1741,9 +2086,20 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { FunctionType *FT = CB.getFunctionType(); if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { - for (unsigned i = 0, n = FT->getNumParams(); i != n; ++i) { - IRB.CreateStore(DFSF.getShadow(CB.getArgOperand(i)), - DFSF.getArgTLS(i, &CB)); + unsigned ArgOffset = 0; + const DataLayout &DL = getDataLayout(); + for (unsigned I = 0, N = FT->getNumParams(); I != N; ++I) { + unsigned Size = + DL.getTypeAllocSize(DFSF.DFS.getShadowTy(FT->getParamType(I))); + // Stop storing if arguments' size overflows. Inside a function, arguments + // after overflow have zero shadow values. + if (ArgOffset + Size > kArgTLSSize) + break; + IRB.CreateAlignedStore( + DFSF.getShadow(CB.getArgOperand(I)), + DFSF.getArgTLS(FT->getParamType(I), ArgOffset, IRB), + kShadowTLSAlignment); + ArgOffset += alignTo(Size, kShadowTLSAlignment); } } @@ -1764,10 +2120,19 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (DFSF.DFS.getInstrumentedABI() == DataFlowSanitizer::IA_TLS) { IRBuilder<> NextIRB(Next); - LoadInst *LI = NextIRB.CreateLoad(DFSF.DFS.ShadowTy, DFSF.getRetvalTLS()); - DFSF.SkipInsts.insert(LI); - DFSF.setShadow(&CB, LI); - DFSF.NonZeroChecks.push_back(LI); + const DataLayout &DL = getDataLayout(); + unsigned Size = DL.getTypeAllocSize(DFSF.DFS.getShadowTy(&CB)); + if (Size > kRetvalTLSSize) { + // Set overflowed return shadow to be zero. + DFSF.setShadow(&CB, DFSF.DFS.getZeroShadow(&CB)); + } else { + LoadInst *LI = NextIRB.CreateAlignedLoad( + DFSF.DFS.getShadowTy(&CB), DFSF.getRetvalTLS(CB.getType(), NextIRB), + kShadowTLSAlignment, "_dfsret"); + DFSF.SkipInsts.insert(LI); + DFSF.setShadow(&CB, LI); + DFSF.NonZeroChecks.push_back(LI); + } } } @@ -1789,7 +2154,8 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { if (FT->isVarArg()) { unsigned VarArgSize = CB.arg_size() - FT->getNumParams(); - ArrayType *VarArgArrayTy = ArrayType::get(DFSF.DFS.ShadowTy, VarArgSize); + ArrayType *VarArgArrayTy = + ArrayType::get(DFSF.DFS.PrimitiveShadowTy, VarArgSize); AllocaInst *VarArgShadow = new AllocaInst(VarArgArrayTy, getDataLayout().getAllocaAddrSpace(), "", &DFSF.F->getEntryBlock().front()); @@ -1830,11 +2196,12 @@ void DFSanVisitor::visitCallBase(CallBase &CB) { } void DFSanVisitor::visitPHINode(PHINode &PN) { + Type *ShadowTy = DFSF.DFS.getShadowTy(&PN); PHINode *ShadowPN = - PHINode::Create(DFSF.DFS.ShadowTy, PN.getNumIncomingValues(), "", &PN); + PHINode::Create(ShadowTy, PN.getNumIncomingValues(), "", &PN); // Give the shadow phi node valid predecessors to fool SplitEdge into working. - Value *UndefShadow = UndefValue::get(DFSF.DFS.ShadowTy); + Value *UndefShadow = UndefValue::get(ShadowTy); for (PHINode::block_iterator i = PN.block_begin(), e = PN.block_end(); i != e; ++i) { ShadowPN->addIncoming(UndefShadow, *i); @@ -1843,3 +2210,39 @@ void DFSanVisitor::visitPHINode(PHINode &PN) { DFSF.PHIFixups.push_back(std::make_pair(&PN, ShadowPN)); DFSF.setShadow(&PN, ShadowPN); } + +namespace { +class DataFlowSanitizerLegacyPass : public ModulePass { +private: + std::vector ABIListFiles; + +public: + static char ID; + + DataFlowSanitizerLegacyPass( + const std::vector &ABIListFiles = std::vector()) + : ModulePass(ID), ABIListFiles(ABIListFiles) {} + + bool runOnModule(Module &M) override { + return DataFlowSanitizer(ABIListFiles).runImpl(M); + } +}; +} // namespace + +char DataFlowSanitizerLegacyPass::ID; + +INITIALIZE_PASS(DataFlowSanitizerLegacyPass, "dfsan", + "DataFlowSanitizer: dynamic data flow analysis.", false, false) + +ModulePass *llvm::createDataFlowSanitizerLegacyPassPass( + const std::vector &ABIListFiles) { + return new DataFlowSanitizerLegacyPass(ABIListFiles); +} + +PreservedAnalyses DataFlowSanitizerPass::run(Module &M, + ModuleAnalysisManager &AM) { + if (DataFlowSanitizer(ABIListFiles).runImpl(M)) { + return PreservedAnalyses::none(); + } + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp index d8a965a90127..527644a69d91 100644 --- a/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/GCOVProfiling.cpp @@ -13,13 +13,17 @@ // //===----------------------------------------------------------------------===// +#include "CFGMST.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/Hashing.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Sequence.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringMap.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/CFG.h" @@ -32,6 +36,7 @@ #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" +#include "llvm/Support/CRC.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/FileSystem.h" @@ -52,6 +57,8 @@ namespace endian = llvm::support::endian; #define DEBUG_TYPE "insert-gcov-profiling" enum : uint32_t { + GCOV_ARC_ON_TREE = 1 << 0, + GCOV_TAG_FUNCTION = 0x01000000, GCOV_TAG_BLOCKS = 0x01410000, GCOV_TAG_ARCS = 0x01430000, @@ -62,6 +69,9 @@ static cl::opt DefaultGCOVVersion("default-gcov-version", cl::init("408*"), cl::Hidden, cl::ValueRequired); +static cl::opt AtomicCounter("gcov-atomic-counter", cl::Hidden, + cl::desc("Make counter updates atomic")); + // Returns the number of words which will be used to represent this string. static unsigned wordsOfString(StringRef s) { // Length + NUL-terminated string + 0~3 padding NULs. @@ -73,6 +83,7 @@ GCOVOptions GCOVOptions::getDefault() { Options.EmitNotes = true; Options.EmitData = true; Options.NoRedZone = false; + Options.Atomic = AtomicCounter; if (DefaultGCOVVersion.size() != 4) { llvm::report_fatal_error(std::string("Invalid -default-gcov-version: ") + @@ -90,7 +101,8 @@ public: GCOVProfiler() : GCOVProfiler(GCOVOptions::getDefault()) {} GCOVProfiler(const GCOVOptions &Opts) : Options(Opts) {} bool - runOnModule(Module &M, + runOnModule(Module &M, function_ref GetBFI, + function_ref GetBPI, std::function GetTLI); void write(uint32_t i) { @@ -107,11 +119,14 @@ public: private: // Create the .gcno files for the Module based on DebugInfo. - void emitProfileNotes(); + bool + emitProfileNotes(NamedMDNode *CUNode, bool HasExecOrFork, + function_ref GetBFI, + function_ref GetBPI, + function_ref GetTLI); - // Modify the program to track transitions along edges and call into the - // profiling runtime to emit .gcda files when run. - bool emitProfileArcs(); + void emitGlobalConstructor( + SmallVectorImpl> &CountersBySP); bool isFunctionInstrumented(const Function &F); std::vector createRegexesFromString(StringRef RegexesStr); @@ -130,7 +145,6 @@ private: Function * insertCounterWriteout(ArrayRef>); Function *insertReset(ArrayRef>); - Function *insertFlush(Function *ResetF); bool AddFlushBeforeForkAndExec(); @@ -150,6 +164,7 @@ private: SmallVector, 16> Funcs; std::vector FilterRe; std::vector ExcludeRe; + DenseSet ExecBlocks; StringMap InstrumentedFiles; }; @@ -165,24 +180,68 @@ public: StringRef getPassName() const override { return "GCOV Profiler"; } bool runOnModule(Module &M) override { - return Profiler.runOnModule(M, [this](Function &F) -> TargetLibraryInfo & { - return getAnalysis().getTLI(F); - }); + auto GetBFI = [this](Function &F) { + return &this->getAnalysis(F).getBFI(); + }; + auto GetBPI = [this](Function &F) { + return &this->getAnalysis(F).getBPI(); + }; + auto GetTLI = [this](Function &F) -> const TargetLibraryInfo & { + return this->getAnalysis().getTLI(F); + }; + return Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI); } void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); AU.addRequired(); } private: GCOVProfiler Profiler; }; + +struct BBInfo { + BBInfo *Group; + uint32_t Index; + uint32_t Rank = 0; + + BBInfo(unsigned Index) : Group(this), Index(Index) {} + const std::string infoString() const { + return (Twine("Index=") + Twine(Index)).str(); + } +}; + +struct Edge { + // This class implements the CFG edges. Note the CFG can be a multi-graph. + // So there might be multiple edges with same SrcBB and DestBB. + const BasicBlock *SrcBB; + const BasicBlock *DestBB; + uint64_t Weight; + BasicBlock *Place = nullptr; + uint32_t SrcNumber, DstNumber; + bool InMST = false; + bool Removed = false; + bool IsCritical = false; + + Edge(const BasicBlock *Src, const BasicBlock *Dest, uint64_t W = 1) + : SrcBB(Src), DestBB(Dest), Weight(W) {} + + // Return the information string of an edge. + const std::string infoString() const { + return (Twine(Removed ? "-" : " ") + (InMST ? " " : "*") + + (IsCritical ? "c" : " ") + " W=" + Twine(Weight)) + .str(); + } +}; } char GCOVProfilerLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( GCOVProfilerLegacyPass, "insert-gcov-profiling", "Insert instrumentation for GCOV profiling", false, false) +INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(BranchProbabilityInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( GCOVProfilerLegacyPass, "insert-gcov-profiling", @@ -267,8 +326,8 @@ namespace { return LinesByFile.try_emplace(Filename, P, Filename).first->second; } - void addEdge(GCOVBlock &Successor) { - OutEdges.push_back(&Successor); + void addEdge(GCOVBlock &Successor, uint32_t Flags) { + OutEdges.emplace_back(&Successor, Flags); } void writeOut() { @@ -301,15 +360,16 @@ namespace { assert(OutEdges.empty()); } - private: + uint32_t Number; + SmallVector, 4> OutEdges; + + private: friend class GCOVFunction; GCOVBlock(GCOVProfiler *P, uint32_t Number) : GCOVRecord(P), Number(Number) {} - uint32_t Number; StringMap LinesByFile; - SmallVector OutEdges; }; // A function has a unique identifier, a checksum (we leave as zero) and a @@ -320,16 +380,12 @@ namespace { GCOVFunction(GCOVProfiler *P, Function *F, const DISubprogram *SP, unsigned EndLine, uint32_t Ident, int Version) : GCOVRecord(P), SP(SP), EndLine(EndLine), Ident(Ident), - Version(Version), ReturnBlock(P, 1) { + Version(Version), EntryBlock(P, 0), ReturnBlock(P, 1) { LLVM_DEBUG(dbgs() << "Function: " << getFunctionName(SP) << "\n"); bool ExitBlockBeforeBody = Version >= 48; - uint32_t i = 0; - for (auto &BB : *F) { - // Skip index 1 if it's assigned to the ReturnBlock. - if (i == 1 && ExitBlockBeforeBody) - ++i; + uint32_t i = ExitBlockBeforeBody ? 2 : 1; + for (BasicBlock &BB : *F) Blocks.insert(std::make_pair(&BB, GCOVBlock(P, i++))); - } if (!ExitBlockBeforeBody) ReturnBlock.Number = i; @@ -340,26 +396,15 @@ namespace { FuncChecksum = hash_value(FunctionNameAndLine); } - GCOVBlock &getBlock(BasicBlock *BB) { - return Blocks.find(BB)->second; + GCOVBlock &getBlock(const BasicBlock *BB) { + return Blocks.find(const_cast(BB))->second; } + GCOVBlock &getEntryBlock() { return EntryBlock; } GCOVBlock &getReturnBlock() { return ReturnBlock; } - std::string getEdgeDestinations() { - std::string EdgeDestinations; - raw_string_ostream EDOS(EdgeDestinations); - Function *F = Blocks.begin()->first->getParent(); - for (BasicBlock &I : *F) { - GCOVBlock &Block = getBlock(&I); - for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) - EDOS << Block.OutEdges[i]->Number; - } - return EdgeDestinations; - } - uint32_t getFuncChecksum() const { return FuncChecksum; } @@ -398,44 +443,52 @@ namespace { // Emit count of blocks. write(GCOV_TAG_BLOCKS); if (Version < 80) { - write(Blocks.size() + 1); - for (int i = Blocks.size() + 1; i; --i) + write(Blocks.size() + 2); + for (int i = Blocks.size() + 2; i; --i) write(0); } else { write(1); - write(Blocks.size() + 1); + write(Blocks.size() + 2); } LLVM_DEBUG(dbgs() << (Blocks.size() + 1) << " blocks\n"); // Emit edges between blocks. - Function *F = Blocks.begin()->first->getParent(); - for (BasicBlock &I : *F) { - GCOVBlock &Block = getBlock(&I); + const uint32_t Outgoing = EntryBlock.OutEdges.size(); + if (Outgoing) { + write(GCOV_TAG_ARCS); + write(Outgoing * 2 + 1); + write(EntryBlock.Number); + for (const auto &E : EntryBlock.OutEdges) { + write(E.first->Number); + write(E.second); + } + } + for (auto &It : Blocks) { + const GCOVBlock &Block = It.second; if (Block.OutEdges.empty()) continue; write(GCOV_TAG_ARCS); write(Block.OutEdges.size() * 2 + 1); write(Block.Number); - for (int i = 0, e = Block.OutEdges.size(); i != e; ++i) { - LLVM_DEBUG(dbgs() << Block.Number << " -> " - << Block.OutEdges[i]->Number << "\n"); - write(Block.OutEdges[i]->Number); - write(0); // no flags + for (const auto &E : Block.OutEdges) { + write(E.first->Number); + write(E.second); } } // Emit lines for each block. - for (BasicBlock &I : *F) - getBlock(&I).writeOut(); + for (auto &It : Blocks) + It.second.writeOut(); } - private: + public: const DISubprogram *SP; unsigned EndLine; uint32_t Ident; uint32_t FuncChecksum; int Version; - DenseMap Blocks; + MapVector Blocks; + GCOVBlock EntryBlock; GCOVBlock ReturnBlock; }; } @@ -549,20 +602,23 @@ std::string GCOVProfiler::mangleName(const DICompileUnit *CU, } bool GCOVProfiler::runOnModule( - Module &M, std::function GetTLI) { + Module &M, function_ref GetBFI, + function_ref GetBPI, + std::function GetTLI) { this->M = &M; this->GetTLI = std::move(GetTLI); Ctx = &M.getContext(); - bool Modified = AddFlushBeforeForkAndExec(); + NamedMDNode *CUNode = M.getNamedMetadata("llvm.dbg.cu"); + if (!CUNode || (!Options.EmitNotes && !Options.EmitData)) + return false; + + bool HasExecOrFork = AddFlushBeforeForkAndExec(); FilterRe = createRegexesFromString(Options.Filter); ExcludeRe = createRegexesFromString(Options.Exclude); - - if (Options.EmitNotes) emitProfileNotes(); - if (Options.EmitData) - Modified |= emitProfileArcs(); - return Modified; + emitProfileNotes(CUNode, HasExecOrFork, GetBFI, GetBPI, this->GetTLI); + return true; } PreservedAnalyses GCOVProfilerPass::run(Module &M, @@ -572,9 +628,17 @@ PreservedAnalyses GCOVProfilerPass::run(Module &M, FunctionAnalysisManager &FAM = AM.getResult(M).getManager(); - if (!Profiler.runOnModule(M, [&](Function &F) -> TargetLibraryInfo & { - return FAM.getResult(F); - })) + auto GetBFI = [&FAM](Function &F) { + return &FAM.getResult(F); + }; + auto GetBPI = [&FAM](Function &F) { + return &FAM.getResult(F); + }; + auto GetTLI = [&FAM](Function &F) -> const TargetLibraryInfo & { + return FAM.getResult(F); + }; + + if (!Profiler.runOnModule(M, GetBFI, GetBPI, GetTLI)) return PreservedAnalyses::all(); return PreservedAnalyses::none(); @@ -611,16 +675,6 @@ static bool isUsingScopeBasedEH(Function &F) { return isScopedEHPersonality(Personality); } -static bool shouldKeepInEntry(BasicBlock::iterator It) { - if (isa(*It)) return true; - if (isa(*It)) return true; - if (auto *II = dyn_cast(It)) { - if (II->getIntrinsicID() == llvm::Intrinsic::localescape) return true; - } - - return false; -} - bool GCOVProfiler::AddFlushBeforeForkAndExec() { SmallVector Forks; SmallVector Execs; @@ -690,6 +744,7 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { // dumped FunctionCallee ResetF = M->getOrInsertFunction("llvm_reset_counters", FTy); Builder.CreateCall(ResetF)->setDebugLoc(Loc); + ExecBlocks.insert(Parent); Parent->splitBasicBlock(NextInst); Parent->back().setDebugLoc(Loc); } @@ -697,10 +752,67 @@ bool GCOVProfiler::AddFlushBeforeForkAndExec() { return !Forks.empty() || !Execs.empty(); } -void GCOVProfiler::emitProfileNotes() { - NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); - if (!CU_Nodes) return; +static BasicBlock *getInstrBB(CFGMST &MST, Edge &E, + const DenseSet &ExecBlocks) { + if (E.InMST || E.Removed) + return nullptr; + + BasicBlock *SrcBB = const_cast(E.SrcBB); + BasicBlock *DestBB = const_cast(E.DestBB); + // For a fake edge, instrument the real BB. + if (SrcBB == nullptr) + return DestBB; + if (DestBB == nullptr) + return SrcBB; + + auto CanInstrument = [](BasicBlock *BB) -> BasicBlock * { + // There are basic blocks (such as catchswitch) cannot be instrumented. + // If the returned first insertion point is the end of BB, skip this BB. + if (BB->getFirstInsertionPt() == BB->end()) + return nullptr; + return BB; + }; + + // Instrument the SrcBB if it has a single successor, + // otherwise, the DestBB if this is not a critical edge. + Instruction *TI = SrcBB->getTerminator(); + if (TI->getNumSuccessors() <= 1 && !ExecBlocks.count(SrcBB)) + return CanInstrument(SrcBB); + if (!E.IsCritical) + return CanInstrument(DestBB); + + // Some IndirectBr critical edges cannot be split by the previous + // SplitIndirectBrCriticalEdges call. Bail out. + const unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); + BasicBlock *InstrBB = + isa(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); + if (!InstrBB) + return nullptr; + + MST.addEdge(SrcBB, InstrBB, 0); + MST.addEdge(InstrBB, DestBB, 0).InMST = true; + E.Removed = true; + + return CanInstrument(InstrBB); +} +#ifndef NDEBUG +static void dumpEdges(CFGMST &MST, GCOVFunction &GF) { + size_t ID = 0; + for (auto &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = E.SrcBB ? GF.getBlock(E.SrcBB) : GF.getEntryBlock(); + GCOVBlock &Dst = E.DestBB ? GF.getBlock(E.DestBB) : GF.getReturnBlock(); + dbgs() << " Edge " << ID++ << ": " << Src.Number << "->" << Dst.Number + << E.infoString() << "\n"; + } +} +#endif + +bool GCOVProfiler::emitProfileNotes( + NamedMDNode *CUNode, bool HasExecOrFork, + function_ref GetBFI, + function_ref GetBPI, + function_ref GetTLI) { int Version; { uint8_t c3 = Options.Version[0]; @@ -710,27 +822,20 @@ void GCOVProfiler::emitProfileNotes() { : (c3 - '0') * 10 + c1 - '0'; } - for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { + bool EmitGCDA = Options.EmitData; + for (unsigned i = 0, e = CUNode->getNumOperands(); i != e; ++i) { // Each compile unit gets its own .gcno file. This means that whether we run // this pass over the original .o's as they're produced, or run it after // LTO, we'll generate the same .gcno files. - auto *CU = cast(CU_Nodes->getOperand(i)); + auto *CU = cast(CUNode->getOperand(i)); // Skip module skeleton (and module) CUs. if (CU->getDWOId()) continue; - std::error_code EC; - raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, - sys::fs::OF_None); - if (EC) { - Ctx->emitError(Twine("failed to open coverage notes file for writing: ") + - EC.message()); - continue; - } - - std::string EdgeDestinations; + std::vector EdgeDestinations; + SmallVector, 8> CountersBySP; Endian = M->getDataLayout().isLittleEndian() ? support::endianness::little : support::endianness::big; @@ -744,36 +849,82 @@ void GCOVProfiler::emitProfileNotes() { // TODO: Functions using scope-based EH are currently not supported. if (isUsingScopeBasedEH(F)) continue; - // gcov expects every function to start with an entry block that has a - // single successor, so split the entry block to make sure of that. - BasicBlock &EntryBlock = F.getEntryBlock(); - BasicBlock::iterator It = EntryBlock.begin(); - while (shouldKeepInEntry(It)) - ++It; - EntryBlock.splitBasicBlock(It); + // Add the function line number to the lines of the entry block + // to have a counter for the function definition. + uint32_t Line = SP->getLine(); + auto Filename = getFilename(SP); + + BranchProbabilityInfo *BPI = GetBPI(F); + BlockFrequencyInfo *BFI = GetBFI(F); + // Split indirectbr critical edges here before computing the MST rather + // than later in getInstrBB() to avoid invalidating it. + SplitIndirectBrCriticalEdges(F, BPI, BFI); + + CFGMST MST(F, /*InstrumentFuncEntry_=*/false, BPI, BFI); + + // getInstrBB can split basic blocks and push elements to AllEdges. + for (size_t I : llvm::seq(0, MST.AllEdges.size())) { + auto &E = *MST.AllEdges[I]; + // For now, disable spanning tree optimization when fork or exec* is + // used. + if (HasExecOrFork) + E.InMST = false; + E.Place = getInstrBB(MST, E, ExecBlocks); + } + // Basic blocks in F are finalized at this point. + BasicBlock &EntryBlock = F.getEntryBlock(); Funcs.push_back(std::make_unique(this, &F, SP, EndLine, FunctionIdent++, Version)); GCOVFunction &Func = *Funcs.back(); - // Add the function line number to the lines of the entry block - // to have a counter for the function definition. - uint32_t Line = SP->getLine(); - auto Filename = getFilename(SP); + // Some non-tree edges are IndirectBr which cannot be split. Ignore them + // as well. + llvm::erase_if(MST.AllEdges, [](std::unique_ptr &E) { + return E->Removed || (!E->InMST && !E->Place); + }); + const size_t Measured = + std::stable_partition( + MST.AllEdges.begin(), MST.AllEdges.end(), + [](std::unique_ptr &E) { return E->Place; }) - + MST.AllEdges.begin(); + for (size_t I : llvm::seq(0, Measured)) { + Edge &E = *MST.AllEdges[I]; + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + E.SrcNumber = Src.Number; + E.DstNumber = Dst.Number; + } + std::stable_sort( + MST.AllEdges.begin(), MST.AllEdges.begin() + Measured, + [](const std::unique_ptr &L, const std::unique_ptr &R) { + return L->SrcNumber != R->SrcNumber ? L->SrcNumber < R->SrcNumber + : L->DstNumber < R->DstNumber; + }); + + for (const Edge &E : make_pointee_range(MST.AllEdges)) { + GCOVBlock &Src = + E.SrcBB ? Func.getBlock(E.SrcBB) : Func.getEntryBlock(); + GCOVBlock &Dst = + E.DestBB ? Func.getBlock(E.DestBB) : Func.getReturnBlock(); + Src.addEdge(Dst, E.Place ? 0 : uint32_t(GCOV_ARC_ON_TREE)); + } // Artificial functions such as global initializers if (!SP->isArtificial()) Func.getBlock(&EntryBlock).getFile(Filename).addLine(Line); - for (auto &BB : F) { - GCOVBlock &Block = Func.getBlock(&BB); - Instruction *TI = BB.getTerminator(); - if (int successors = TI->getNumSuccessors()) { - for (int i = 0; i != successors; ++i) { - Block.addEdge(Func.getBlock(TI->getSuccessor(i))); - } - } else if (isa(TI)) { - Block.addEdge(Func.getReturnBlock()); + LLVM_DEBUG(dumpEdges(MST, Func)); + + for (auto &GB : Func.Blocks) { + const BasicBlock &BB = *GB.first; + auto &Block = GB.second; + for (auto Succ : Block.OutEdges) { + uint32_t Idx = Succ.first->Number; + do EdgeDestinations.push_back(Idx & 255); + while ((Idx >>= 8) > 0); } for (auto &I : BB) { @@ -799,149 +950,110 @@ void GCOVProfiler::emitProfileNotes() { } Line = 0; } - EdgeDestinations += Func.getEdgeDestinations(); + if (EmitGCDA) { + DISubprogram *SP = F.getSubprogram(); + ArrayType *CounterTy = ArrayType::get(Type::getInt64Ty(*Ctx), Measured); + GlobalVariable *Counters = new GlobalVariable( + *M, CounterTy, false, GlobalValue::InternalLinkage, + Constant::getNullValue(CounterTy), "__llvm_gcov_ctr"); + CountersBySP.emplace_back(Counters, SP); + + for (size_t I : llvm::seq(0, Measured)) { + const Edge &E = *MST.AllEdges[I]; + IRBuilder<> Builder(E.Place, E.Place->getFirstInsertionPt()); + Value *V = Builder.CreateConstInBoundsGEP2_64( + Counters->getValueType(), Counters, 0, I); + if (Options.Atomic) { + Builder.CreateAtomicRMW(AtomicRMWInst::Add, V, Builder.getInt64(1), + AtomicOrdering::Monotonic); + } else { + Value *Count = + Builder.CreateLoad(Builder.getInt64Ty(), V, "gcov_ctr"); + Count = Builder.CreateAdd(Count, Builder.getInt64(1)); + Builder.CreateStore(Count, V); + } + } + } } char Tmp[4]; - os = &out; - auto Stamp = static_cast(hash_value(EdgeDestinations)); + JamCRC JC; + JC.update(EdgeDestinations); + uint32_t Stamp = JC.getCRC(); FileChecksums.push_back(Stamp); - if (Endian == support::endianness::big) { - out.write("gcno", 4); - out.write(Options.Version, 4); - } else { - out.write("oncg", 4); - std::reverse_copy(Options.Version, Options.Version + 4, Tmp); - out.write(Tmp, 4); - } - write(Stamp); - if (Version >= 90) - writeString(""); // unuseful current_working_directory - if (Version >= 80) - write(0); // unuseful has_unexecuted_blocks - - for (auto &Func : Funcs) - Func->writeOut(Stamp); - - write(0); - write(0); - out.close(); - } -} - -bool GCOVProfiler::emitProfileArcs() { - NamedMDNode *CU_Nodes = M->getNamedMetadata("llvm.dbg.cu"); - if (!CU_Nodes) return false; - bool Result = false; - for (unsigned i = 0, e = CU_Nodes->getNumOperands(); i != e; ++i) { - SmallVector, 8> CountersBySP; - for (auto &F : M->functions()) { - DISubprogram *SP = F.getSubprogram(); - unsigned EndLine; - if (!SP) continue; - if (!functionHasLines(F, EndLine) || !isFunctionInstrumented(F)) + if (Options.EmitNotes) { + std::error_code EC; + raw_fd_ostream out(mangleName(CU, GCovFileType::GCNO), EC, + sys::fs::OF_None); + if (EC) { + Ctx->emitError( + Twine("failed to open coverage notes file for writing: ") + + EC.message()); continue; - // TODO: Functions using scope-based EH are currently not supported. - if (isUsingScopeBasedEH(F)) continue; - - DenseMap, unsigned> EdgeToCounter; - unsigned Edges = 0; - for (auto &BB : F) { - Instruction *TI = BB.getTerminator(); - if (isa(TI)) { - EdgeToCounter[{&BB, nullptr}] = Edges++; - } else { - for (BasicBlock *Succ : successors(TI)) { - EdgeToCounter[{&BB, Succ}] = Edges++; - } - } } + os = &out; + if (Endian == support::endianness::big) { + out.write("gcno", 4); + out.write(Options.Version, 4); + } else { + out.write("oncg", 4); + std::reverse_copy(Options.Version, Options.Version + 4, Tmp); + out.write(Tmp, 4); + } + write(Stamp); + if (Version >= 90) + writeString(""); // unuseful current_working_directory + if (Version >= 80) + write(0); // unuseful has_unexecuted_blocks - ArrayType *CounterTy = - ArrayType::get(Type::getInt64Ty(*Ctx), Edges); - GlobalVariable *Counters = - new GlobalVariable(*M, CounterTy, false, - GlobalValue::InternalLinkage, - Constant::getNullValue(CounterTy), - "__llvm_gcov_ctr"); - CountersBySP.push_back(std::make_pair(Counters, SP)); - - // If a BB has several predecessors, use a PHINode to select - // the correct counter. - for (auto &BB : F) { - const unsigned EdgeCount = - std::distance(pred_begin(&BB), pred_end(&BB)); - if (EdgeCount) { - // The phi node must be at the begin of the BB. - IRBuilder<> BuilderForPhi(&*BB.begin()); - Type *Int64PtrTy = Type::getInt64PtrTy(*Ctx); - PHINode *Phi = BuilderForPhi.CreatePHI(Int64PtrTy, EdgeCount); - for (BasicBlock *Pred : predecessors(&BB)) { - auto It = EdgeToCounter.find({Pred, &BB}); - assert(It != EdgeToCounter.end()); - const unsigned Edge = It->second; - Value *EdgeCounter = BuilderForPhi.CreateConstInBoundsGEP2_64( - Counters->getValueType(), Counters, 0, Edge); - Phi->addIncoming(EdgeCounter, Pred); - } + for (auto &Func : Funcs) + Func->writeOut(Stamp); - // Skip phis, landingpads. - IRBuilder<> Builder(&*BB.getFirstInsertionPt()); - Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Phi); - Count = Builder.CreateAdd(Count, Builder.getInt64(1)); - Builder.CreateStore(Count, Phi); - - Instruction *TI = BB.getTerminator(); - if (isa(TI)) { - auto It = EdgeToCounter.find({&BB, nullptr}); - assert(It != EdgeToCounter.end()); - const unsigned Edge = It->second; - Value *Counter = Builder.CreateConstInBoundsGEP2_64( - Counters->getValueType(), Counters, 0, Edge); - Value *Count = Builder.CreateLoad(Builder.getInt64Ty(), Counter); - Count = Builder.CreateAdd(Count, Builder.getInt64(1)); - Builder.CreateStore(Count, Counter); - } - } - } + write(0); + write(0); + out.close(); } - Function *WriteoutF = insertCounterWriteout(CountersBySP); - Function *ResetF = insertReset(CountersBySP); - Function *FlushF = insertFlush(ResetF); - - // Create a small bit of code that registers the "__llvm_gcov_writeout" to - // be executed at exit and the "__llvm_gcov_flush" function to be executed - // when "__gcov_flush" is called. - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, - "__llvm_gcov_init", M); - F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - F->setLinkage(GlobalValue::InternalLinkage); - F->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - F->addFnAttr(Attribute::NoRedZone); - - BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); - IRBuilder<> Builder(BB); - - FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Type *Params[] = {PointerType::get(FTy, 0), PointerType::get(FTy, 0), - PointerType::get(FTy, 0)}; - FTy = FunctionType::get(Builder.getVoidTy(), Params, false); - - // Initialize the environment and register the local writeout, flush and - // reset functions. - FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); - Builder.CreateCall(GCOVInit, {WriteoutF, FlushF, ResetF}); - Builder.CreateRetVoid(); - - appendToGlobalCtors(*M, F, 0); - Result = true; + if (EmitGCDA) { + emitGlobalConstructor(CountersBySP); + EmitGCDA = false; + } } + return true; +} + +void GCOVProfiler::emitGlobalConstructor( + SmallVectorImpl> &CountersBySP) { + Function *WriteoutF = insertCounterWriteout(CountersBySP); + Function *ResetF = insertReset(CountersBySP); + + // Create a small bit of code that registers the "__llvm_gcov_writeout" to + // be executed at exit and the "__llvm_gcov_flush" function to be executed + // when "__gcov_flush" is called. + FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + Function *F = Function::Create(FTy, GlobalValue::InternalLinkage, + "__llvm_gcov_init", M); + F->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); + F->setLinkage(GlobalValue::InternalLinkage); + F->addFnAttr(Attribute::NoInline); + if (Options.NoRedZone) + F->addFnAttr(Attribute::NoRedZone); - return Result; + BasicBlock *BB = BasicBlock::Create(*Ctx, "entry", F); + IRBuilder<> Builder(BB); + + FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); + auto *PFTy = PointerType::get(FTy, 0); + FTy = FunctionType::get(Builder.getVoidTy(), {PFTy, PFTy}, false); + + // Initialize the environment and register the local writeout, flush and + // reset functions. + FunctionCallee GCOVInit = M->getOrInsertFunction("llvm_gcov_init", FTy); + Builder.CreateCall(GCOVInit, {WriteoutF, ResetF}); + Builder.CreateRetVoid(); + + appendToGlobalCtors(*M, F, 0); } FunctionCallee GCOVProfiler::getStartFileFunc(const TargetLibraryInfo *TLI) { @@ -1028,15 +1140,19 @@ Function *GCOVProfiler::insertCounterWriteout( // Collect the relevant data into a large constant data structure that we can // walk to write out everything. StructType *StartFileCallArgsTy = StructType::create( - {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}); + {Builder.getInt8PtrTy(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "start_file_args_ty"); StructType *EmitFunctionCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}); + {Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()}, + "emit_function_args_ty"); StructType *EmitArcsCallArgsTy = StructType::create( - {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}); + {Builder.getInt32Ty(), Builder.getInt64Ty()->getPointerTo()}, + "emit_arcs_args_ty"); StructType *FileInfoTy = StructType::create({StartFileCallArgsTy, Builder.getInt32Ty(), EmitFunctionCallArgsTy->getPointerTo(), - EmitArcsCallArgsTy->getPointerTo()}); + EmitArcsCallArgsTy->getPointerTo()}, + "file_info"); Constant *Zero32 = Builder.getInt32(0); // Build an explicit array of two zeros for use in ConstantExpr GEP building. @@ -1146,41 +1262,46 @@ Function *GCOVProfiler::insertCounterWriteout( // The index into the files structure is our loop induction variable. Builder.SetInsertPoint(FileLoopHeader); - PHINode *IV = - Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); + PHINode *IV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "file_idx"); IV->addIncoming(Builder.getInt32(0), BB); auto *FileInfoPtr = Builder.CreateInBoundsGEP( FileInfoArrayTy, FileInfoArrayGV, {Builder.getInt32(0), IV}); auto *StartFileCallArgsPtr = - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 0, "start_file_args"); auto *StartFileCall = Builder.CreateCall( StartFile, {Builder.CreateLoad(StartFileCallArgsTy->getElementType(0), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 0)), + StartFileCallArgsPtr, 0), + "filename"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(1), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 1)), + StartFileCallArgsPtr, 1), + "version"), Builder.CreateLoad(StartFileCallArgsTy->getElementType(2), Builder.CreateStructGEP(StartFileCallArgsTy, - StartFileCallArgsPtr, 2))}); + StartFileCallArgsPtr, 2), + "stamp")}); if (auto AK = TLI->getExtAttrForI32Param(false)) StartFileCall->addParamAttr(2, AK); - auto *NumCounters = - Builder.CreateLoad(FileInfoTy->getElementType(1), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1)); + auto *NumCounters = Builder.CreateLoad( + FileInfoTy->getElementType(1), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 1), "num_ctrs"); auto *EmitFunctionCallArgsArray = Builder.CreateLoad(FileInfoTy->getElementType(2), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2)); - auto *EmitArcsCallArgsArray = - Builder.CreateLoad(FileInfoTy->getElementType(3), - Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3)); + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 2), + "emit_function_args"); + auto *EmitArcsCallArgsArray = Builder.CreateLoad( + FileInfoTy->getElementType(3), + Builder.CreateStructGEP(FileInfoTy, FileInfoPtr, 3), "emit_arcs_args"); auto *EnterCounterLoopCond = Builder.CreateICmpSLT(Builder.getInt32(0), NumCounters); Builder.CreateCondBr(EnterCounterLoopCond, CounterLoopHeader, FileLoopLatch); Builder.SetInsertPoint(CounterLoopHeader); - auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2); + auto *JV = Builder.CreatePHI(Builder.getInt32Ty(), /*NumReservedValues*/ 2, + "ctr_idx"); JV->addIncoming(Builder.getInt32(0), FileLoopHeader); auto *EmitFunctionCallArgsPtr = Builder.CreateInBoundsGEP( EmitFunctionCallArgsTy, EmitFunctionCallArgsArray, JV); @@ -1188,14 +1309,16 @@ Function *GCOVProfiler::insertCounterWriteout( EmitFunction, {Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(0), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 0)), + EmitFunctionCallArgsPtr, 0), + "ident"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(1), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, 1)), + EmitFunctionCallArgsPtr, 1), + "func_checkssum"), Builder.CreateLoad(EmitFunctionCallArgsTy->getElementType(2), Builder.CreateStructGEP(EmitFunctionCallArgsTy, - EmitFunctionCallArgsPtr, - 2))}); + EmitFunctionCallArgsPtr, 2), + "cfg_checksum")}); if (auto AK = TLI->getExtAttrForI32Param(false)) { EmitFunctionCall->addParamAttr(0, AK); EmitFunctionCall->addParamAttr(1, AK); @@ -1207,10 +1330,12 @@ Function *GCOVProfiler::insertCounterWriteout( EmitArcs, {Builder.CreateLoad( EmitArcsCallArgsTy->getElementType(0), - Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0)), - Builder.CreateLoad(EmitArcsCallArgsTy->getElementType(1), - Builder.CreateStructGEP(EmitArcsCallArgsTy, - EmitArcsCallArgsPtr, 1))}); + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 0), + "num_counters"), + Builder.CreateLoad( + EmitArcsCallArgsTy->getElementType(1), + Builder.CreateStructGEP(EmitArcsCallArgsTy, EmitArcsCallArgsPtr, 1), + "counters")}); if (auto AK = TLI->getExtAttrForI32Param(false)) EmitArcsCall->addParamAttr(0, AK); auto *NextJV = Builder.CreateAdd(JV, Builder.getInt32(1)); @@ -1221,7 +1346,7 @@ Function *GCOVProfiler::insertCounterWriteout( Builder.SetInsertPoint(FileLoopLatch); Builder.CreateCall(SummaryInfo, {}); Builder.CreateCall(EndFile, {}); - auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1)); + auto *NextIV = Builder.CreateAdd(IV, Builder.getInt32(1), "next_file_idx"); auto *FileLoopCond = Builder.CreateICmpSLT(NextIV, Builder.getInt32(FileInfos.size())); Builder.CreateCondBr(FileLoopCond, FileLoopHeader, ExitBB); @@ -1266,36 +1391,3 @@ Function *GCOVProfiler::insertReset( return ResetF; } - -Function *GCOVProfiler::insertFlush(Function *ResetF) { - FunctionType *FTy = FunctionType::get(Type::getVoidTy(*Ctx), false); - Function *FlushF = M->getFunction("__llvm_gcov_flush"); - if (!FlushF) - FlushF = Function::Create(FTy, GlobalValue::InternalLinkage, - "__llvm_gcov_flush", M); - FlushF->setUnnamedAddr(GlobalValue::UnnamedAddr::Global); - FlushF->addFnAttr(Attribute::NoInline); - if (Options.NoRedZone) - FlushF->addFnAttr(Attribute::NoRedZone); - - BasicBlock *Entry = BasicBlock::Create(*Ctx, "entry", FlushF); - - // Write out the current counters. - Function *WriteoutF = M->getFunction("__llvm_gcov_writeout"); - assert(WriteoutF && "Need to create the writeout function first!"); - - IRBuilder<> Builder(Entry); - Builder.CreateCall(WriteoutF, {}); - Builder.CreateCall(ResetF, {}); - - Type *RetTy = FlushF->getReturnType(); - if (RetTy->isVoidTy()) - Builder.CreateRetVoid(); - else if (RetTy->isIntegerTy()) - // Used if __llvm_gcov_flush was implicitly declared. - Builder.CreateRet(ConstantInt::get(RetTy, 0)); - else - report_fatal_error("invalid return type for __llvm_gcov_flush"); - - return FlushF; -} diff --git a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp index 2e71d613714a..fedd9bfc977e 100644 --- a/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp @@ -55,13 +55,12 @@ using namespace llvm; #define DEBUG_TYPE "hwasan" -static const char *const kHwasanModuleCtorName = "hwasan.module_ctor"; -static const char *const kHwasanNoteName = "hwasan.note"; -static const char *const kHwasanInitName = "__hwasan_init"; -static const char *const kHwasanPersonalityThunkName = - "__hwasan_personality_thunk"; +const char kHwasanModuleCtorName[] = "hwasan.module_ctor"; +const char kHwasanNoteName[] = "hwasan.note"; +const char kHwasanInitName[] = "__hwasan_init"; +const char kHwasanPersonalityThunkName[] = "__hwasan_personality_thunk"; -static const char *const kHwasanShadowMemoryDynamicAddress = +const char kHwasanShadowMemoryDynamicAddress[] = "__hwasan_shadow_memory_dynamic_address"; // Accesses sizes are powers of two: 1, 2, 4, 8, 16. @@ -203,14 +202,16 @@ public: bool sanitizeFunction(Function &F); void initializeModule(); + void createHwasanCtorComdat(); void initializeCallbacks(Module &M); + Value *getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val); + Value *getDynamicShadowIfunc(IRBuilder<> &IRB); - Value *getDynamicShadowNonTls(IRBuilder<> &IRB); + Value *getShadowNonTls(IRBuilder<> &IRB); void untagPointerOperand(Instruction *I, Value *Addr); - Value *shadowBase(); Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); void instrumentMemAccessInline(Value *Ptr, bool IsWrite, unsigned AccessSizeIndex, @@ -280,9 +281,13 @@ private: bool CompileKernel; bool Recover; + bool OutlinedChecks; bool UseShortGranules; bool InstrumentLandingPads; + bool HasMatchAllTag = false; + uint8_t MatchAllTag = 0; + Function *HwasanCtorFunction; FunctionCallee HwasanMemoryAccessCallback[2][kNumberOfAccessSizes]; @@ -293,7 +298,7 @@ private: Constant *ShadowGlobal; - Value *LocalDynamicShadow = nullptr; + Value *ShadowBase = nullptr; Value *StackBaseTag = nullptr; GlobalValue *ThreadPtrGlobal = nullptr; }; @@ -365,6 +370,106 @@ PreservedAnalyses HWAddressSanitizerPass::run(Module &M, return PreservedAnalyses::all(); } +void HWAddressSanitizer::createHwasanCtorComdat() { + std::tie(HwasanCtorFunction, std::ignore) = + getOrCreateSanitizerCtorAndInitFunctions( + M, kHwasanModuleCtorName, kHwasanInitName, + /*InitArgTypes=*/{}, + /*InitArgs=*/{}, + // This callback is invoked when the functions are created the first + // time. Hook them into the global ctors list in that case: + [&](Function *Ctor, FunctionCallee) { + Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + Ctor->setComdat(CtorComdat); + appendToGlobalCtors(M, Ctor, 0, Ctor); + }); + + // Create a note that contains pointers to the list of global + // descriptors. Adding a note to the output file will cause the linker to + // create a PT_NOTE program header pointing to the note that we can use to + // find the descriptor list starting from the program headers. A function + // provided by the runtime initializes the shadow memory for the globals by + // accessing the descriptor list via the note. The dynamic loader needs to + // call this function whenever a library is loaded. + // + // The reason why we use a note for this instead of a more conventional + // approach of having a global constructor pass a descriptor list pointer to + // the runtime is because of an order of initialization problem. With + // constructors we can encounter the following problematic scenario: + // + // 1) library A depends on library B and also interposes one of B's symbols + // 2) B's constructors are called before A's (as required for correctness) + // 3) during construction, B accesses one of its "own" globals (actually + // interposed by A) and triggers a HWASAN failure due to the initialization + // for A not having happened yet + // + // Even without interposition it is possible to run into similar situations in + // cases where two libraries mutually depend on each other. + // + // We only need one note per binary, so put everything for the note in a + // comdat. This needs to be a comdat with an .init_array section to prevent + // newer versions of lld from discarding the note. + // + // Create the note even if we aren't instrumenting globals. This ensures that + // binaries linked from object files with both instrumented and + // non-instrumented globals will end up with a note, even if a comdat from an + // object file with non-instrumented globals is selected. The note is harmless + // if the runtime doesn't support it, since it will just be ignored. + Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName); + + Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); + auto Start = + new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, + nullptr, "__start_hwasan_globals"); + Start->setVisibility(GlobalValue::HiddenVisibility); + Start->setDSOLocal(true); + auto Stop = + new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, + nullptr, "__stop_hwasan_globals"); + Stop->setVisibility(GlobalValue::HiddenVisibility); + Stop->setDSOLocal(true); + + // Null-terminated so actually 8 bytes, which are required in order to align + // the note properly. + auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0"); + + auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(), + Int32Ty, Int32Ty); + auto *Note = + new GlobalVariable(M, NoteTy, /*isConstant=*/true, + GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName); + Note->setSection(".note.hwasan.globals"); + Note->setComdat(NoteComdat); + Note->setAlignment(Align(4)); + Note->setDSOLocal(true); + + // The pointers in the note need to be relative so that the note ends up being + // placed in rodata, which is the standard location for notes. + auto CreateRelPtr = [&](Constant *Ptr) { + return ConstantExpr::getTrunc( + ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty), + ConstantExpr::getPtrToInt(Note, Int64Ty)), + Int32Ty); + }; + Note->setInitializer(ConstantStruct::getAnon( + {ConstantInt::get(Int32Ty, 8), // n_namesz + ConstantInt::get(Int32Ty, 8), // n_descsz + ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type + Name, CreateRelPtr(Start), CreateRelPtr(Stop)})); + appendToCompilerUsed(M, Note); + + // Create a zero-length global in hwasan_globals so that the linker will + // always create start and stop symbols. + auto Dummy = new GlobalVariable( + M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage, + Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global"); + Dummy->setSection("hwasan_globals"); + Dummy->setComdat(NoteComdat); + Dummy->setMetadata(LLVMContext::MD_associated, + MDNode::get(*C, ValueAsMetadata::get(Note))); + appendToCompilerUsed(M, Dummy); +} + /// Module-level initialization. /// /// inserts a call to __hwasan_init to the module's constructor list. @@ -393,6 +498,19 @@ void HWAddressSanitizer::initializeModule() { UseShortGranules = ClUseShortGranules.getNumOccurrences() ? ClUseShortGranules : NewRuntime; + OutlinedChecks = + TargetTriple.isAArch64() && TargetTriple.isOSBinFormatELF() && + (ClInlineAllChecks.getNumOccurrences() ? !ClInlineAllChecks : !Recover); + + if (ClMatchAllTag.getNumOccurrences()) { + if (ClMatchAllTag != -1) { + HasMatchAllTag = true; + MatchAllTag = ClMatchAllTag & 0xFF; + } + } else if (CompileKernel) { + HasMatchAllTag = true; + MatchAllTag = 0xFF; + } // If we don't have personality function support, fall back to landing pads. InstrumentLandingPads = ClInstrumentLandingPads.getNumOccurrences() @@ -400,19 +518,7 @@ void HWAddressSanitizer::initializeModule() { : !NewRuntime; if (!CompileKernel) { - std::tie(HwasanCtorFunction, std::ignore) = - getOrCreateSanitizerCtorAndInitFunctions( - M, kHwasanModuleCtorName, kHwasanInitName, - /*InitArgTypes=*/{}, - /*InitArgs=*/{}, - // This callback is invoked when the functions are created the first - // time. Hook them into the global ctors list in that case: - [&](Function *Ctor, FunctionCallee) { - Comdat *CtorComdat = M.getOrInsertComdat(kHwasanModuleCtorName); - Ctor->setComdat(CtorComdat); - appendToGlobalCtors(M, Ctor, 0, Ctor); - }); - + createHwasanCtorComdat(); bool InstrumentGlobals = ClGlobals.getNumOccurrences() ? ClGlobals : NewRuntime; if (InstrumentGlobals) @@ -483,20 +589,27 @@ void HWAddressSanitizer::initializeCallbacks(Module &M) { M.getOrInsertFunction("__hwasan_handle_vfork", IRB.getVoidTy(), IntptrTy); } -Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { +Value *HWAddressSanitizer::getOpaqueNoopCast(IRBuilder<> &IRB, Value *Val) { // An empty inline asm with input reg == output reg. // An opaque no-op cast, basically. - InlineAsm *Asm = InlineAsm::get( - FunctionType::get(Int8PtrTy, {ShadowGlobal->getType()}, false), - StringRef(""), StringRef("=r,0"), - /*hasSideEffects=*/false); - return IRB.CreateCall(Asm, {ShadowGlobal}, ".hwasan.shadow"); + // This prevents code bloat as a result of rematerializing trivial definitions + // such as constants or global addresses at every load and store. + InlineAsm *Asm = + InlineAsm::get(FunctionType::get(Int8PtrTy, {Val->getType()}, false), + StringRef(""), StringRef("=r,0"), + /*hasSideEffects=*/false); + return IRB.CreateCall(Asm, {Val}, ".hwasan.shadow"); +} + +Value *HWAddressSanitizer::getDynamicShadowIfunc(IRBuilder<> &IRB) { + return getOpaqueNoopCast(IRB, ShadowGlobal); } -Value *HWAddressSanitizer::getDynamicShadowNonTls(IRBuilder<> &IRB) { - // Generate code only when dynamic addressing is needed. +Value *HWAddressSanitizer::getShadowNonTls(IRBuilder<> &IRB) { if (Mapping.Offset != kDynamicShadowSentinel) - return nullptr; + return getOpaqueNoopCast( + IRB, ConstantExpr::getIntToPtr( + ConstantInt::get(IntptrTy, Mapping.Offset), Int8PtrTy)); if (Mapping.InGlobal) { return getDynamicShadowIfunc(IRB); @@ -532,7 +645,7 @@ void HWAddressSanitizer::getInterestingMemoryOperands( return; // Do not instrument the load fetching the dynamic shadow address. - if (LocalDynamicShadow == I) + if (ShadowBase == I) return; if (LoadInst *LI = dyn_cast(I)) { @@ -596,37 +709,35 @@ void HWAddressSanitizer::untagPointerOperand(Instruction *I, Value *Addr) { I->setOperand(getPointerOperandIndex(I), UntaggedPtr); } -Value *HWAddressSanitizer::shadowBase() { - if (LocalDynamicShadow) - return LocalDynamicShadow; - return ConstantExpr::getIntToPtr(ConstantInt::get(IntptrTy, Mapping.Offset), - Int8PtrTy); -} - Value *HWAddressSanitizer::memToShadow(Value *Mem, IRBuilder<> &IRB) { // Mem >> Scale Value *Shadow = IRB.CreateLShr(Mem, Mapping.Scale); if (Mapping.Offset == 0) return IRB.CreateIntToPtr(Shadow, Int8PtrTy); // (Mem >> Scale) + Offset - return IRB.CreateGEP(Int8Ty, shadowBase(), Shadow); + return IRB.CreateGEP(Int8Ty, ShadowBase, Shadow); } void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, unsigned AccessSizeIndex, Instruction *InsertBefore) { - const int64_t AccessInfo = Recover * 0x20 + IsWrite * 0x10 + AccessSizeIndex; + const int64_t AccessInfo = + (CompileKernel << HWASanAccessInfo::CompileKernelShift) + + (HasMatchAllTag << HWASanAccessInfo::HasMatchAllShift) + + (MatchAllTag << HWASanAccessInfo::MatchAllShift) + + (Recover << HWASanAccessInfo::RecoverShift) + + (IsWrite << HWASanAccessInfo::IsWriteShift) + + (AccessSizeIndex << HWASanAccessInfo::AccessSizeShift); IRBuilder<> IRB(InsertBefore); - if (!ClInlineAllChecks && TargetTriple.isAArch64() && - TargetTriple.isOSBinFormatELF() && !Recover) { + if (OutlinedChecks) { Module *M = IRB.GetInsertBlock()->getParent()->getParent(); Ptr = IRB.CreateBitCast(Ptr, Int8PtrTy); IRB.CreateCall(Intrinsic::getDeclaration( M, UseShortGranules ? Intrinsic::hwasan_check_memaccess_shortgranules : Intrinsic::hwasan_check_memaccess), - {shadowBase(), Ptr, ConstantInt::get(Int32Ty, AccessInfo)}); + {ShadowBase, Ptr, ConstantInt::get(Int32Ty, AccessInfo)}); return; } @@ -638,11 +749,9 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *MemTag = IRB.CreateLoad(Int8Ty, Shadow); Value *TagMismatch = IRB.CreateICmpNE(PtrTag, MemTag); - int matchAllTag = ClMatchAllTag.getNumOccurrences() > 0 ? - ClMatchAllTag : (CompileKernel ? 0xFF : -1); - if (matchAllTag != -1) { - Value *TagNotIgnored = IRB.CreateICmpNE(PtrTag, - ConstantInt::get(PtrTag->getType(), matchAllTag)); + if (HasMatchAllTag) { + Value *TagNotIgnored = IRB.CreateICmpNE( + PtrTag, ConstantInt::get(PtrTag->getType(), MatchAllTag)); TagMismatch = IRB.CreateAnd(TagMismatch, TagNotIgnored); } @@ -664,7 +773,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *PtrLowBitsOOB = IRB.CreateICmpUGE(PtrLowBits, MemTag); SplitBlockAndInsertIfThen(PtrLowBitsOOB, CheckTerm, false, MDBuilder(*C).createBranchWeights(1, 100000), - nullptr, nullptr, CheckFailTerm->getParent()); + (DomTreeUpdater *)nullptr, nullptr, + CheckFailTerm->getParent()); IRB.SetInsertPoint(CheckTerm); Value *InlineTagAddr = IRB.CreateOr(AddrLong, 15); @@ -673,7 +783,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, Value *InlineTagMismatch = IRB.CreateICmpNE(PtrTag, InlineTag); SplitBlockAndInsertIfThen(InlineTagMismatch, CheckTerm, false, MDBuilder(*C).createBranchWeights(1, 100000), - nullptr, nullptr, CheckFailTerm->getParent()); + (DomTreeUpdater *)nullptr, nullptr, + CheckFailTerm->getParent()); IRB.SetInsertPoint(CheckFailTerm); InlineAsm *Asm; @@ -682,7 +793,9 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, // The signal handler will find the data address in rdi. Asm = InlineAsm::get( FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), - "int3\nnopl " + itostr(0x40 + AccessInfo) + "(%rax)", + "int3\nnopl " + + itostr(0x40 + (AccessInfo & HWASanAccessInfo::RuntimeMask)) + + "(%rax)", "{rdi}", /*hasSideEffects=*/true); break; @@ -691,7 +804,8 @@ void HWAddressSanitizer::instrumentMemAccessInline(Value *Ptr, bool IsWrite, // The signal handler will find the data address in x0. Asm = InlineAsm::get( FunctionType::get(IRB.getVoidTy(), {PtrLong->getType()}, false), - "brk #" + itostr(0x900 + AccessInfo), + "brk #" + + itostr(0x900 + (AccessInfo & HWASanAccessInfo::RuntimeMask)), "{x0}", /*hasSideEffects=*/true); break; @@ -914,12 +1028,12 @@ Value *HWAddressSanitizer::getHwasanThreadSlotPtr(IRBuilder<> &IRB, Type *Ty) { void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { if (!Mapping.InTls) { - LocalDynamicShadow = getDynamicShadowNonTls(IRB); + ShadowBase = getShadowNonTls(IRB); return; } if (!WithFrameRecord && TargetTriple.isAndroid()) { - LocalDynamicShadow = getDynamicShadowIfunc(IRB); + ShadowBase = getDynamicShadowIfunc(IRB); return; } @@ -980,12 +1094,12 @@ void HWAddressSanitizer::emitPrologue(IRBuilder<> &IRB, bool WithFrameRecord) { // Get shadow base address by aligning RecordPtr up. // Note: this is not correct if the pointer is already aligned. // Runtime library will make sure this never happens. - LocalDynamicShadow = IRB.CreateAdd( + ShadowBase = IRB.CreateAdd( IRB.CreateOr( ThreadLongMaybeUntagged, ConstantInt::get(IntptrTy, (1ULL << kShadowBaseAlignment) - 1)), ConstantInt::get(IntptrTy, 1), "hwasan.shadow"); - LocalDynamicShadow = IRB.CreateIntToPtr(LocalDynamicShadow, Int8PtrTy); + ShadowBase = IRB.CreateIntToPtr(ShadowBase, Int8PtrTy); } Value *HWAddressSanitizer::readRegister(IRBuilder<> &IRB, StringRef Name) { @@ -1137,7 +1251,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) { IntrinToInstrument.empty()) return Changed; - assert(!LocalDynamicShadow); + assert(!ShadowBase); Instruction *InsertPt = &*F.getEntryBlock().begin(); IRBuilder<> EntryIRB(InsertPt); @@ -1217,7 +1331,7 @@ bool HWAddressSanitizer::sanitizeFunction(Function &F) { instrumentMemIntrinsic(cast(Inst)); } - LocalDynamicShadow = nullptr; + ShadowBase = nullptr; StackBaseTag = nullptr; return true; @@ -1300,85 +1414,6 @@ void HWAddressSanitizer::instrumentGlobal(GlobalVariable *GV, uint8_t Tag) { } void HWAddressSanitizer::instrumentGlobals() { - // Start by creating a note that contains pointers to the list of global - // descriptors. Adding a note to the output file will cause the linker to - // create a PT_NOTE program header pointing to the note that we can use to - // find the descriptor list starting from the program headers. A function - // provided by the runtime initializes the shadow memory for the globals by - // accessing the descriptor list via the note. The dynamic loader needs to - // call this function whenever a library is loaded. - // - // The reason why we use a note for this instead of a more conventional - // approach of having a global constructor pass a descriptor list pointer to - // the runtime is because of an order of initialization problem. With - // constructors we can encounter the following problematic scenario: - // - // 1) library A depends on library B and also interposes one of B's symbols - // 2) B's constructors are called before A's (as required for correctness) - // 3) during construction, B accesses one of its "own" globals (actually - // interposed by A) and triggers a HWASAN failure due to the initialization - // for A not having happened yet - // - // Even without interposition it is possible to run into similar situations in - // cases where two libraries mutually depend on each other. - // - // We only need one note per binary, so put everything for the note in a - // comdat. This need to be a comdat with an .init_array section to prevent - // newer versions of lld from discarding the note. - Comdat *NoteComdat = M.getOrInsertComdat(kHwasanModuleCtorName); - - Type *Int8Arr0Ty = ArrayType::get(Int8Ty, 0); - auto Start = - new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, - nullptr, "__start_hwasan_globals"); - Start->setVisibility(GlobalValue::HiddenVisibility); - Start->setDSOLocal(true); - auto Stop = - new GlobalVariable(M, Int8Arr0Ty, true, GlobalVariable::ExternalLinkage, - nullptr, "__stop_hwasan_globals"); - Stop->setVisibility(GlobalValue::HiddenVisibility); - Stop->setDSOLocal(true); - - // Null-terminated so actually 8 bytes, which are required in order to align - // the note properly. - auto *Name = ConstantDataArray::get(*C, "LLVM\0\0\0"); - - auto *NoteTy = StructType::get(Int32Ty, Int32Ty, Int32Ty, Name->getType(), - Int32Ty, Int32Ty); - auto *Note = - new GlobalVariable(M, NoteTy, /*isConstantGlobal=*/true, - GlobalValue::PrivateLinkage, nullptr, kHwasanNoteName); - Note->setSection(".note.hwasan.globals"); - Note->setComdat(NoteComdat); - Note->setAlignment(Align(4)); - Note->setDSOLocal(true); - - // The pointers in the note need to be relative so that the note ends up being - // placed in rodata, which is the standard location for notes. - auto CreateRelPtr = [&](Constant *Ptr) { - return ConstantExpr::getTrunc( - ConstantExpr::getSub(ConstantExpr::getPtrToInt(Ptr, Int64Ty), - ConstantExpr::getPtrToInt(Note, Int64Ty)), - Int32Ty); - }; - Note->setInitializer(ConstantStruct::getAnon( - {ConstantInt::get(Int32Ty, 8), // n_namesz - ConstantInt::get(Int32Ty, 8), // n_descsz - ConstantInt::get(Int32Ty, ELF::NT_LLVM_HWASAN_GLOBALS), // n_type - Name, CreateRelPtr(Start), CreateRelPtr(Stop)})); - appendToCompilerUsed(M, Note); - - // Create a zero-length global in hwasan_globals so that the linker will - // always create start and stop symbols. - auto Dummy = new GlobalVariable( - M, Int8Arr0Ty, /*isConstantGlobal*/ true, GlobalVariable::PrivateLinkage, - Constant::getNullValue(Int8Arr0Ty), "hwasan.dummy.global"); - Dummy->setSection("hwasan_globals"); - Dummy->setComdat(NoteComdat); - Dummy->setMetadata(LLVMContext::MD_associated, - MDNode::get(*C, ValueAsMetadata::get(Note))); - appendToCompilerUsed(M, Dummy); - std::vector Globals; for (GlobalVariable &GV : M.globals()) { if (GV.isDeclarationForLinker() || GV.getName().startswith("llvm.") || diff --git a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp index bcd4e2e8e33c..5b9557a9b328 100644 --- a/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp +++ b/llvm/lib/Transforms/Instrumentation/IndirectCallPromotion.cpp @@ -263,8 +263,15 @@ ICallPromotionFunc::getPromotionCandidatesForCallSite( break; } + // Don't promote if the symbol is not defined in the module. This avoids + // creating a reference to a symbol that doesn't exist in the module + // This can happen when we compile with a sample profile collected from + // one binary but used for another, which may have profiled targets that + // aren't used in the new binary. We might have a declaration initially in + // the case where the symbol is globally dead in the binary and removed by + // ThinLTO. Function *TargetFunction = Symtab->getFunction(Target); - if (TargetFunction == nullptr) { + if (TargetFunction == nullptr || TargetFunction->isDeclaration()) { LLVM_DEBUG(dbgs() << " Not promote: Cannot find the target\n"); ORE.emit([&]() { return OptimizationRemarkMissed(DEBUG_TYPE, "UnableToFindTarget", &CB) diff --git a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp index 7b03bbfcdfe4..9efc7d1ac500 100644 --- a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp +++ b/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp @@ -57,21 +57,6 @@ using namespace llvm; #define DEBUG_TYPE "instrprof" -// The start and end values of precise value profile range for memory -// intrinsic sizes -cl::opt MemOPSizeRange( - "memop-size-range", - cl::desc("Set the range of size in memory intrinsic calls to be profiled " - "precisely, in a format of :"), - cl::init("")); - -// The value that considered to be large value in memory intrinsic. -cl::opt MemOPSizeLarge( - "memop-size-large", - cl::desc("Set large value thresthold in memory intrinsic size profiling. " - "Value of 0 disables the large value profiling."), - cl::init(8192)); - namespace { cl::opt DoHashBasedCounterSplit( @@ -150,6 +135,10 @@ cl::opt IterativeCounterPromotion( cl::ZeroOrMore, "iterative-counter-promotion", cl::init(true), cl::desc("Allow counter promotion across the whole loop nest.")); +cl::opt SkipRetExitBlock( + cl::ZeroOrMore, "skip-ret-exit-block", cl::init(true), + cl::desc("Suppress counter promotion if exit blocks contain ret.")); + class InstrProfilingLegacyPass : public ModulePass { InstrProfiling InstrProf; @@ -272,6 +261,18 @@ public: // Skip 'infinite' loops: if (ExitBlocks.size() == 0) return false; + + // Skip if any of the ExitBlocks contains a ret instruction. + // This is to prevent dumping of incomplete profile -- if the + // the loop is a long running loop and dump is called in the middle + // of the loop, the result profile is incomplete. + // FIXME: add other heuristics to detect long running loops. + if (SkipRetExitBlock) { + for (auto BB : ExitBlocks) + if (isa(BB->getTerminator())) + return false; + } + unsigned MaxProm = getMaxNumOfPromotionsInLoop(&L); if (MaxProm == 0) return false; @@ -395,6 +396,15 @@ private: BlockFrequencyInfo *BFI; }; +enum class ValueProfilingCallType { + // Individual values are tracked. Currently used for indiret call target + // profiling. + Default, + + // MemOp: the memop size value profiling. + MemOp +}; + } // end anonymous namespace PreservedAnalyses InstrProfiling::run(Module &M, ModuleAnalysisManager &AM) { @@ -529,8 +539,6 @@ bool InstrProfiling::run( NamesSize = 0; ProfileDataMap.clear(); UsedVars.clear(); - getMemOPSizeRangeFromOption(MemOPSizeRange, MemOPSizeRangeStart, - MemOPSizeRangeLast); TT = Triple(M.getTargetTriple()); // Emit the runtime hook even if no counters are present. @@ -579,9 +587,9 @@ bool InstrProfiling::run( return true; } -static FunctionCallee -getOrInsertValueProfilingCall(Module &M, const TargetLibraryInfo &TLI, - bool IsRange = false) { +static FunctionCallee getOrInsertValueProfilingCall( + Module &M, const TargetLibraryInfo &TLI, + ValueProfilingCallType CallType = ValueProfilingCallType::Default) { LLVMContext &Ctx = M.getContext(); auto *ReturnTy = Type::getVoidTy(M.getContext()); @@ -589,27 +597,19 @@ getOrInsertValueProfilingCall(Module &M, const TargetLibraryInfo &TLI, if (auto AK = TLI.getExtAttrForI32Param(false)) AL = AL.addParamAttribute(M.getContext(), 2, AK); - if (!IsRange) { - Type *ParamTypes[] = { -#define VALUE_PROF_FUNC_PARAM(ParamType, ParamName, ParamLLVMType) ParamLLVMType -#include "llvm/ProfileData/InstrProfData.inc" - }; - auto *ValueProfilingCallTy = - FunctionType::get(ReturnTy, makeArrayRef(ParamTypes), false); - return M.getOrInsertFunction(getInstrProfValueProfFuncName(), - ValueProfilingCallTy, AL); - } else { - Type *RangeParamTypes[] = { -#define VALUE_RANGE_PROF 1 + assert((CallType == ValueProfilingCallType::Default || + CallType == ValueProfilingCallType::MemOp) && + "Must be Default or MemOp"); + Type *ParamTypes[] = { #define VALUE_PROF_FUNC_PARAM(ParamType, ParamName, ParamLLVMType) ParamLLVMType #include "llvm/ProfileData/InstrProfData.inc" -#undef VALUE_RANGE_PROF - }; - auto *ValueRangeProfilingCallTy = - FunctionType::get(ReturnTy, makeArrayRef(RangeParamTypes), false); - return M.getOrInsertFunction(getInstrProfValueRangeProfFuncName(), - ValueRangeProfilingCallTy, AL); - } + }; + auto *ValueProfilingCallTy = + FunctionType::get(ReturnTy, makeArrayRef(ParamTypes), false); + StringRef FuncName = CallType == ValueProfilingCallType::Default + ? getInstrProfValueProfFuncName() + : getInstrProfValueProfMemOpFuncName(); + return M.getOrInsertFunction(FuncName, ValueProfilingCallTy, AL); } void InstrProfiling::computeNumValueSiteCounts(InstrProfValueProfileInst *Ind) { @@ -638,8 +638,8 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) { Index += It->second.NumValueSites[Kind]; IRBuilder<> Builder(Ind); - bool IsRange = (Ind->getValueKind()->getZExtValue() == - llvm::InstrProfValueKind::IPVK_MemOPSize); + bool IsMemOpSize = (Ind->getValueKind()->getZExtValue() == + llvm::InstrProfValueKind::IPVK_MemOPSize); CallInst *Call = nullptr; auto *TLI = &GetTLI(*Ind->getFunction()); @@ -649,22 +649,19 @@ void InstrProfiling::lowerValueProfileInst(InstrProfValueProfileInst *Ind) { // WinEHPrepare pass. SmallVector OpBundles; Ind->getOperandBundlesAsDefs(OpBundles); - if (!IsRange) { + if (!IsMemOpSize) { Value *Args[3] = {Ind->getTargetValue(), Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), Builder.getInt32(Index)}; Call = Builder.CreateCall(getOrInsertValueProfilingCall(*M, *TLI), Args, OpBundles); } else { - Value *Args[6] = { - Ind->getTargetValue(), - Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), - Builder.getInt32(Index), - Builder.getInt64(MemOPSizeRangeStart), - Builder.getInt64(MemOPSizeRangeLast), - Builder.getInt64(MemOPSizeLarge == 0 ? INT64_MIN : MemOPSizeLarge)}; - Call = Builder.CreateCall(getOrInsertValueProfilingCall(*M, *TLI, true), - Args, OpBundles); + Value *Args[3] = {Ind->getTargetValue(), + Builder.CreateBitCast(DataVar, Builder.getInt8PtrTy()), + Builder.getInt32(Index)}; + Call = Builder.CreateCall( + getOrInsertValueProfilingCall(*M, *TLI, ValueProfilingCallType::MemOp), + Args, OpBundles); } if (auto AK = TLI->getExtAttrForI32Param(false)) Call->addParamAttr(2, AK); @@ -831,9 +828,11 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) { Visibility = GlobalValue::HiddenVisibility; } } + std::string DataVarName = getVarName(Inc, getInstrProfDataVarPrefix()); auto MaybeSetComdat = [=](GlobalVariable *GV) { if (NeedComdat) - GV->setComdat(M->getOrInsertComdat(GV->getName())); + GV->setComdat(M->getOrInsertComdat(TT.isOSBinFormatCOFF() ? GV->getName() + : DataVarName)); }; uint64_t NumCounters = Inc->getNumCounters()->getZExtValue(); @@ -898,9 +897,9 @@ InstrProfiling::getOrCreateRegionCounters(InstrProfIncrementInst *Inc) { #define INSTR_PROF_DATA(Type, LLVMType, Name, Init) Init, #include "llvm/ProfileData/InstrProfData.inc" }; - auto *Data = new GlobalVariable(*M, DataTy, false, Linkage, - ConstantStruct::get(DataTy, DataVals), - getVarName(Inc, getInstrProfDataVarPrefix())); + auto *Data = + new GlobalVariable(*M, DataTy, false, Linkage, + ConstantStruct::get(DataTy, DataVals), DataVarName); Data->setVisibility(Visibility); Data->setSection(getInstrProfSectionName(IPSK_data, TT.getObjectFormat())); Data->setAlignment(Align(INSTR_PROF_DATA_ALIGNMENT)); diff --git a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp index ad238f1357c6..cfdf3cad97f7 100644 --- a/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/Instrumentation.cpp @@ -105,6 +105,8 @@ Comdat *llvm::GetOrCreateFunctionComdat(Function &F, Triple &T, void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeAddressSanitizerLegacyPassPass(Registry); initializeModuleAddressSanitizerLegacyPassPass(Registry); + initializeMemProfilerLegacyPassPass(Registry); + initializeModuleMemProfilerLegacyPassPass(Registry); initializeBoundsCheckingLegacyPassPass(Registry); initializeControlHeightReductionLegacyPassPass(Registry); initializeGCOVProfilerLegacyPassPass(Registry); @@ -119,7 +121,7 @@ void llvm::initializeInstrumentation(PassRegistry &Registry) { initializeHWAddressSanitizerLegacyPassPass(Registry); initializeThreadSanitizerLegacyPassPass(Registry); initializeModuleSanitizerCoverageLegacyPassPass(Registry); - initializeDataFlowSanitizerPass(Registry); + initializeDataFlowSanitizerLegacyPassPass(Registry); } /// LLVMInitializeInstrumentation - C binding for diff --git a/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp new file mode 100644 index 000000000000..0e6a404a9e0b --- /dev/null +++ b/llvm/lib/Transforms/Instrumentation/MemProfiler.cpp @@ -0,0 +1,638 @@ +//===- MemProfiler.cpp - memory allocation and access profiler ------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file is a part of MemProfiler. Memory accesses are instrumented +// to increment the access count held in a shadow memory location, or +// alternatively to call into the runtime. Memory intrinsic calls (memmove, +// memcpy, memset) are changed to call the memory profiling runtime version +// instead. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Instrumentation/MemProfiler.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/GlobalValue.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Instrumentation.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/ModuleUtils.h" + +using namespace llvm; + +#define DEBUG_TYPE "memprof" + +constexpr int LLVM_MEM_PROFILER_VERSION = 1; + +// Size of memory mapped to a single shadow location. +constexpr uint64_t DefaultShadowGranularity = 64; + +// Scale from granularity down to shadow size. +constexpr uint64_t DefaultShadowScale = 3; + +constexpr char MemProfModuleCtorName[] = "memprof.module_ctor"; +constexpr uint64_t MemProfCtorAndDtorPriority = 1; +// On Emscripten, the system needs more than one priorities for constructors. +constexpr uint64_t MemProfEmscriptenCtorAndDtorPriority = 50; +constexpr char MemProfInitName[] = "__memprof_init"; +constexpr char MemProfVersionCheckNamePrefix[] = + "__memprof_version_mismatch_check_v"; + +constexpr char MemProfShadowMemoryDynamicAddress[] = + "__memprof_shadow_memory_dynamic_address"; + +constexpr char MemProfFilenameVar[] = "__memprof_profile_filename"; + +// Command-line flags. + +static cl::opt ClInsertVersionCheck( + "memprof-guard-against-version-mismatch", + cl::desc("Guard against compiler/runtime version mismatch."), cl::Hidden, + cl::init(true)); + +// This flag may need to be replaced with -f[no-]memprof-reads. +static cl::opt ClInstrumentReads("memprof-instrument-reads", + cl::desc("instrument read instructions"), + cl::Hidden, cl::init(true)); + +static cl::opt + ClInstrumentWrites("memprof-instrument-writes", + cl::desc("instrument write instructions"), cl::Hidden, + cl::init(true)); + +static cl::opt ClInstrumentAtomics( + "memprof-instrument-atomics", + cl::desc("instrument atomic instructions (rmw, cmpxchg)"), cl::Hidden, + cl::init(true)); + +static cl::opt ClUseCalls( + "memprof-use-callbacks", + cl::desc("Use callbacks instead of inline instrumentation sequences."), + cl::Hidden, cl::init(false)); + +static cl::opt + ClMemoryAccessCallbackPrefix("memprof-memory-access-callback-prefix", + cl::desc("Prefix for memory access callbacks"), + cl::Hidden, cl::init("__memprof_")); + +// These flags allow to change the shadow mapping. +// The shadow mapping looks like +// Shadow = ((Mem & mask) >> scale) + offset + +static cl::opt ClMappingScale("memprof-mapping-scale", + cl::desc("scale of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowScale)); + +static cl::opt + ClMappingGranularity("memprof-mapping-granularity", + cl::desc("granularity of memprof shadow mapping"), + cl::Hidden, cl::init(DefaultShadowGranularity)); + +// Debug flags. + +static cl::opt ClDebug("memprof-debug", cl::desc("debug"), cl::Hidden, + cl::init(0)); + +static cl::opt ClDebugFunc("memprof-debug-func", cl::Hidden, + cl::desc("Debug func")); + +static cl::opt ClDebugMin("memprof-debug-min", cl::desc("Debug min inst"), + cl::Hidden, cl::init(-1)); + +static cl::opt ClDebugMax("memprof-debug-max", cl::desc("Debug max inst"), + cl::Hidden, cl::init(-1)); + +STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); +STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); + +namespace { + +/// This struct defines the shadow mapping using the rule: +/// shadow = ((mem & mask) >> Scale) ADD DynamicShadowOffset. +struct ShadowMapping { + ShadowMapping() { + Scale = ClMappingScale; + Granularity = ClMappingGranularity; + Mask = ~(Granularity - 1); + } + + int Scale; + int Granularity; + uint64_t Mask; // Computed as ~(Granularity-1) +}; + +static uint64_t getCtorAndDtorPriority(Triple &TargetTriple) { + return TargetTriple.isOSEmscripten() ? MemProfEmscriptenCtorAndDtorPriority + : MemProfCtorAndDtorPriority; +} + +struct InterestingMemoryAccess { + Value *Addr = nullptr; + bool IsWrite; + unsigned Alignment; + uint64_t TypeSize; + Value *MaybeMask = nullptr; +}; + +/// Instrument the code in module to profile memory accesses. +class MemProfiler { +public: + MemProfiler(Module &M) { + C = &(M.getContext()); + LongSize = M.getDataLayout().getPointerSizeInBits(); + IntptrTy = Type::getIntNTy(*C, LongSize); + } + + /// If it is an interesting memory access, populate information + /// about the access and return a InterestingMemoryAccess struct. + /// Otherwise return None. + Optional + isInterestingMemoryAccess(Instruction *I) const; + + void instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access); + void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore, + Value *Addr, uint32_t TypeSize, bool IsWrite); + void instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, uint32_t TypeSize, + bool IsWrite); + void instrumentMemIntrinsic(MemIntrinsic *MI); + Value *memToShadow(Value *Shadow, IRBuilder<> &IRB); + bool instrumentFunction(Function &F); + bool maybeInsertMemProfInitAtFunctionEntry(Function &F); + bool insertDynamicShadowAtFunctionEntry(Function &F); + +private: + void initializeCallbacks(Module &M); + + LLVMContext *C; + int LongSize; + Type *IntptrTy; + ShadowMapping Mapping; + + // These arrays is indexed by AccessIsWrite + FunctionCallee MemProfMemoryAccessCallback[2]; + FunctionCallee MemProfMemoryAccessCallbackSized[2]; + + FunctionCallee MemProfMemmove, MemProfMemcpy, MemProfMemset; + Value *DynamicShadowOffset = nullptr; +}; + +class MemProfilerLegacyPass : public FunctionPass { +public: + static char ID; + + explicit MemProfilerLegacyPass() : FunctionPass(ID) { + initializeMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "MemProfilerFunctionPass"; } + + bool runOnFunction(Function &F) override { + MemProfiler Profiler(*F.getParent()); + return Profiler.instrumentFunction(F); + } +}; + +class ModuleMemProfiler { +public: + ModuleMemProfiler(Module &M) { TargetTriple = Triple(M.getTargetTriple()); } + + bool instrumentModule(Module &); + +private: + Triple TargetTriple; + ShadowMapping Mapping; + Function *MemProfCtorFunction = nullptr; +}; + +class ModuleMemProfilerLegacyPass : public ModulePass { +public: + static char ID; + + explicit ModuleMemProfilerLegacyPass() : ModulePass(ID) { + initializeModuleMemProfilerLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + StringRef getPassName() const override { return "ModuleMemProfiler"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override {} + + bool runOnModule(Module &M) override { + ModuleMemProfiler MemProfiler(M); + return MemProfiler.instrumentModule(M); + } +}; + +} // end anonymous namespace + +MemProfilerPass::MemProfilerPass() {} + +PreservedAnalyses MemProfilerPass::run(Function &F, + AnalysisManager &AM) { + Module &M = *F.getParent(); + MemProfiler Profiler(M); + if (Profiler.instrumentFunction(F)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); + + return PreservedAnalyses::all(); +} + +ModuleMemProfilerPass::ModuleMemProfilerPass() {} + +PreservedAnalyses ModuleMemProfilerPass::run(Module &M, + AnalysisManager &AM) { + ModuleMemProfiler Profiler(M); + if (Profiler.instrumentModule(M)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); +} + +char MemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS_BEGIN(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) +INITIALIZE_PASS_END(MemProfilerLegacyPass, "memprof", + "MemProfiler: profile memory allocations and accesses.", + false, false) + +FunctionPass *llvm::createMemProfilerFunctionPass() { + return new MemProfilerLegacyPass(); +} + +char ModuleMemProfilerLegacyPass::ID = 0; + +INITIALIZE_PASS(ModuleMemProfilerLegacyPass, "memprof-module", + "MemProfiler: profile memory allocations and accesses." + "ModulePass", + false, false) + +ModulePass *llvm::createModuleMemProfilerLegacyPassPass() { + return new ModuleMemProfilerLegacyPass(); +} + +Value *MemProfiler::memToShadow(Value *Shadow, IRBuilder<> &IRB) { + // (Shadow & mask) >> scale + Shadow = IRB.CreateAnd(Shadow, Mapping.Mask); + Shadow = IRB.CreateLShr(Shadow, Mapping.Scale); + // (Shadow >> scale) | offset + assert(DynamicShadowOffset); + return IRB.CreateAdd(Shadow, DynamicShadowOffset); +} + +// Instrument memset/memmove/memcpy +void MemProfiler::instrumentMemIntrinsic(MemIntrinsic *MI) { + IRBuilder<> IRB(MI); + if (isa(MI)) { + IRB.CreateCall( + isa(MI) ? MemProfMemmove : MemProfMemcpy, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreatePointerCast(MI->getOperand(1), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } else if (isa(MI)) { + IRB.CreateCall( + MemProfMemset, + {IRB.CreatePointerCast(MI->getOperand(0), IRB.getInt8PtrTy()), + IRB.CreateIntCast(MI->getOperand(1), IRB.getInt32Ty(), false), + IRB.CreateIntCast(MI->getOperand(2), IntptrTy, false)}); + } + MI->eraseFromParent(); +} + +Optional +MemProfiler::isInterestingMemoryAccess(Instruction *I) const { + // Do not instrument the load fetching the dynamic shadow address. + if (DynamicShadowOffset == I) + return None; + + InterestingMemoryAccess Access; + + const DataLayout &DL = I->getModule()->getDataLayout(); + if (LoadInst *LI = dyn_cast(I)) { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + Access.TypeSize = DL.getTypeStoreSizeInBits(LI->getType()); + Access.Alignment = LI->getAlignment(); + Access.Addr = LI->getPointerOperand(); + } else if (StoreInst *SI = dyn_cast(I)) { + if (!ClInstrumentWrites) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(SI->getValueOperand()->getType()); + Access.Alignment = SI->getAlignment(); + Access.Addr = SI->getPointerOperand(); + } else if (AtomicRMWInst *RMW = dyn_cast(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(RMW->getValOperand()->getType()); + Access.Alignment = 0; + Access.Addr = RMW->getPointerOperand(); + } else if (AtomicCmpXchgInst *XCHG = dyn_cast(I)) { + if (!ClInstrumentAtomics) + return None; + Access.IsWrite = true; + Access.TypeSize = + DL.getTypeStoreSizeInBits(XCHG->getCompareOperand()->getType()); + Access.Alignment = 0; + Access.Addr = XCHG->getPointerOperand(); + } else if (auto *CI = dyn_cast(I)) { + auto *F = CI->getCalledFunction(); + if (F && (F->getIntrinsicID() == Intrinsic::masked_load || + F->getIntrinsicID() == Intrinsic::masked_store)) { + unsigned OpOffset = 0; + if (F->getIntrinsicID() == Intrinsic::masked_store) { + if (!ClInstrumentWrites) + return None; + // Masked store has an initial operand for the value. + OpOffset = 1; + Access.IsWrite = true; + } else { + if (!ClInstrumentReads) + return None; + Access.IsWrite = false; + } + + auto *BasePtr = CI->getOperand(0 + OpOffset); + auto *Ty = cast(BasePtr->getType())->getElementType(); + Access.TypeSize = DL.getTypeStoreSizeInBits(Ty); + if (auto *AlignmentConstant = + dyn_cast(CI->getOperand(1 + OpOffset))) + Access.Alignment = (unsigned)AlignmentConstant->getZExtValue(); + else + Access.Alignment = 1; // No alignment guarantees. We probably got Undef + Access.MaybeMask = CI->getOperand(2 + OpOffset); + Access.Addr = BasePtr; + } + } + + if (!Access.Addr) + return None; + + // Do not instrument acesses from different address spaces; we cannot deal + // with them. + Type *PtrTy = cast(Access.Addr->getType()->getScalarType()); + if (PtrTy->getPointerAddressSpace() != 0) + return None; + + // Ignore swifterror addresses. + // swifterror memory addresses are mem2reg promoted by instruction + // selection. As such they cannot have regular uses like an instrumentation + // function and it makes no sense to track them as memory. + if (Access.Addr->isSwiftError()) + return None; + + return Access; +} + +void MemProfiler::instrumentMaskedLoadOrStore(const DataLayout &DL, Value *Mask, + Instruction *I, Value *Addr, + unsigned Alignment, + uint32_t TypeSize, bool IsWrite) { + auto *VTy = cast( + cast(Addr->getType())->getElementType()); + uint64_t ElemTypeSize = DL.getTypeStoreSizeInBits(VTy->getScalarType()); + unsigned Num = VTy->getNumElements(); + auto *Zero = ConstantInt::get(IntptrTy, 0); + for (unsigned Idx = 0; Idx < Num; ++Idx) { + Value *InstrumentedAddress = nullptr; + Instruction *InsertBefore = I; + if (auto *Vector = dyn_cast(Mask)) { + // dyn_cast as we might get UndefValue + if (auto *Masked = dyn_cast(Vector->getOperand(Idx))) { + if (Masked->isZero()) + // Mask is constant false, so no instrumentation needed. + continue; + // If we have a true or undef value, fall through to instrumentAddress. + // with InsertBefore == I + } + } else { + IRBuilder<> IRB(I); + Value *MaskElem = IRB.CreateExtractElement(Mask, Idx); + Instruction *ThenTerm = SplitBlockAndInsertIfThen(MaskElem, I, false); + InsertBefore = ThenTerm; + } + + IRBuilder<> IRB(InsertBefore); + InstrumentedAddress = + IRB.CreateGEP(VTy, Addr, {Zero, ConstantInt::get(IntptrTy, Idx)}); + instrumentAddress(I, InsertBefore, InstrumentedAddress, ElemTypeSize, + IsWrite); + } +} + +void MemProfiler::instrumentMop(Instruction *I, const DataLayout &DL, + InterestingMemoryAccess &Access) { + if (Access.IsWrite) + NumInstrumentedWrites++; + else + NumInstrumentedReads++; + + if (Access.MaybeMask) { + instrumentMaskedLoadOrStore(DL, Access.MaybeMask, I, Access.Addr, + Access.Alignment, Access.TypeSize, + Access.IsWrite); + } else { + // Since the access counts will be accumulated across the entire allocation, + // we only update the shadow access count for the first location and thus + // don't need to worry about alignment and type size. + instrumentAddress(I, I, Access.Addr, Access.TypeSize, Access.IsWrite); + } +} + +void MemProfiler::instrumentAddress(Instruction *OrigIns, + Instruction *InsertBefore, Value *Addr, + uint32_t TypeSize, bool IsWrite) { + IRBuilder<> IRB(InsertBefore); + Value *AddrLong = IRB.CreatePointerCast(Addr, IntptrTy); + + if (ClUseCalls) { + IRB.CreateCall(MemProfMemoryAccessCallback[IsWrite], AddrLong); + return; + } + + // Create an inline sequence to compute shadow location, and increment the + // value by one. + Type *ShadowTy = Type::getInt64Ty(*C); + Type *ShadowPtrTy = PointerType::get(ShadowTy, 0); + Value *ShadowPtr = memToShadow(AddrLong, IRB); + Value *ShadowAddr = IRB.CreateIntToPtr(ShadowPtr, ShadowPtrTy); + Value *ShadowValue = IRB.CreateLoad(ShadowTy, ShadowAddr); + Value *Inc = ConstantInt::get(Type::getInt64Ty(*C), 1); + ShadowValue = IRB.CreateAdd(ShadowValue, Inc); + IRB.CreateStore(ShadowValue, ShadowAddr); +} + +// Create the variable for the profile file name. +void createProfileFileNameVar(Module &M) { + const MDString *MemProfFilename = + dyn_cast_or_null(M.getModuleFlag("MemProfProfileFilename")); + if (!MemProfFilename) + return; + assert(!MemProfFilename->getString().empty() && + "Unexpected MemProfProfileFilename metadata with empty string"); + Constant *ProfileNameConst = ConstantDataArray::getString( + M.getContext(), MemProfFilename->getString(), true); + GlobalVariable *ProfileNameVar = new GlobalVariable( + M, ProfileNameConst->getType(), /*isConstant=*/true, + GlobalValue::WeakAnyLinkage, ProfileNameConst, MemProfFilenameVar); + Triple TT(M.getTargetTriple()); + if (TT.supportsCOMDAT()) { + ProfileNameVar->setLinkage(GlobalValue::ExternalLinkage); + ProfileNameVar->setComdat(M.getOrInsertComdat(MemProfFilenameVar)); + } +} + +bool ModuleMemProfiler::instrumentModule(Module &M) { + // Create a module constructor. + std::string MemProfVersion = std::to_string(LLVM_MEM_PROFILER_VERSION); + std::string VersionCheckName = + ClInsertVersionCheck ? (MemProfVersionCheckNamePrefix + MemProfVersion) + : ""; + std::tie(MemProfCtorFunction, std::ignore) = + createSanitizerCtorAndInitFunctions(M, MemProfModuleCtorName, + MemProfInitName, /*InitArgTypes=*/{}, + /*InitArgs=*/{}, VersionCheckName); + + const uint64_t Priority = getCtorAndDtorPriority(TargetTriple); + appendToGlobalCtors(M, MemProfCtorFunction, Priority); + + createProfileFileNameVar(M); + + return true; +} + +void MemProfiler::initializeCallbacks(Module &M) { + IRBuilder<> IRB(*C); + + for (size_t AccessIsWrite = 0; AccessIsWrite <= 1; AccessIsWrite++) { + const std::string TypeStr = AccessIsWrite ? "store" : "load"; + + SmallVector Args2 = {IntptrTy, IntptrTy}; + SmallVector Args1{1, IntptrTy}; + MemProfMemoryAccessCallbackSized[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr + "N", + FunctionType::get(IRB.getVoidTy(), Args2, false)); + + MemProfMemoryAccessCallback[AccessIsWrite] = + M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + TypeStr, + FunctionType::get(IRB.getVoidTy(), Args1, false)); + } + MemProfMemmove = M.getOrInsertFunction( + ClMemoryAccessCallbackPrefix + "memmove", IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); + MemProfMemcpy = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memcpy", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt8PtrTy(), IntptrTy); + MemProfMemset = M.getOrInsertFunction(ClMemoryAccessCallbackPrefix + "memset", + IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), + IRB.getInt32Ty(), IntptrTy); +} + +bool MemProfiler::maybeInsertMemProfInitAtFunctionEntry(Function &F) { + // For each NSObject descendant having a +load method, this method is invoked + // by the ObjC runtime before any of the static constructors is called. + // Therefore we need to instrument such methods with a call to __memprof_init + // at the beginning in order to initialize our runtime before any access to + // the shadow memory. + // We cannot just ignore these methods, because they may call other + // instrumented functions. + if (F.getName().find(" load]") != std::string::npos) { + FunctionCallee MemProfInitFunction = + declareSanitizerInitFunction(*F.getParent(), MemProfInitName, {}); + IRBuilder<> IRB(&F.front(), F.front().begin()); + IRB.CreateCall(MemProfInitFunction, {}); + return true; + } + return false; +} + +bool MemProfiler::insertDynamicShadowAtFunctionEntry(Function &F) { + IRBuilder<> IRB(&F.front().front()); + Value *GlobalDynamicAddress = F.getParent()->getOrInsertGlobal( + MemProfShadowMemoryDynamicAddress, IntptrTy); + if (F.getParent()->getPICLevel() == PICLevel::NotPIC) + cast(GlobalDynamicAddress)->setDSOLocal(true); + DynamicShadowOffset = IRB.CreateLoad(IntptrTy, GlobalDynamicAddress); + return true; +} + +bool MemProfiler::instrumentFunction(Function &F) { + if (F.getLinkage() == GlobalValue::AvailableExternallyLinkage) + return false; + if (ClDebugFunc == F.getName()) + return false; + if (F.getName().startswith("__memprof_")) + return false; + + bool FunctionModified = false; + + // If needed, insert __memprof_init. + // This function needs to be called even if the function body is not + // instrumented. + if (maybeInsertMemProfInitAtFunctionEntry(F)) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF instrumenting:\n" << F << "\n"); + + initializeCallbacks(*F.getParent()); + + FunctionModified |= insertDynamicShadowAtFunctionEntry(F); + + SmallVector ToInstrument; + + // Fill the set of memory operations to instrument. + for (auto &BB : F) { + for (auto &Inst : BB) { + if (isInterestingMemoryAccess(&Inst) || isa(Inst)) + ToInstrument.push_back(&Inst); + } + } + + int NumInstrumented = 0; + for (auto *Inst : ToInstrument) { + if (ClDebugMin < 0 || ClDebugMax < 0 || + (NumInstrumented >= ClDebugMin && NumInstrumented <= ClDebugMax)) { + Optional Access = + isInterestingMemoryAccess(Inst); + if (Access) + instrumentMop(Inst, F.getParent()->getDataLayout(), *Access); + else + instrumentMemIntrinsic(cast(Inst)); + } + NumInstrumented++; + } + + if (NumInstrumented > 0) + FunctionModified = true; + + LLVM_DEBUG(dbgs() << "MEMPROF done instrumenting: " << FunctionModified << " " + << F << "\n"); + + return FunctionModified; +} diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index fcf7f470b3e1..7a6874584d59 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -153,6 +153,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Triple.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" @@ -337,8 +338,8 @@ static cl::opt ClOriginBase("msan-origin-base", cl::desc("Define custom MSan OriginBase"), cl::Hidden, cl::init(0)); -static const char *const kMsanModuleCtorName = "msan.module_ctor"; -static const char *const kMsanInitName = "__msan_init"; +const char kMsanModuleCtorName[] = "msan.module_ctor"; +const char kMsanInitName[] = "__msan_init"; namespace { @@ -572,6 +573,9 @@ private: /// uninitialized value and returns an updated origin id encoding this info. FunctionCallee MsanChainOriginFn; + /// Run-time helper that paints an origin over a region. + FunctionCallee MsanSetOriginFn; + /// MSan runtime replacements for memmove, memcpy and memset. FunctionCallee MemmoveFn, MemcpyFn, MemsetFn; @@ -850,6 +854,9 @@ void MemorySanitizer::initializeCallbacks(Module &M) { // instrumentation. MsanChainOriginFn = M.getOrInsertFunction( "__msan_chain_origin", IRB.getInt32Ty(), IRB.getInt32Ty()); + MsanSetOriginFn = + M.getOrInsertFunction("__msan_set_origin", IRB.getVoidTy(), + IRB.getInt8PtrTy(), IntptrTy, IRB.getInt32Ty()); MemmoveFn = M.getOrInsertFunction( "__msan_memmove", IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IRB.getInt8PtrTy(), IntptrTy); @@ -1049,7 +1056,7 @@ struct MemorySanitizerVisitor : public InstVisitor { ValueMap ShadowMap, OriginMap; std::unique_ptr VAHelper; const TargetLibraryInfo *TLI; - BasicBlock *ActualFnStart; + Instruction *FnPrologueEnd; // The following flags disable parts of MSan instrumentation based on // exclusion list contents and command-line options. @@ -1081,17 +1088,31 @@ struct MemorySanitizerVisitor : public InstVisitor { PoisonStack = SanitizeFunction && ClPoisonStack; PoisonUndef = SanitizeFunction && ClPoisonUndef; + // In the presence of unreachable blocks, we may see Phi nodes with + // incoming nodes from such blocks. Since InstVisitor skips unreachable + // blocks, such nodes will not have any shadow value associated with them. + // It's easier to remove unreachable blocks than deal with missing shadow. + removeUnreachableBlocks(F); + MS.initializeCallbacks(*F.getParent()); - if (MS.CompileKernel) - ActualFnStart = insertKmsanPrologue(F); - else - ActualFnStart = &F.getEntryBlock(); + FnPrologueEnd = IRBuilder<>(F.getEntryBlock().getFirstNonPHI()) + .CreateIntrinsic(Intrinsic::donothing, {}, {}); + + if (MS.CompileKernel) { + IRBuilder<> IRB(FnPrologueEnd); + insertKmsanPrologue(IRB); + } LLVM_DEBUG(if (!InsertChecks) dbgs() << "MemorySanitizer is not inserting checks into '" << F.getName() << "'\n"); } + bool isInPrologue(Instruction &I) { + return I.getParent() == FnPrologueEnd->getParent() && + (&I == FnPrologueEnd || I.comesBefore(FnPrologueEnd)); + } + Value *updateOrigin(Value *V, IRBuilder<> &IRB) { if (MS.TrackOrigins <= 1) return V; return IRB.CreateCall(MS.MsanChainOriginFn, V); @@ -1143,37 +1164,30 @@ struct MemorySanitizerVisitor : public InstVisitor { const DataLayout &DL = F.getParent()->getDataLayout(); const Align OriginAlignment = std::max(kMinOriginAlignment, Alignment); unsigned StoreSize = DL.getTypeStoreSize(Shadow->getType()); - if (Shadow->getType()->isAggregateType()) { - paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, - OriginAlignment); - } else { - Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); - if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { - if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) - paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, - OriginAlignment); - return; - } - - unsigned TypeSizeInBits = - DL.getTypeSizeInBits(ConvertedShadow->getType()); - unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); - if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) { - FunctionCallee Fn = MS.MaybeStoreOriginFn[SizeIndex]; - Value *ConvertedShadow2 = IRB.CreateZExt( - ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex))); - IRB.CreateCall(Fn, {ConvertedShadow2, - IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), - Origin}); - } else { - Value *Cmp = IRB.CreateICmpNE( - ConvertedShadow, getCleanShadow(ConvertedShadow), "_mscmp"); - Instruction *CheckTerm = SplitBlockAndInsertIfThen( - Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights); - IRBuilder<> IRBNew(CheckTerm); - paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), OriginPtr, StoreSize, + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); + if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { + if (ClCheckConstantShadow && !ConstantShadow->isZeroValue()) + paintOrigin(IRB, updateOrigin(Origin, IRB), OriginPtr, StoreSize, OriginAlignment); - } + return; + } + + unsigned TypeSizeInBits = DL.getTypeSizeInBits(ConvertedShadow->getType()); + unsigned SizeIndex = TypeSizeToSizeIndex(TypeSizeInBits); + if (AsCall && SizeIndex < kNumberOfAccessSizes && !MS.CompileKernel) { + FunctionCallee Fn = MS.MaybeStoreOriginFn[SizeIndex]; + Value *ConvertedShadow2 = + IRB.CreateZExt(ConvertedShadow, IRB.getIntNTy(8 * (1 << SizeIndex))); + IRB.CreateCall(Fn, + {ConvertedShadow2, + IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy()), Origin}); + } else { + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); + Instruction *CheckTerm = SplitBlockAndInsertIfThen( + Cmp, &*IRB.GetInsertPoint(), false, MS.OriginStoreWeights); + IRBuilder<> IRBNew(CheckTerm); + paintOrigin(IRBNew, updateOrigin(Origin, IRBNew), OriginPtr, StoreSize, + OriginAlignment); } } @@ -1218,7 +1232,7 @@ struct MemorySanitizerVisitor : public InstVisitor { bool AsCall) { IRBuilder<> IRB(OrigIns); LLVM_DEBUG(dbgs() << " SHAD0 : " << *Shadow << "\n"); - Value *ConvertedShadow = convertToShadowTyNoVec(Shadow, IRB); + Value *ConvertedShadow = convertShadowToScalar(Shadow, IRB); LLVM_DEBUG(dbgs() << " SHAD1 : " << *ConvertedShadow << "\n"); if (auto *ConstantShadow = dyn_cast(ConvertedShadow)) { @@ -1240,8 +1254,7 @@ struct MemorySanitizerVisitor : public InstVisitor { ? Origin : (Value *)IRB.getInt32(0)}); } else { - Value *Cmp = IRB.CreateICmpNE(ConvertedShadow, - getCleanShadow(ConvertedShadow), "_mscmp"); + Value *Cmp = convertToBool(ConvertedShadow, IRB, "_mscmp"); Instruction *CheckTerm = SplitBlockAndInsertIfThen( Cmp, OrigIns, /* Unreachable */ !MS.Recover, MS.ColdCallWeights); @@ -1262,10 +1275,8 @@ struct MemorySanitizerVisitor : public InstVisitor { LLVM_DEBUG(dbgs() << "DONE:\n" << F); } - BasicBlock *insertKmsanPrologue(Function &F) { - BasicBlock *ret = - SplitBlock(&F.getEntryBlock(), F.getEntryBlock().getFirstNonPHI()); - IRBuilder<> IRB(F.getEntryBlock().getFirstNonPHI()); + // Returns the last instruction in the new prologue + void insertKmsanPrologue(IRBuilder<> &IRB) { Value *ContextState = IRB.CreateCall(MS.MsanGetContextStateFn, {}); Constant *Zero = IRB.getInt32(0); MS.ParamTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState, @@ -1284,21 +1295,14 @@ struct MemorySanitizerVisitor : public InstVisitor { MS.RetvalOriginTLS = IRB.CreateGEP(MS.MsanContextStateTy, ContextState, {Zero, IRB.getInt32(6)}, "retval_origin"); - return ret; } /// Add MemorySanitizer instrumentation to a function. bool runOnFunction() { - // In the presence of unreachable blocks, we may see Phi nodes with - // incoming nodes from such blocks. Since InstVisitor skips unreachable - // blocks, such nodes will not have any shadow value associated with them. - // It's easier to remove unreachable blocks than deal with missing shadow. - removeUnreachableBlocks(F); - // Iterate all BBs in depth-first order and create shadow instructions // for all instructions (where applicable). // For PHI nodes we create dummy shadow PHIs which will be finalized later. - for (BasicBlock *BB : depth_first(ActualFnStart)) + for (BasicBlock *BB : depth_first(FnPrologueEnd->getParent())) visit(*BB); // Finalize PHI nodes. @@ -1385,14 +1389,68 @@ struct MemorySanitizerVisitor : public InstVisitor { return ty; } - /// Convert a shadow value to it's flattened variant. - Value *convertToShadowTyNoVec(Value *V, IRBuilder<> &IRB) { + /// Extract combined shadow of struct elements as a bool + Value *collapseStructShadow(StructType *Struct, Value *Shadow, + IRBuilder<> &IRB) { + Value *FalseVal = IRB.getIntN(/* width */ 1, /* value */ 0); + Value *Aggregator = FalseVal; + + for (unsigned Idx = 0; Idx < Struct->getNumElements(); Idx++) { + // Combine by ORing together each element's bool shadow + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); + Value *ShadowBool = convertToBool(ShadowInner, IRB); + + if (Aggregator != FalseVal) + Aggregator = IRB.CreateOr(Aggregator, ShadowBool); + else + Aggregator = ShadowBool; + } + + return Aggregator; + } + + // Extract combined shadow of array elements + Value *collapseArrayShadow(ArrayType *Array, Value *Shadow, + IRBuilder<> &IRB) { + if (!Array->getNumElements()) + return IRB.getIntN(/* width */ 1, /* value */ 0); + + Value *FirstItem = IRB.CreateExtractValue(Shadow, 0); + Value *Aggregator = convertShadowToScalar(FirstItem, IRB); + + for (unsigned Idx = 1; Idx < Array->getNumElements(); Idx++) { + Value *ShadowItem = IRB.CreateExtractValue(Shadow, Idx); + Value *ShadowInner = convertShadowToScalar(ShadowItem, IRB); + Aggregator = IRB.CreateOr(Aggregator, ShadowInner); + } + return Aggregator; + } + + /// Convert a shadow value to it's flattened variant. The resulting + /// shadow may not necessarily have the same bit width as the input + /// value, but it will always be comparable to zero. + Value *convertShadowToScalar(Value *V, IRBuilder<> &IRB) { + if (StructType *Struct = dyn_cast(V->getType())) + return collapseStructShadow(Struct, V, IRB); + if (ArrayType *Array = dyn_cast(V->getType())) + return collapseArrayShadow(Array, V, IRB); Type *Ty = V->getType(); Type *NoVecTy = getShadowTyNoVec(Ty); if (Ty == NoVecTy) return V; return IRB.CreateBitCast(V, NoVecTy); } + // Convert a scalar value to an i1 by comparing with 0 + Value *convertToBool(Value *V, IRBuilder<> &IRB, const Twine &name = "") { + Type *VTy = V->getType(); + assert(VTy->isIntegerTy()); + if (VTy->getIntegerBitWidth() == 1) + // Just converting a bool to a bool, so do nothing. + return V; + return IRB.CreateICmpNE(V, ConstantInt::get(VTy, 0), name); + } + /// Compute the integer shadow offset that corresponds to a given /// application address. /// @@ -1611,7 +1669,7 @@ struct MemorySanitizerVisitor : public InstVisitor { if (*ShadowPtr) return *ShadowPtr; Function *F = A->getParent(); - IRBuilder<> EntryIRB(ActualFnStart->getFirstNonPHI()); + IRBuilder<> EntryIRB(FnPrologueEnd); unsigned ArgOffset = 0; const DataLayout &DL = F->getParent()->getDataLayout(); for (auto &FArg : F->args()) { @@ -1679,6 +1737,8 @@ struct MemorySanitizerVisitor : public InstVisitor { } else { setOrigin(A, getCleanOrigin()); } + + break; } if (!FArgEagerCheck) @@ -1726,8 +1786,10 @@ struct MemorySanitizerVisitor : public InstVisitor { if (!InsertChecks) return; #ifndef NDEBUG Type *ShadowTy = Shadow->getType(); - assert((isa(ShadowTy) || isa(ShadowTy)) && - "Can only insert checks for integer and vector shadow types"); + assert((isa(ShadowTy) || isa(ShadowTy) || + isa(ShadowTy) || isa(ShadowTy)) && + "Can only insert checks for integer, vector, and aggregate shadow " + "types"); #endif InstrumentationList.push_back( ShadowOriginAndInsertPoint(Shadow, Origin, OrigIns)); @@ -1769,6 +1831,24 @@ struct MemorySanitizerVisitor : public InstVisitor { llvm_unreachable("Unknown ordering"); } + Value *makeAddReleaseOrderingTable(IRBuilder<> &IRB) { + constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; + uint32_t OrderingTable[NumOrderings] = {}; + + OrderingTable[(int)AtomicOrderingCABI::relaxed] = + OrderingTable[(int)AtomicOrderingCABI::release] = + (int)AtomicOrderingCABI::release; + OrderingTable[(int)AtomicOrderingCABI::consume] = + OrderingTable[(int)AtomicOrderingCABI::acquire] = + OrderingTable[(int)AtomicOrderingCABI::acq_rel] = + (int)AtomicOrderingCABI::acq_rel; + OrderingTable[(int)AtomicOrderingCABI::seq_cst] = + (int)AtomicOrderingCABI::seq_cst; + + return ConstantDataVector::get(IRB.getContext(), + makeArrayRef(OrderingTable, NumOrderings)); + } + AtomicOrdering addAcquireOrdering(AtomicOrdering a) { switch (a) { case AtomicOrdering::NotAtomic: @@ -1786,11 +1866,33 @@ struct MemorySanitizerVisitor : public InstVisitor { llvm_unreachable("Unknown ordering"); } + Value *makeAddAcquireOrderingTable(IRBuilder<> &IRB) { + constexpr int NumOrderings = (int)AtomicOrderingCABI::seq_cst + 1; + uint32_t OrderingTable[NumOrderings] = {}; + + OrderingTable[(int)AtomicOrderingCABI::relaxed] = + OrderingTable[(int)AtomicOrderingCABI::acquire] = + OrderingTable[(int)AtomicOrderingCABI::consume] = + (int)AtomicOrderingCABI::acquire; + OrderingTable[(int)AtomicOrderingCABI::release] = + OrderingTable[(int)AtomicOrderingCABI::acq_rel] = + (int)AtomicOrderingCABI::acq_rel; + OrderingTable[(int)AtomicOrderingCABI::seq_cst] = + (int)AtomicOrderingCABI::seq_cst; + + return ConstantDataVector::get(IRB.getContext(), + makeArrayRef(OrderingTable, NumOrderings)); + } + // ------------------- Visitors. using InstVisitor::visit; void visit(Instruction &I) { - if (!I.getMetadata("nosanitize")) - InstVisitor::visit(I); + if (I.getMetadata("nosanitize")) + return; + // Don't want to visit if we're in the prologue + if (isInPrologue(I)) + return; + InstVisitor::visit(I); } /// Instrument LoadInst @@ -2046,7 +2148,7 @@ struct MemorySanitizerVisitor : public InstVisitor { Constant *ConstOrigin = dyn_cast(OpOrigin); // No point in adding something that might result in 0 origin value. if (!ConstOrigin || !ConstOrigin->isNullValue()) { - Value *FlatShadow = MSV->convertToShadowTyNoVec(OpShadow, IRB); + Value *FlatShadow = MSV->convertShadowToScalar(OpShadow, IRB); Value *Cond = IRB.CreateICmpNE(FlatShadow, MSV->getCleanShadow(FlatShadow)); Origin = IRB.CreateSelect(Cond, OpOrigin, Origin); @@ -2538,7 +2640,6 @@ struct MemorySanitizerVisitor : public InstVisitor { return false; unsigned NumArgOperands = I.getNumArgOperands(); - for (unsigned i = 0; i < NumArgOperands; ++i) { Type *Ty = I.getArgOperand(i)->getType(); if (Ty != RetTy) @@ -2602,9 +2703,7 @@ struct MemorySanitizerVisitor : public InstVisitor { void handleLifetimeStart(IntrinsicInst &I) { if (!PoisonStack) return; - DenseMap AllocaForValue; - AllocaInst *AI = - llvm::findAllocaForValue(I.getArgOperand(1), AllocaForValue); + AllocaInst *AI = llvm::findAllocaForValue(I.getArgOperand(1)); if (!AI) InstrumentLifetimeStart = false; LifetimeStartList.push_back(std::make_pair(&I, AI)); @@ -2635,14 +2734,16 @@ struct MemorySanitizerVisitor : public InstVisitor { // We copy the shadow of \p CopyOp[NumUsedElements:] to \p // Out[NumUsedElements:]. This means that intrinsics without \p CopyOp always // return a fully initialized value. - void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements) { + void handleVectorConvertIntrinsic(IntrinsicInst &I, int NumUsedElements, + bool HasRoundingMode = false) { IRBuilder<> IRB(&I); Value *CopyOp, *ConvertOp; - switch (I.getNumArgOperands()) { - case 3: - assert(isa(I.getArgOperand(2)) && "Invalid rounding mode"); - LLVM_FALLTHROUGH; + assert((!HasRoundingMode || + isa(I.getArgOperand(I.getNumArgOperands() - 1))) && + "Invalid rounding mode"); + + switch (I.getNumArgOperands() - HasRoundingMode) { case 2: CopyOp = I.getArgOperand(0); ConvertOp = I.getArgOperand(1); @@ -2898,7 +2999,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOrigin(&I, getOrigin(&I, 0)); } - // Instrument experimental.vector.reduce.or intrinsic. + // Instrument vector.reduce.or intrinsic. // Valid (non-poisoned) set bits in the operand pull low the // corresponding shadow bits. void handleVectorReduceOrIntrinsic(IntrinsicInst &I) { @@ -2916,7 +3017,7 @@ struct MemorySanitizerVisitor : public InstVisitor { setOrigin(&I, getOrigin(&I, 0)); } - // Instrument experimental.vector.reduce.or intrinsic. + // Instrument vector.reduce.and intrinsic. // Valid (non-poisoned) unset bits in the operand pull down the // corresponding shadow bits. void handleVectorReduceAndIntrinsic(IntrinsicInst &I) { @@ -3089,18 +3190,15 @@ struct MemorySanitizerVisitor : public InstVisitor { // and then apply the usual shadow combining logic. void handlePclmulIntrinsic(IntrinsicInst &I) { IRBuilder<> IRB(&I); - Type *ShadowTy = getShadowTy(&I); unsigned Width = cast(I.getArgOperand(0)->getType())->getNumElements(); assert(isa(I.getArgOperand(2)) && "pclmul 3rd operand must be a constant"); unsigned Imm = cast(I.getArgOperand(2))->getZExtValue(); - Value *Shuf0 = - IRB.CreateShuffleVector(getShadow(&I, 0), UndefValue::get(ShadowTy), - getPclmulMask(Width, Imm & 0x01)); - Value *Shuf1 = - IRB.CreateShuffleVector(getShadow(&I, 1), UndefValue::get(ShadowTy), - getPclmulMask(Width, Imm & 0x10)); + Value *Shuf0 = IRB.CreateShuffleVector(getShadow(&I, 0), + getPclmulMask(Width, Imm & 0x01)); + Value *Shuf1 = IRB.CreateShuffleVector(getShadow(&I, 1), + getPclmulMask(Width, Imm & 0x10)); ShadowAndOriginCombiner SOC(this, IRB); SOC.Add(Shuf0, getOrigin(&I, 0)); SOC.Add(Shuf1, getOrigin(&I, 1)); @@ -3133,8 +3231,24 @@ struct MemorySanitizerVisitor : public InstVisitor { setOriginForNaryOp(I); } + // Instrument abs intrinsic. + // handleUnknownIntrinsic can't handle it because of the last + // is_int_min_poison argument which does not match the result type. + void handleAbsIntrinsic(IntrinsicInst &I) { + assert(I.getType()->isIntOrIntVectorTy()); + assert(I.getArgOperand(0)->getType() == I.getType()); + + // FIXME: Handle is_int_min_poison. + IRBuilder<> IRB(&I); + setShadow(&I, getShadow(&I, 0)); + setOrigin(&I, getOrigin(&I, 0)); + } + void visitIntrinsicInst(IntrinsicInst &I) { switch (I.getIntrinsicID()) { + case Intrinsic::abs: + handleAbsIntrinsic(I); + break; case Intrinsic::lifetime_start: handleLifetimeStart(I); break; @@ -3151,15 +3265,15 @@ struct MemorySanitizerVisitor : public InstVisitor { case Intrinsic::masked_load: handleMaskedLoad(I); break; - case Intrinsic::experimental_vector_reduce_and: + case Intrinsic::vector_reduce_and: handleVectorReduceAndIntrinsic(I); break; - case Intrinsic::experimental_vector_reduce_or: + case Intrinsic::vector_reduce_or: handleVectorReduceOrIntrinsic(I); break; - case Intrinsic::experimental_vector_reduce_add: - case Intrinsic::experimental_vector_reduce_xor: - case Intrinsic::experimental_vector_reduce_mul: + case Intrinsic::vector_reduce_add: + case Intrinsic::vector_reduce_xor: + case Intrinsic::vector_reduce_mul: handleVectorReduceIntrinsic(I); break; case Intrinsic::x86_sse_stmxcsr: @@ -3179,6 +3293,8 @@ struct MemorySanitizerVisitor : public InstVisitor { case Intrinsic::x86_avx512_cvtusi2ss: case Intrinsic::x86_avx512_cvtusi642sd: case Intrinsic::x86_avx512_cvtusi642ss: + handleVectorConvertIntrinsic(I, 1, true); + break; case Intrinsic::x86_sse2_cvtsd2si64: case Intrinsic::x86_sse2_cvtsd2si: case Intrinsic::x86_sse2_cvtsd2ss: @@ -3404,6 +3520,63 @@ struct MemorySanitizerVisitor : public InstVisitor { } } + void visitLibAtomicLoad(CallBase &CB) { + // Since we use getNextNode here, we can't have CB terminate the BB. + assert(isa(CB)); + + IRBuilder<> IRB(&CB); + Value *Size = CB.getArgOperand(0); + Value *SrcPtr = CB.getArgOperand(1); + Value *DstPtr = CB.getArgOperand(2); + Value *Ordering = CB.getArgOperand(3); + // Convert the call to have at least Acquire ordering to make sure + // the shadow operations aren't reordered before it. + Value *NewOrdering = + IRB.CreateExtractElement(makeAddAcquireOrderingTable(IRB), Ordering); + CB.setArgOperand(3, NewOrdering); + + IRBuilder<> NextIRB(CB.getNextNode()); + NextIRB.SetCurrentDebugLocation(CB.getDebugLoc()); + + Value *SrcShadowPtr, *SrcOriginPtr; + std::tie(SrcShadowPtr, SrcOriginPtr) = + getShadowOriginPtr(SrcPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), + /*isStore*/ false); + Value *DstShadowPtr = + getShadowOriginPtr(DstPtr, NextIRB, NextIRB.getInt8Ty(), Align(1), + /*isStore*/ true) + .first; + + NextIRB.CreateMemCpy(DstShadowPtr, Align(1), SrcShadowPtr, Align(1), Size); + if (MS.TrackOrigins) { + Value *SrcOrigin = NextIRB.CreateAlignedLoad(MS.OriginTy, SrcOriginPtr, + kMinOriginAlignment); + Value *NewOrigin = updateOrigin(SrcOrigin, NextIRB); + NextIRB.CreateCall(MS.MsanSetOriginFn, {DstPtr, Size, NewOrigin}); + } + } + + void visitLibAtomicStore(CallBase &CB) { + IRBuilder<> IRB(&CB); + Value *Size = CB.getArgOperand(0); + Value *DstPtr = CB.getArgOperand(2); + Value *Ordering = CB.getArgOperand(3); + // Convert the call to have at least Release ordering to make sure + // the shadow operations aren't reordered after it. + Value *NewOrdering = + IRB.CreateExtractElement(makeAddReleaseOrderingTable(IRB), Ordering); + CB.setArgOperand(3, NewOrdering); + + Value *DstShadowPtr = + getShadowOriginPtr(DstPtr, IRB, IRB.getInt8Ty(), Align(1), + /*isStore*/ true) + .first; + + // Atomic store always paints clean shadow/origin. See file header. + IRB.CreateMemSet(DstShadowPtr, getCleanShadow(IRB.getInt8Ty()), Size, + Align(1)); + } + void visitCallBase(CallBase &CB) { assert(!CB.getMetadata("nosanitize")); if (CB.isInlineAsm()) { @@ -3417,6 +3590,28 @@ struct MemorySanitizerVisitor : public InstVisitor { visitInstruction(CB); return; } + LibFunc LF; + if (TLI->getLibFunc(CB, LF)) { + // libatomic.a functions need to have special handling because there isn't + // a good way to intercept them or compile the library with + // instrumentation. + switch (LF) { + case LibFunc_atomic_load: + if (!isa(CB)) { + llvm::errs() << "MSAN -- cannot instrument invoke of libatomic load." + "Ignoring!\n"; + break; + } + visitLibAtomicLoad(CB); + return; + case LibFunc_atomic_store: + visitLibAtomicStore(CB); + return; + default: + break; + } + } + if (auto *Call = dyn_cast(&CB)) { assert(!isa(Call) && "intrinsics are handled elsewhere"); @@ -3424,20 +3619,27 @@ struct MemorySanitizerVisitor : public InstVisitor { // will become a non-readonly function after it is instrumented by us. To // prevent this code from being optimized out, mark that function // non-readonly in advance. + AttrBuilder B; + B.addAttribute(Attribute::ReadOnly) + .addAttribute(Attribute::ReadNone) + .addAttribute(Attribute::WriteOnly) + .addAttribute(Attribute::ArgMemOnly) + .addAttribute(Attribute::Speculatable); + + Call->removeAttributes(AttributeList::FunctionIndex, B); if (Function *Func = Call->getCalledFunction()) { - // Clear out readonly/readnone attributes. - AttrBuilder B; - B.addAttribute(Attribute::ReadOnly) - .addAttribute(Attribute::ReadNone) - .addAttribute(Attribute::WriteOnly) - .addAttribute(Attribute::ArgMemOnly) - .addAttribute(Attribute::Speculatable); Func->removeAttributes(AttributeList::FunctionIndex, B); } maybeMarkSanitizerLibraryCallNoBuiltin(Call, TLI); } IRBuilder<> IRB(&CB); + bool MayCheckCall = ClEagerChecks; + if (Function *Func = CB.getCalledFunction()) { + // __sanitizer_unaligned_{load,store} functions may be called by users + // and always expects shadows in the TLS. So don't check them. + MayCheckCall &= !Func->getName().startswith("__sanitizer_unaligned_"); + } unsigned ArgOffset = 0; LLVM_DEBUG(dbgs() << " CallSite: " << CB << "\n"); @@ -3463,7 +3665,7 @@ struct MemorySanitizerVisitor : public InstVisitor { bool ByVal = CB.paramHasAttr(i, Attribute::ByVal); bool NoUndef = CB.paramHasAttr(i, Attribute::NoUndef); - bool EagerCheck = ClEagerChecks && !ByVal && NoUndef; + bool EagerCheck = MayCheckCall && !ByVal && NoUndef; if (EagerCheck) { insertShadowCheck(A, &CB); @@ -3503,7 +3705,7 @@ struct MemorySanitizerVisitor : public InstVisitor { (void)Store; assert(Size != 0 && Store != nullptr); LLVM_DEBUG(dbgs() << " Param:" << *Store << "\n"); - ArgOffset += alignTo(Size, 8); + ArgOffset += alignTo(Size, kShadowTLSAlignment); } LLVM_DEBUG(dbgs() << " done with call args\n"); @@ -3519,7 +3721,7 @@ struct MemorySanitizerVisitor : public InstVisitor { if (isa(CB) && cast(CB).isMustTailCall()) return; - if (ClEagerChecks && CB.hasRetAttr(Attribute::NoUndef)) { + if (MayCheckCall && CB.hasRetAttr(Attribute::NoUndef)) { setShadow(&CB, getCleanShadow(&CB)); setOrigin(&CB, getCleanOrigin()); return; @@ -3902,6 +4104,12 @@ struct MemorySanitizerVisitor : public InstVisitor { setOrigin(&I, getCleanOrigin()); } + void visitFreezeInst(FreezeInst &I) { + // Freeze always returns a fully defined value. + setShadow(&I, getCleanShadow(&I)); + setOrigin(&I, getCleanOrigin()); + } + void visitInstruction(Instruction &I) { // Everything else: stop propagating and check for poisoned shadow. if (ClDumpStrictInstructions) @@ -4125,7 +4333,7 @@ struct VarArgAMD64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = @@ -4271,7 +4479,7 @@ struct VarArgMIPS64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -4464,7 +4672,7 @@ struct VarArgAArch64Helper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = @@ -4584,15 +4792,14 @@ struct VarArgPowerPC64Helper : public VarArgHelper { // For PowerPC, we need to deal with alignment of stack arguments - // they are mostly aligned to 8 bytes, but vectors and i128 arrays // are aligned to 16 bytes, byvals can be aligned to 8 or 16 bytes, - // and QPX vectors are aligned to 32 bytes. For that reason, we - // compute current offset from stack pointer (which is always properly - // aligned), and offset for the first vararg, then subtract them. + // For that reason, we compute current offset from stack pointer (which is + // always properly aligned), and offset for the first vararg, then subtract + // them. unsigned VAArgBase; Triple TargetTriple(F.getParent()->getTargetTriple()); // Parameter save area starts at 48 bytes from frame pointer for ABIv1, // and 32 bytes for ABIv2. This is usually determined by target // endianness, but in theory could be overridden by function attribute. - // For simplicity, we ignore it here (it'd only matter for QPX vectors). if (TargetTriple.getArch() == Triple::ppc64) VAArgBase = 48; else @@ -4710,7 +4917,7 @@ struct VarArgPowerPC64Helper : public VarArgHelper { void finalizeInstrumentation() override { assert(!VAArgSize && !VAArgTLSCopy && "finalizeInstrumentation called twice"); - IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = IRB.CreateAdd(ConstantInt::get(MS.IntptrTy, 0), VAArgSize); @@ -5029,7 +5236,7 @@ struct VarArgSystemZHelper : public VarArgHelper { if (!VAStartInstrumentationList.empty()) { // If there is a va_start in this function, make a backup copy of // va_arg_tls somewhere in the function entry block. - IRBuilder<> IRB(MSV.ActualFnStart->getFirstNonPHI()); + IRBuilder<> IRB(MSV.FnPrologueEnd); VAArgOverflowSize = IRB.CreateLoad(IRB.getInt64Ty(), MS.VAArgOverflowSizeTLS); Value *CopySize = diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index dcfc28887a48..be6c8c631001 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -110,7 +110,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/MisExpect.h" #include #include #include @@ -249,6 +248,38 @@ static cl::opt "optimization remarks: -{Rpass|" "pass-remarks}=pgo-instrumentation")); +static cl::opt PGOInstrumentEntry( + "pgo-instrument-entry", cl::init(false), cl::Hidden, + cl::desc("Force to instrument function entry basicblock.")); + +static cl::opt + PGOFixEntryCount("pgo-fix-entry-count", cl::init(true), cl::Hidden, + cl::desc("Fix function entry count in profile use.")); + +static cl::opt PGOVerifyHotBFI( + "pgo-verify-hot-bfi", cl::init(false), cl::Hidden, + cl::desc("Print out the non-match BFI count if a hot raw profile count " + "becomes non-hot, or a cold raw profile count becomes hot. " + "The print is enabled under -Rpass-analysis=pgo, or " + "internal option -pass-remakrs-analysis=pgo.")); + +static cl::opt PGOVerifyBFI( + "pgo-verify-bfi", cl::init(false), cl::Hidden, + cl::desc("Print out mismatched BFI counts after setting profile metadata " + "The print is enabled under -Rpass-analysis=pgo, or " + "internal option -pass-remakrs-analysis=pgo.")); + +static cl::opt PGOVerifyBFIRatio( + "pgo-verify-bfi-ratio", cl::init(5), cl::Hidden, + cl::desc("Set the threshold for pgo-verify-big -- only print out " + "mismatched BFI if the difference percentage is greater than " + "this value (in percentage).")); + +static cl::opt PGOVerifyBFICutoff( + "pgo-verify-bfi-cutoff", cl::init(1), cl::Hidden, + cl::desc("Set the threshold for pgo-verify-bfi -- skip the counts whose " + "profile count value is below.")); + // Command line option to turn on CFG dot dump after profile annotation. // Defined in Analysis/BlockFrequencyInfo.cpp: -pgo-view-counts extern cl::opt PGOViewCounts; @@ -257,6 +288,10 @@ extern cl::opt PGOViewCounts; // Defined in Analysis/BlockFrequencyInfo.cpp: -view-bfi-func-name= extern cl::opt ViewBlockFreqFuncName; +static cl::opt + PGOOldCFGHashing("pgo-instr-old-cfg-hashing", cl::init(false), cl::Hidden, + cl::desc("Use the old CFG function hashing")); + // Return a string describing the branch condition that can be // used in static branch probability heuristics: static std::string getBranchCondString(Instruction *TI) { @@ -425,7 +460,7 @@ public: private: bool runOnModule(Module &M) override { createProfileFileNameVar(M, InstrProfileOutput); - createIRLevelProfileFlagVar(M, true); + createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); return false; } std::string InstrProfileOutput; @@ -572,9 +607,11 @@ public: Function &Func, TargetLibraryInfo &TLI, std::unordered_multimap &ComdatMembers, bool CreateGlobalVar = false, BranchProbabilityInfo *BPI = nullptr, - BlockFrequencyInfo *BFI = nullptr, bool IsCS = false) + BlockFrequencyInfo *BFI = nullptr, bool IsCS = false, + bool InstrumentFuncEntry = true) : F(Func), IsCS(IsCS), ComdatMembers(ComdatMembers), VPC(Func, TLI), - ValueSites(IPVK_Last + 1), SIVisitor(Func), MST(F, BPI, BFI) { + ValueSites(IPVK_Last + 1), SIVisitor(Func), + MST(F, InstrumentFuncEntry, BPI, BFI) { // This should be done before CFG hash computation. SIVisitor.countSelects(Func); ValueSites[IPVK_MemOPSize] = VPC.get(IPVK_MemOPSize); @@ -611,7 +648,8 @@ public: } // end anonymous namespace // Compute Hash value for the CFG: the lower 32 bits are CRC32 of the index -// value of each BB in the CFG. The higher 32 bits record the number of edges. +// value of each BB in the CFG. The higher 32 bits are the CRC32 of the numbers +// of selects, indirect calls, mem ops and edges. template void FuncPGOInstrumentation::computeCFGHash() { std::vector Indexes; @@ -630,12 +668,31 @@ void FuncPGOInstrumentation::computeCFGHash() { } JC.update(Indexes); - // Hash format for context sensitive profile. Reserve 4 bits for other - // information. - FunctionHash = (uint64_t)SIVisitor.getNumOfSelectInsts() << 56 | - (uint64_t)ValueSites[IPVK_IndirectCallTarget].size() << 48 | - //(uint64_t)ValueSites[IPVK_MemOPSize].size() << 40 | - (uint64_t)MST.AllEdges.size() << 32 | JC.getCRC(); + JamCRC JCH; + if (PGOOldCFGHashing) { + // Hash format for context sensitive profile. Reserve 4 bits for other + // information. + FunctionHash = (uint64_t)SIVisitor.getNumOfSelectInsts() << 56 | + (uint64_t)ValueSites[IPVK_IndirectCallTarget].size() << 48 | + //(uint64_t)ValueSites[IPVK_MemOPSize].size() << 40 | + (uint64_t)MST.AllEdges.size() << 32 | JC.getCRC(); + } else { + // The higher 32 bits. + auto updateJCH = [&JCH](uint64_t Num) { + uint8_t Data[8]; + support::endian::write64le(Data, Num); + JCH.update(Data); + }; + updateJCH((uint64_t)SIVisitor.getNumOfSelectInsts()); + updateJCH((uint64_t)ValueSites[IPVK_IndirectCallTarget].size()); + updateJCH((uint64_t)ValueSites[IPVK_MemOPSize].size()); + updateJCH((uint64_t)MST.AllEdges.size()); + + // Hash format for context sensitive profile. Reserve 4 bits for other + // information. + FunctionHash = (((uint64_t)JCH.getCRC()) << 28) + JC.getCRC(); + } + // Reserve bit 60-63 for other information purpose. FunctionHash &= 0x0FFFFFFFFFFFFFFF; if (IsCS) @@ -644,8 +701,12 @@ void FuncPGOInstrumentation::computeCFGHash() { << " CRC = " << JC.getCRC() << ", Selects = " << SIVisitor.getNumOfSelectInsts() << ", Edges = " << MST.AllEdges.size() << ", ICSites = " - << ValueSites[IPVK_IndirectCallTarget].size() - << ", Hash = " << FunctionHash << "\n";); + << ValueSites[IPVK_IndirectCallTarget].size()); + if (!PGOOldCFGHashing) { + LLVM_DEBUG(dbgs() << ", Memops = " << ValueSites[IPVK_MemOPSize].size() + << ", High32 CRC = " << JCH.getCRC()); + } + LLVM_DEBUG(dbgs() << ", Hash = " << FunctionHash << "\n";); } // Check if we can safely rename this Comdat function. @@ -656,7 +717,7 @@ static bool canRenameComdat( return false; // FIXME: Current only handle those Comdat groups that only containing one - // function and function aliases. + // function. // (1) For a Comdat group containing multiple functions, we need to have a // unique postfix based on the hashes for each function. There is a // non-trivial code refactoring to do this efficiently. @@ -664,8 +725,7 @@ static bool canRenameComdat( // group including global vars. Comdat *C = F.getComdat(); for (auto &&CM : make_range(ComdatMembers.equal_range(C))) { - if (dyn_cast(CM.second)) - continue; + assert(!isa(CM.second)); Function *FM = dyn_cast(CM.second); if (FM != &F) return false; @@ -705,18 +765,8 @@ void FuncPGOInstrumentation::renameComdatFunction() { NewComdat->setSelectionKind(OrigComdat->getSelectionKind()); for (auto &&CM : make_range(ComdatMembers.equal_range(OrigComdat))) { - if (GlobalAlias *GA = dyn_cast(CM.second)) { - // For aliases, change the name directly. - assert(dyn_cast(GA->getAliasee()->stripPointerCasts()) == &F); - std::string OrigGAName = GA->getName().str(); - GA->setName(Twine(GA->getName() + "." + Twine(FunctionHash))); - GlobalAlias::create(GlobalValue::WeakAnyLinkage, OrigGAName, GA); - continue; - } // Must be a function. - Function *CF = dyn_cast(CM.second); - assert(CF); - CF->setComdat(NewComdat); + cast(CM.second)->setComdat(NewComdat); } } @@ -781,8 +831,11 @@ BasicBlock *FuncPGOInstrumentation::getInstrBB(Edge *E) { if (!E->IsCritical) return canInstrument(DestBB); + // Some IndirectBr critical edges cannot be split by the previous + // SplitIndirectBrCriticalEdges call. Bail out. unsigned SuccNum = GetSuccessorNumber(SrcBB, DestBB); - BasicBlock *InstrBB = SplitCriticalEdge(TI, SuccNum); + BasicBlock *InstrBB = + isa(TI) ? nullptr : SplitCriticalEdge(TI, SuccNum); if (!InstrBB) { LLVM_DEBUG( dbgs() << "Fail to split critical edge: not instrument this edge.\n"); @@ -845,8 +898,8 @@ static void instrumentOneFunc( // later in getInstrBB() to avoid invalidating it. SplitIndirectBrCriticalEdges(F, BPI, BFI); - FuncPGOInstrumentation FuncInfo(F, TLI, ComdatMembers, true, - BPI, BFI, IsCS); + FuncPGOInstrumentation FuncInfo( + F, TLI, ComdatMembers, true, BPI, BFI, IsCS, PGOInstrumentEntry); std::vector InstrumentBBs; FuncInfo.getInstrumentBBs(InstrumentBBs); unsigned NumCounters = @@ -1004,13 +1057,15 @@ public: PGOUseFunc(Function &Func, Module *Modu, TargetLibraryInfo &TLI, std::unordered_multimap &ComdatMembers, BranchProbabilityInfo *BPI, BlockFrequencyInfo *BFIin, - ProfileSummaryInfo *PSI, bool IsCS) + ProfileSummaryInfo *PSI, bool IsCS, bool InstrumentFuncEntry) : F(Func), M(Modu), BFI(BFIin), PSI(PSI), - FuncInfo(Func, TLI, ComdatMembers, false, BPI, BFIin, IsCS), + FuncInfo(Func, TLI, ComdatMembers, false, BPI, BFIin, IsCS, + InstrumentFuncEntry), FreqAttr(FFA_Normal), IsCS(IsCS) {} // Read counts for the instrumented BB from profile. - bool readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros); + bool readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, + bool &AllMinusOnes); // Populate the counts for all BBs. void populateCounters(); @@ -1121,11 +1176,18 @@ bool PGOUseFunc::setInstrumentedCounts( if (NumCounters != CountFromProfile.size()) { return false; } + auto *FuncEntry = &*F.begin(); + // Set the profile count to the Instrumented BBs. uint32_t I = 0; for (BasicBlock *InstrBB : InstrumentBBs) { uint64_t CountValue = CountFromProfile[I++]; UseBBInfo &Info = getBBInfo(InstrBB); + // If we reach here, we know that we have some nonzero count + // values in this function. The entry count should not be 0. + // Fix it if necessary. + if (InstrBB == FuncEntry && CountValue == 0) + CountValue = 1; Info.setBBInfoCount(CountValue); } ProfileCountSize = CountFromProfile.size(); @@ -1186,7 +1248,8 @@ void PGOUseFunc::setEdgeCount(DirectEdges &Edges, uint64_t Value) { // Read the profile from ProfileFileName and assign the value to the // instrumented BB and the edges. This function also updates ProgramMaxCount. // Return true if the profile are successfully read, and false on errors. -bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros) { +bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros, + bool &AllMinusOnes) { auto &Ctx = M->getContext(); Expected Result = PGOReader->getInstrProfRecord(FuncInfo.FuncName, FuncInfo.FunctionHash); @@ -1229,10 +1292,13 @@ bool PGOUseFunc::readCounters(IndexedInstrProfReader *PGOReader, bool &AllZeros) IsCS ? NumOfCSPGOFunc++ : NumOfPGOFunc++; LLVM_DEBUG(dbgs() << CountFromProfile.size() << " counts\n"); + AllMinusOnes = (CountFromProfile.size() > 0); uint64_t ValueSum = 0; for (unsigned I = 0, S = CountFromProfile.size(); I < S; I++) { LLVM_DEBUG(dbgs() << " " << I << ": " << CountFromProfile[I] << "\n"); ValueSum += CountFromProfile[I]; + if (CountFromProfile[I] != (uint64_t)-1) + AllMinusOnes = false; } AllZeros = (ValueSum == 0); @@ -1316,7 +1382,6 @@ void PGOUseFunc::populateCounters() { } #endif uint64_t FuncEntryCount = getBBInfo(&*F.begin()).CountValue; - F.setEntryCount(ProfileCount(FuncEntryCount, Function::PCT_Real)); uint64_t FuncMaxCount = FuncEntryCount; for (auto &BB : F) { auto BI = findBBInfo(&BB); @@ -1324,6 +1389,11 @@ void PGOUseFunc::populateCounters() { continue; FuncMaxCount = std::max(FuncMaxCount, BI->CountValue); } + + // Fix the obviously inconsistent entry count. + if (FuncMaxCount > 0 && FuncEntryCount == 0) + FuncEntryCount = 1; + F.setEntryCount(ProfileCount(FuncEntryCount, Function::PCT_Real)); markFunctionAttributes(FuncEntryCount, FuncMaxCount); // Now annotate select instructions @@ -1514,13 +1584,15 @@ static bool InstrumentAllFunctions( // For the context-sensitve instrumentation, we should have a separated pass // (before LTO/ThinLTO linking) to create these variables. if (!IsCS) - createIRLevelProfileFlagVar(M, /* IsCS */ false); + createIRLevelProfileFlagVar(M, /* IsCS */ false, PGOInstrumentEntry); std::unordered_multimap ComdatMembers; collectComdatMembers(M, ComdatMembers); for (auto &F : M) { if (F.isDeclaration()) continue; + if (F.hasFnAttribute(llvm::Attribute::NoProfile)) + continue; auto &TLI = LookupTLI(F); auto *BPI = LookupBPI(F); auto *BFI = LookupBFI(F); @@ -1532,7 +1604,7 @@ static bool InstrumentAllFunctions( PreservedAnalyses PGOInstrumentationGenCreateVar::run(Module &M, ModuleAnalysisManager &AM) { createProfileFileNameVar(M, CSInstrName); - createIRLevelProfileFlagVar(M, /* IsCS */ true); + createIRLevelProfileFlagVar(M, /* IsCS */ true, PGOInstrumentEntry); return PreservedAnalyses::all(); } @@ -1571,6 +1643,129 @@ PreservedAnalyses PGOInstrumentationGen::run(Module &M, return PreservedAnalyses::none(); } +// Using the ratio b/w sums of profile count values and BFI count values to +// adjust the func entry count. +static void fixFuncEntryCount(PGOUseFunc &Func, LoopInfo &LI, + BranchProbabilityInfo &NBPI) { + Function &F = Func.getFunc(); + BlockFrequencyInfo NBFI(F, NBPI, LI); +#ifndef NDEBUG + auto BFIEntryCount = F.getEntryCount(); + assert(BFIEntryCount.hasValue() && (BFIEntryCount.getCount() > 0) && + "Invalid BFI Entrycount"); +#endif + auto SumCount = APFloat::getZero(APFloat::IEEEdouble()); + auto SumBFICount = APFloat::getZero(APFloat::IEEEdouble()); + for (auto &BBI : F) { + uint64_t CountValue = 0; + uint64_t BFICountValue = 0; + if (!Func.findBBInfo(&BBI)) + continue; + auto BFICount = NBFI.getBlockProfileCount(&BBI); + CountValue = Func.getBBInfo(&BBI).CountValue; + BFICountValue = BFICount.getValue(); + SumCount.add(APFloat(CountValue * 1.0), APFloat::rmNearestTiesToEven); + SumBFICount.add(APFloat(BFICountValue * 1.0), APFloat::rmNearestTiesToEven); + } + if (SumCount.isZero()) + return; + + assert(SumBFICount.compare(APFloat(0.0)) == APFloat::cmpGreaterThan && + "Incorrect sum of BFI counts"); + if (SumBFICount.compare(SumCount) == APFloat::cmpEqual) + return; + double Scale = (SumCount / SumBFICount).convertToDouble(); + if (Scale < 1.001 && Scale > 0.999) + return; + + uint64_t FuncEntryCount = Func.getBBInfo(&*F.begin()).CountValue; + uint64_t NewEntryCount = 0.5 + FuncEntryCount * Scale; + if (NewEntryCount == 0) + NewEntryCount = 1; + if (NewEntryCount != FuncEntryCount) { + F.setEntryCount(ProfileCount(NewEntryCount, Function::PCT_Real)); + LLVM_DEBUG(dbgs() << "FixFuncEntryCount: in " << F.getName() + << ", entry_count " << FuncEntryCount << " --> " + << NewEntryCount << "\n"); + } +} + +// Compare the profile count values with BFI count values, and print out +// the non-matching ones. +static void verifyFuncBFI(PGOUseFunc &Func, LoopInfo &LI, + BranchProbabilityInfo &NBPI, + uint64_t HotCountThreshold, + uint64_t ColdCountThreshold) { + Function &F = Func.getFunc(); + BlockFrequencyInfo NBFI(F, NBPI, LI); + // bool PrintFunc = false; + bool HotBBOnly = PGOVerifyHotBFI; + std::string Msg; + OptimizationRemarkEmitter ORE(&F); + + unsigned BBNum = 0, BBMisMatchNum = 0, NonZeroBBNum = 0; + for (auto &BBI : F) { + uint64_t CountValue = 0; + uint64_t BFICountValue = 0; + + if (Func.getBBInfo(&BBI).CountValid) + CountValue = Func.getBBInfo(&BBI).CountValue; + + BBNum++; + if (CountValue) + NonZeroBBNum++; + auto BFICount = NBFI.getBlockProfileCount(&BBI); + if (BFICount) + BFICountValue = BFICount.getValue(); + + if (HotBBOnly) { + bool rawIsHot = CountValue >= HotCountThreshold; + bool BFIIsHot = BFICountValue >= HotCountThreshold; + bool rawIsCold = CountValue <= ColdCountThreshold; + bool ShowCount = false; + if (rawIsHot && !BFIIsHot) { + Msg = "raw-Hot to BFI-nonHot"; + ShowCount = true; + } else if (rawIsCold && BFIIsHot) { + Msg = "raw-Cold to BFI-Hot"; + ShowCount = true; + } + if (!ShowCount) + continue; + } else { + if ((CountValue < PGOVerifyBFICutoff) && + (BFICountValue < PGOVerifyBFICutoff)) + continue; + uint64_t Diff = (BFICountValue >= CountValue) + ? BFICountValue - CountValue + : CountValue - BFICountValue; + if (Diff < CountValue / 100 * PGOVerifyBFIRatio) + continue; + } + BBMisMatchNum++; + + ORE.emit([&]() { + OptimizationRemarkAnalysis Remark(DEBUG_TYPE, "bfi-verify", + F.getSubprogram(), &BBI); + Remark << "BB " << ore::NV("Block", BBI.getName()) + << " Count=" << ore::NV("Count", CountValue) + << " BFI_Count=" << ore::NV("Count", BFICountValue); + if (!Msg.empty()) + Remark << " (" << Msg << ")"; + return Remark; + }); + } + if (BBMisMatchNum) + ORE.emit([&]() { + return OptimizationRemarkAnalysis(DEBUG_TYPE, "bfi-verify", + F.getSubprogram(), &F.getEntryBlock()) + << "In Func " << ore::NV("Function", F.getName()) + << ": Num_of_BB=" << ore::NV("Count", BBNum) + << ", Num_of_non_zerovalue_BB=" << ore::NV("Count", NonZeroBBNum) + << ", Num_of_mis_matching_BB=" << ore::NV("Count", BBMisMatchNum); + }); +} + static bool annotateAllFunctions( Module &M, StringRef ProfileFileName, StringRef ProfileRemappingFileName, function_ref LookupTLI, @@ -1619,6 +1814,12 @@ static bool annotateAllFunctions( collectComdatMembers(M, ComdatMembers); std::vector HotFunctions; std::vector ColdFunctions; + + // If the profile marked as always instrument the entry BB, do the + // same. Note this can be overwritten by the internal option in CFGMST.h + bool InstrumentFuncEntry = PGOReader->instrEntryBBEnabled(); + if (PGOInstrumentEntry.getNumOccurrences() > 0) + InstrumentFuncEntry = PGOInstrumentEntry; for (auto &F : M) { if (F.isDeclaration()) continue; @@ -1628,9 +1829,15 @@ static bool annotateAllFunctions( // Split indirectbr critical edges here before computing the MST rather than // later in getInstrBB() to avoid invalidating it. SplitIndirectBrCriticalEdges(F, BPI, BFI); - PGOUseFunc Func(F, &M, TLI, ComdatMembers, BPI, BFI, PSI, IsCS); + PGOUseFunc Func(F, &M, TLI, ComdatMembers, BPI, BFI, PSI, IsCS, + InstrumentFuncEntry); + // When AllMinusOnes is true, it means the profile for the function + // is unrepresentative and this function is actually hot. Set the + // entry count of the function to be multiple times of hot threshold + // and drop all its internal counters. + bool AllMinusOnes = false; bool AllZeros = false; - if (!Func.readCounters(PGOReader.get(), AllZeros)) + if (!Func.readCounters(PGOReader.get(), AllZeros, AllMinusOnes)) continue; if (AllZeros) { F.setEntryCount(ProfileCount(0, Function::PCT_Real)); @@ -1638,6 +1845,15 @@ static bool annotateAllFunctions( ColdFunctions.push_back(&F); continue; } + const unsigned MultiplyFactor = 3; + if (AllMinusOnes) { + uint64_t HotThreshold = PSI->getHotCountThreshold(); + if (HotThreshold) + F.setEntryCount( + ProfileCount(HotThreshold * MultiplyFactor, Function::PCT_Real)); + HotFunctions.push_back(&F); + continue; + } Func.populateCounters(); Func.setBranchWeights(); Func.annotateValueSites(); @@ -1675,6 +1891,23 @@ static bool annotateAllFunctions( Func.dumpInfo(); } } + + if (PGOVerifyBFI || PGOVerifyHotBFI || PGOFixEntryCount) { + LoopInfo LI{DominatorTree(F)}; + BranchProbabilityInfo NBPI(F, LI); + + // Fix func entry count. + if (PGOFixEntryCount) + fixFuncEntryCount(Func, LI, NBPI); + + // Verify BlockFrequency information. + uint64_t HotCountThreshold = 0, ColdCountThreshold = 0; + if (PGOVerifyHotBFI) { + HotCountThreshold = PSI->getOrCompHotCountThreshold(); + ColdCountThreshold = PSI->getOrCompColdCountThreshold(); + } + verifyFuncBFI(Func, LI, NBPI, HotCountThreshold, ColdCountThreshold); + } } // Set function hotness attribute from the profile. @@ -1687,6 +1920,17 @@ static bool annotateAllFunctions( << "\n"); } for (auto &F : ColdFunctions) { + // Only set when there is no Attribute::Hot set by the user. For Hot + // attribute, user's annotation has the precedence over the profile. + if (F->hasFnAttribute(Attribute::Hot)) { + auto &Ctx = M.getContext(); + std::string Msg = std::string("Function ") + F->getName().str() + + std::string(" is annotated as a hot function but" + " the profile is cold"); + Ctx.diagnose( + DiagnosticInfoPGOProfile(M.getName().data(), Msg, DS_Warning)); + continue; + } F->addFnAttr(Attribute::Cold); LLVM_DEBUG(dbgs() << "Set cold attribute to function: " << F->getName() << "\n"); @@ -1772,8 +2016,6 @@ void llvm::setProfMetadata(Module *M, Instruction *TI, dbgs() << W << " "; } dbgs() << "\n";); - misexpect::verifyMisExpect(TI, Weights, TI->getContext()); - TI->setMetadata(LLVMContext::MD_prof, MDB.createBranchWeights(Weights)); if (EmitBranchProbability) { std::string BrCondStr = getBranchCondString(TI); diff --git a/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp b/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp index 2b7b859891dc..55a93b6152dc 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOMemOPSizeOpt.cpp @@ -22,6 +22,7 @@ #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" @@ -38,6 +39,8 @@ #include "llvm/Pass.h" #include "llvm/PassRegistry.h" #include "llvm/ProfileData/InstrProf.h" +#define INSTR_PROF_VALUE_PROF_MEMOP_API +#include "llvm/ProfileData/InstrProfData.inc" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -89,17 +92,15 @@ static cl::opt cl::desc("Scale the memop size counts using the basic " " block count value")); -// This option sets the rangge of precise profile memop sizes. -extern cl::opt MemOPSizeRange; - -// This option sets the value that groups large memop sizes -extern cl::opt MemOPSizeLarge; - cl::opt MemOPOptMemcmpBcmp("pgo-memop-optimize-memcmp-bcmp", cl::init(true), cl::Hidden, cl::desc("Size-specialize memcmp and bcmp calls")); +static cl::opt + MemOpMaxOptSize("memop-value-prof-max-opt-size", cl::Hidden, cl::init(128), + cl::desc("Optimize the memop size <= this value")); + namespace { class PGOMemOPSizeOptLegacyPass : public FunctionPass { public: @@ -224,9 +225,6 @@ public: : Func(Func), BFI(BFI), ORE(ORE), DT(DT), TLI(TLI), Changed(false) { ValueDataArray = std::make_unique(MemOPMaxVersion + 2); - // Get the MemOPSize range information from option MemOPSizeRange, - getMemOPSizeRangeFromOption(MemOPSizeRange, PreciseRangeStart, - PreciseRangeLast); } bool isChanged() const { return Changed; } void perform() { @@ -256,7 +254,7 @@ public: LibFunc Func; if (TLI.getLibFunc(CI, Func) && (Func == LibFunc_memcmp || Func == LibFunc_bcmp) && - !dyn_cast(CI.getArgOperand(2))) { + !isa(CI.getArgOperand(2))) { WorkList.push_back(MemOp(&CI)); } } @@ -269,26 +267,9 @@ private: TargetLibraryInfo &TLI; bool Changed; std::vector WorkList; - // Start of the previse range. - int64_t PreciseRangeStart; - // Last value of the previse range. - int64_t PreciseRangeLast; // The space to read the profile annotation. std::unique_ptr ValueDataArray; bool perform(MemOp MO); - - // This kind shows which group the value falls in. For PreciseValue, we have - // the profile count for that value. LargeGroup groups the values that are in - // range [LargeValue, +inf). NonLargeGroup groups the rest of values. - enum MemOPSizeKind { PreciseValue, NonLargeGroup, LargeGroup }; - - MemOPSizeKind getMemOPSizeKind(int64_t Value) const { - if (Value == MemOPSizeLarge && MemOPSizeLarge != 0) - return LargeGroup; - if (Value == PreciseRangeLast + 1) - return NonLargeGroup; - return PreciseValue; - } }; static bool isProfitable(uint64_t Count, uint64_t TotalCount) { @@ -365,8 +346,7 @@ bool MemOPSizeOpt::perform(MemOp MO) { if (MemOPScaleCount) C = getScaledCount(C, ActualCount, SavedTotalCount); - // Only care precise value here. - if (getMemOPSizeKind(V) != PreciseValue) + if (!InstrProfIsSingleValRange(V) || V > MemOpMaxOptSize) continue; // ValueCounts are sorted on the count. Break at the first un-profitable diff --git a/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp b/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp index 85e096112fca..fc5267261851 100644 --- a/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp +++ b/llvm/lib/Transforms/Instrumentation/PoisonChecking.cpp @@ -282,8 +282,10 @@ static bool rewrite(Function &F) { // Note: There are many more sources of documented UB, but this pass only // attempts to find UB triggered by propagation of poison. - if (Value *Op = const_cast(getGuaranteedNonPoisonOp(&I))) - CreateAssertNot(B, getPoisonFor(ValToPoison, Op)); + SmallPtrSet NonPoisonOps; + getGuaranteedNonPoisonOps(&I, NonPoisonOps); + for (const Value *Op : NonPoisonOps) + CreateAssertNot(B, getPoisonFor(ValToPoison, const_cast(Op))); if (LocalCheck) if (auto *RI = dyn_cast(&I)) @@ -293,11 +295,11 @@ static bool rewrite(Function &F) { } SmallVector Checks; - if (propagatesPoison(&I)) + if (propagatesPoison(cast(&I))) for (Value *V : I.operands()) Checks.push_back(getPoisonFor(ValToPoison, V)); - if (canCreatePoison(&I)) + if (canCreatePoison(cast(&I))) generateCreationChecks(I, Checks); ValToPoison[&I] = buildOrChain(B, Checks); } diff --git a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp index b6a9df57e431..2d4b07939463 100644 --- a/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ b/llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -45,49 +45,39 @@ using namespace llvm; #define DEBUG_TYPE "sancov" -static const char *const SanCovTracePCIndirName = - "__sanitizer_cov_trace_pc_indir"; -static const char *const SanCovTracePCName = "__sanitizer_cov_trace_pc"; -static const char *const SanCovTraceCmp1 = "__sanitizer_cov_trace_cmp1"; -static const char *const SanCovTraceCmp2 = "__sanitizer_cov_trace_cmp2"; -static const char *const SanCovTraceCmp4 = "__sanitizer_cov_trace_cmp4"; -static const char *const SanCovTraceCmp8 = "__sanitizer_cov_trace_cmp8"; -static const char *const SanCovTraceConstCmp1 = - "__sanitizer_cov_trace_const_cmp1"; -static const char *const SanCovTraceConstCmp2 = - "__sanitizer_cov_trace_const_cmp2"; -static const char *const SanCovTraceConstCmp4 = - "__sanitizer_cov_trace_const_cmp4"; -static const char *const SanCovTraceConstCmp8 = - "__sanitizer_cov_trace_const_cmp8"; -static const char *const SanCovTraceDiv4 = "__sanitizer_cov_trace_div4"; -static const char *const SanCovTraceDiv8 = "__sanitizer_cov_trace_div8"; -static const char *const SanCovTraceGep = "__sanitizer_cov_trace_gep"; -static const char *const SanCovTraceSwitchName = "__sanitizer_cov_trace_switch"; -static const char *const SanCovModuleCtorTracePcGuardName = +const char SanCovTracePCIndirName[] = "__sanitizer_cov_trace_pc_indir"; +const char SanCovTracePCName[] = "__sanitizer_cov_trace_pc"; +const char SanCovTraceCmp1[] = "__sanitizer_cov_trace_cmp1"; +const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; +const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; +const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; +const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; +const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; +const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceDiv4[] = "__sanitizer_cov_trace_div4"; +const char SanCovTraceDiv8[] = "__sanitizer_cov_trace_div8"; +const char SanCovTraceGep[] = "__sanitizer_cov_trace_gep"; +const char SanCovTraceSwitchName[] = "__sanitizer_cov_trace_switch"; +const char SanCovModuleCtorTracePcGuardName[] = "sancov.module_ctor_trace_pc_guard"; -static const char *const SanCovModuleCtor8bitCountersName = +const char SanCovModuleCtor8bitCountersName[] = "sancov.module_ctor_8bit_counters"; -static const char *const SanCovModuleCtorBoolFlagName = - "sancov.module_ctor_bool_flag"; +const char SanCovModuleCtorBoolFlagName[] = "sancov.module_ctor_bool_flag"; static const uint64_t SanCtorAndDtorPriority = 2; -static const char *const SanCovTracePCGuardName = - "__sanitizer_cov_trace_pc_guard"; -static const char *const SanCovTracePCGuardInitName = - "__sanitizer_cov_trace_pc_guard_init"; -static const char *const SanCov8bitCountersInitName = - "__sanitizer_cov_8bit_counters_init"; -static const char *const SanCovBoolFlagInitName = - "__sanitizer_cov_bool_flag_init"; -static const char *const SanCovPCsInitName = "__sanitizer_cov_pcs_init"; +const char SanCovTracePCGuardName[] = "__sanitizer_cov_trace_pc_guard"; +const char SanCovTracePCGuardInitName[] = "__sanitizer_cov_trace_pc_guard_init"; +const char SanCov8bitCountersInitName[] = "__sanitizer_cov_8bit_counters_init"; +const char SanCovBoolFlagInitName[] = "__sanitizer_cov_bool_flag_init"; +const char SanCovPCsInitName[] = "__sanitizer_cov_pcs_init"; -static const char *const SanCovGuardsSectionName = "sancov_guards"; -static const char *const SanCovCountersSectionName = "sancov_cntrs"; -static const char *const SanCovBoolFlagSectionName = "sancov_bools"; -static const char *const SanCovPCsSectionName = "sancov_pcs"; +const char SanCovGuardsSectionName[] = "sancov_guards"; +const char SanCovCountersSectionName[] = "sancov_cntrs"; +const char SanCovBoolFlagSectionName[] = "sancov_bools"; +const char SanCovPCsSectionName[] = "sancov_pcs"; -static const char *const SanCovLowestStackName = "__sancov_lowest_stack"; +const char SanCovLowestStackName[] = "__sancov_lowest_stack"; static cl::opt ClCoverageLevel( "sanitizer-coverage-level", @@ -338,25 +328,24 @@ PreservedAnalyses ModuleSanitizerCoveragePass::run(Module &M, std::pair ModuleSanitizerCoverage::CreateSecStartEnd(Module &M, const char *Section, Type *Ty) { - GlobalVariable *SecStart = - new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, nullptr, - getSectionStart(Section)); + GlobalVariable *SecStart = new GlobalVariable( + M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, + nullptr, getSectionStart(Section)); SecStart->setVisibility(GlobalValue::HiddenVisibility); - GlobalVariable *SecEnd = - new GlobalVariable(M, Ty, false, GlobalVariable::ExternalLinkage, - nullptr, getSectionEnd(Section)); + GlobalVariable *SecEnd = new GlobalVariable( + M, Ty->getPointerElementType(), false, GlobalVariable::ExternalLinkage, + nullptr, getSectionEnd(Section)); SecEnd->setVisibility(GlobalValue::HiddenVisibility); IRBuilder<> IRB(M.getContext()); - Value *SecEndPtr = IRB.CreatePointerCast(SecEnd, Ty); if (!TargetTriple.isOSBinFormatCOFF()) - return std::make_pair(IRB.CreatePointerCast(SecStart, Ty), SecEndPtr); + return std::make_pair(SecStart, SecEnd); // Account for the fact that on windows-msvc __start_* symbols actually // point to a uint64_t before the start of the array. auto SecStartI8Ptr = IRB.CreatePointerCast(SecStart, Int8PtrTy); auto GEP = IRB.CreateGEP(Int8Ty, SecStartI8Ptr, ConstantInt::get(IntptrTy, sizeof(uint64_t))); - return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEndPtr); + return std::make_pair(IRB.CreatePointerCast(GEP, Ty), SecEnd); } Function *ModuleSanitizerCoverage::CreateInitCallsForSections( @@ -426,15 +415,13 @@ bool ModuleSanitizerCoverage::instrumentModule( SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); - // Make sure smaller parameters are zero-extended to i64 as required by the - // x86_64 ABI. + // Make sure smaller parameters are zero-extended to i64 if required by the + // target ABI. AttributeList SanCovTraceCmpZeroExtAL; - if (TargetTriple.getArch() == Triple::x86_64) { - SanCovTraceCmpZeroExtAL = - SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt); - SanCovTraceCmpZeroExtAL = - SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt); - } + SanCovTraceCmpZeroExtAL = + SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 0, Attribute::ZExt); + SanCovTraceCmpZeroExtAL = + SanCovTraceCmpZeroExtAL.addParamAttribute(*C, 1, Attribute::ZExt); SanCovTraceCmpFunction[0] = M.getOrInsertFunction(SanCovTraceCmp1, SanCovTraceCmpZeroExtAL, VoidTy, @@ -459,8 +446,7 @@ bool ModuleSanitizerCoverage::instrumentModule( { AttributeList AL; - if (TargetTriple.getArch() == Triple::x86_64) - AL = AL.addParamAttribute(*C, 0, Attribute::ZExt); + AL = AL.addParamAttribute(*C, 0, Attribute::ZExt); SanCovTraceDivFunction[0] = M.getOrInsertFunction(SanCovTraceDiv4, AL, VoidTy, IRB.getInt32Ty()); } @@ -523,29 +509,23 @@ bool ModuleSanitizerCoverage::instrumentModule( // True if block has successors and it dominates all of them. static bool isFullDominator(const BasicBlock *BB, const DominatorTree *DT) { - if (succ_begin(BB) == succ_end(BB)) + if (succ_empty(BB)) return false; - for (const BasicBlock *SUCC : make_range(succ_begin(BB), succ_end(BB))) { - if (!DT->dominates(BB, SUCC)) - return false; - } - - return true; + return llvm::all_of(successors(BB), [&](const BasicBlock *SUCC) { + return DT->dominates(BB, SUCC); + }); } // True if block has predecessors and it postdominates all of them. static bool isFullPostDominator(const BasicBlock *BB, const PostDominatorTree *PDT) { - if (pred_begin(BB) == pred_end(BB)) + if (pred_empty(BB)) return false; - for (const BasicBlock *PRED : make_range(pred_begin(BB), pred_end(BB))) { - if (!PDT->dominates(BB, PRED)) - return false; - } - - return true; + return llvm::all_of(predecessors(BB), [&](const BasicBlock *PRED) { + return PDT->dominates(BB, PRED); + }); } static bool shouldInstrumentBlock(const Function &F, const BasicBlock *BB, @@ -815,7 +795,7 @@ void ModuleSanitizerCoverage::InjectTraceForSwitch( C = ConstantExpr::getCast(CastInst::ZExt, It.getCaseValue(), Int64Ty); Initializers.push_back(C); } - llvm::sort(Initializers.begin() + 2, Initializers.end(), + llvm::sort(drop_begin(Initializers, 2), [](const Constant *A, const Constant *B) { return cast(A)->getLimitedValue() < cast(B)->getLimitedValue(); @@ -903,7 +883,7 @@ void ModuleSanitizerCoverage::InjectCoverageAtBlock(Function &F, BasicBlock &BB, DebugLoc EntryLoc; if (IsEntryBB) { if (auto SP = F.getSubprogram()) - EntryLoc = DebugLoc::get(SP->getScopeLine(), 0, SP); + EntryLoc = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); // Keep static allocas and llvm.localescape calls in the entry block. Even // if we aren't splitting the block, it's nice for allocas to be before // calls. diff --git a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp index c911b37afac7..783878cf1ec0 100644 --- a/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/ThreadSanitizer.cpp @@ -19,7 +19,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Instrumentation/ThreadSanitizer.h" -#include "llvm/ADT/SmallPtrSet.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -52,30 +53,36 @@ using namespace llvm; #define DEBUG_TYPE "tsan" -static cl::opt ClInstrumentMemoryAccesses( +static cl::opt ClInstrumentMemoryAccesses( "tsan-instrument-memory-accesses", cl::init(true), cl::desc("Instrument memory accesses"), cl::Hidden); -static cl::opt ClInstrumentFuncEntryExit( - "tsan-instrument-func-entry-exit", cl::init(true), - cl::desc("Instrument function entry and exit"), cl::Hidden); -static cl::opt ClHandleCxxExceptions( +static cl::opt + ClInstrumentFuncEntryExit("tsan-instrument-func-entry-exit", cl::init(true), + cl::desc("Instrument function entry and exit"), + cl::Hidden); +static cl::opt ClHandleCxxExceptions( "tsan-handle-cxx-exceptions", cl::init(true), cl::desc("Handle C++ exceptions (insert cleanup blocks for unwinding)"), cl::Hidden); -static cl::opt ClInstrumentAtomics( - "tsan-instrument-atomics", cl::init(true), - cl::desc("Instrument atomics"), cl::Hidden); -static cl::opt ClInstrumentMemIntrinsics( +static cl::opt ClInstrumentAtomics("tsan-instrument-atomics", + cl::init(true), + cl::desc("Instrument atomics"), + cl::Hidden); +static cl::opt ClInstrumentMemIntrinsics( "tsan-instrument-memintrinsics", cl::init(true), cl::desc("Instrument memintrinsics (memset/memcpy/memmove)"), cl::Hidden); -static cl::opt ClDistinguishVolatile( +static cl::opt ClDistinguishVolatile( "tsan-distinguish-volatile", cl::init(false), cl::desc("Emit special instrumentation for accesses to volatiles"), cl::Hidden); -static cl::opt ClInstrumentReadBeforeWrite( +static cl::opt ClInstrumentReadBeforeWrite( "tsan-instrument-read-before-write", cl::init(false), cl::desc("Do not eliminate read instrumentation for read-before-writes"), cl::Hidden); +static cl::opt ClCompoundReadBeforeWrite( + "tsan-compound-read-before-write", cl::init(false), + cl::desc("Emit special compound instrumentation for reads-before-writes"), + cl::Hidden); STATISTIC(NumInstrumentedReads, "Number of instrumented reads"); STATISTIC(NumInstrumentedWrites, "Number of instrumented writes"); @@ -89,8 +96,8 @@ STATISTIC(NumOmittedReadsFromConstantGlobals, STATISTIC(NumOmittedReadsFromVtable, "Number of vtable reads"); STATISTIC(NumOmittedNonCaptured, "Number of accesses ignored due to capturing"); -static const char *const kTsanModuleCtorName = "tsan.module_ctor"; -static const char *const kTsanInitName = "__tsan_init"; +const char kTsanModuleCtorName[] = "tsan.module_ctor"; +const char kTsanInitName[] = "__tsan_init"; namespace { @@ -101,15 +108,37 @@ namespace { /// ensures the __tsan_init function is in the list of global constructors for /// the module. struct ThreadSanitizer { + ThreadSanitizer() { + // Sanity check options and warn user. + if (ClInstrumentReadBeforeWrite && ClCompoundReadBeforeWrite) { + errs() + << "warning: Option -tsan-compound-read-before-write has no effect " + "when -tsan-instrument-read-before-write is set.\n"; + } + } + bool sanitizeFunction(Function &F, const TargetLibraryInfo &TLI); private: + // Internal Instruction wrapper that contains more information about the + // Instruction from prior analysis. + struct InstructionInfo { + // Instrumentation emitted for this instruction is for a compounded set of + // read and write operations in the same basic block. + static constexpr unsigned kCompoundRW = (1U << 0); + + explicit InstructionInfo(Instruction *Inst) : Inst(Inst) {} + + Instruction *Inst; + unsigned Flags = 0; + }; + void initialize(Module &M); - bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL); + bool instrumentLoadOrStore(const InstructionInfo &II, const DataLayout &DL); bool instrumentAtomic(Instruction *I, const DataLayout &DL); bool instrumentMemIntrinsic(Instruction *I); void chooseInstructionsToInstrument(SmallVectorImpl &Local, - SmallVectorImpl &All, + SmallVectorImpl &All, const DataLayout &DL); bool addrPointsToConstantData(Value *Addr); int getMemoryAccessFuncIndex(Value *Addr, const DataLayout &DL); @@ -130,6 +159,8 @@ private: FunctionCallee TsanVolatileWrite[kNumberOfAccessSizes]; FunctionCallee TsanUnalignedVolatileRead[kNumberOfAccessSizes]; FunctionCallee TsanUnalignedVolatileWrite[kNumberOfAccessSizes]; + FunctionCallee TsanCompoundRW[kNumberOfAccessSizes]; + FunctionCallee TsanUnalignedCompoundRW[kNumberOfAccessSizes]; FunctionCallee TsanAtomicLoad[kNumberOfAccessSizes]; FunctionCallee TsanAtomicStore[kNumberOfAccessSizes]; FunctionCallee TsanAtomicRMW[AtomicRMWInst::LAST_BINOP + 1] @@ -268,6 +299,15 @@ void ThreadSanitizer::initialize(Module &M) { TsanUnalignedVolatileWrite[i] = M.getOrInsertFunction( UnalignedVolatileWriteName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); + SmallString<64> CompoundRWName("__tsan_read_write" + ByteSizeStr); + TsanCompoundRW[i] = M.getOrInsertFunction( + CompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); + + SmallString<64> UnalignedCompoundRWName("__tsan_unaligned_read_write" + + ByteSizeStr); + TsanUnalignedCompoundRW[i] = M.getOrInsertFunction( + UnalignedCompoundRWName, Attr, IRB.getVoidTy(), IRB.getInt8PtrTy()); + Type *Ty = Type::getIntNTy(M.getContext(), BitSize); Type *PtrTy = Ty->getPointerTo(); SmallString<32> AtomicLoadName("__tsan_atomic" + BitSizeStr + "_load"); @@ -402,35 +442,43 @@ bool ThreadSanitizer::addrPointsToConstantData(Value *Addr) { // 'Local' is a vector of insns within the same BB (no calls between). // 'All' is a vector of insns that will be instrumented. void ThreadSanitizer::chooseInstructionsToInstrument( - SmallVectorImpl &Local, SmallVectorImpl &All, - const DataLayout &DL) { - SmallPtrSet WriteTargets; + SmallVectorImpl &Local, + SmallVectorImpl &All, const DataLayout &DL) { + DenseMap WriteTargets; // Map of addresses to index in All // Iterate from the end. for (Instruction *I : reverse(Local)) { - if (StoreInst *Store = dyn_cast(I)) { - Value *Addr = Store->getPointerOperand(); - if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr)) - continue; - WriteTargets.insert(Addr); - } else { - LoadInst *Load = cast(I); - Value *Addr = Load->getPointerOperand(); - if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr)) - continue; - if (!ClInstrumentReadBeforeWrite && WriteTargets.count(Addr)) { - // We will write to this temp, so no reason to analyze the read. - NumOmittedReadsBeforeWrite++; - continue; + const bool IsWrite = isa(*I); + Value *Addr = IsWrite ? cast(I)->getPointerOperand() + : cast(I)->getPointerOperand(); + + if (!shouldInstrumentReadWriteFromAddress(I->getModule(), Addr)) + continue; + + if (!IsWrite) { + const auto WriteEntry = WriteTargets.find(Addr); + if (!ClInstrumentReadBeforeWrite && WriteEntry != WriteTargets.end()) { + auto &WI = All[WriteEntry->second]; + // If we distinguish volatile accesses and if either the read or write + // is volatile, do not omit any instrumentation. + const bool AnyVolatile = + ClDistinguishVolatile && (cast(I)->isVolatile() || + cast(WI.Inst)->isVolatile()); + if (!AnyVolatile) { + // We will write to this temp, so no reason to analyze the read. + // Mark the write instruction as compound. + WI.Flags |= InstructionInfo::kCompoundRW; + NumOmittedReadsBeforeWrite++; + continue; + } } + if (addrPointsToConstantData(Addr)) { // Addr points to some constant data -- it can not race with any writes. continue; } } - Value *Addr = isa(*I) - ? cast(I)->getPointerOperand() - : cast(I)->getPointerOperand(); - if (isa(GetUnderlyingObject(Addr, DL)) && + + if (isa(getUnderlyingObject(Addr)) && !PointerMayBeCaptured(Addr, true, true)) { // The variable is addressable but not captured, so it cannot be // referenced from a different thread and participate in a data race @@ -438,7 +486,14 @@ void ThreadSanitizer::chooseInstructionsToInstrument( NumOmittedNonCaptured++; continue; } - All.push_back(I); + + // Instrument this instruction. + All.emplace_back(I); + if (IsWrite) { + // For read-before-write and compound instrumentation we only need one + // write target, and we can override any previous entry if it exists. + WriteTargets[Addr] = All.size() - 1; + } } Local.clear(); } @@ -479,7 +534,7 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, if (F.hasFnAttribute(Attribute::Naked)) return false; initialize(*F.getParent()); - SmallVector AllLoadsAndStores; + SmallVector AllLoadsAndStores; SmallVector LocalLoadsAndStores; SmallVector AtomicAccesses; SmallVector MemIntrinCalls; @@ -514,8 +569,8 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, // Instrument memory accesses only if we want to report bugs in the function. if (ClInstrumentMemoryAccesses && SanitizeFunction) - for (auto Inst : AllLoadsAndStores) { - Res |= instrumentLoadOrStore(Inst, DL); + for (const auto &II : AllLoadsAndStores) { + Res |= instrumentLoadOrStore(II, DL); } // Instrument atomic memory accesses in any case (they can be used to @@ -553,13 +608,12 @@ bool ThreadSanitizer::sanitizeFunction(Function &F, return Res; } -bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I, +bool ThreadSanitizer::instrumentLoadOrStore(const InstructionInfo &II, const DataLayout &DL) { - IRBuilder<> IRB(I); - bool IsWrite = isa(*I); - Value *Addr = IsWrite - ? cast(I)->getPointerOperand() - : cast(I)->getPointerOperand(); + IRBuilder<> IRB(II.Inst); + const bool IsWrite = isa(*II.Inst); + Value *Addr = IsWrite ? cast(II.Inst)->getPointerOperand() + : cast(II.Inst)->getPointerOperand(); // swifterror memory addresses are mem2reg promoted by instruction selection. // As such they cannot have regular uses like an instrumentation function and @@ -570,9 +624,9 @@ bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I, int Idx = getMemoryAccessFuncIndex(Addr, DL); if (Idx < 0) return false; - if (IsWrite && isVtableAccess(I)) { - LLVM_DEBUG(dbgs() << " VPTR : " << *I << "\n"); - Value *StoredValue = cast(I)->getValueOperand(); + if (IsWrite && isVtableAccess(II.Inst)) { + LLVM_DEBUG(dbgs() << " VPTR : " << *II.Inst << "\n"); + Value *StoredValue = cast(II.Inst)->getValueOperand(); // StoredValue may be a vector type if we are storing several vptrs at once. // In this case, just take the first element of the vector since this is // enough to find vptr races. @@ -588,36 +642,46 @@ bool ThreadSanitizer::instrumentLoadOrStore(Instruction *I, NumInstrumentedVtableWrites++; return true; } - if (!IsWrite && isVtableAccess(I)) { + if (!IsWrite && isVtableAccess(II.Inst)) { IRB.CreateCall(TsanVptrLoad, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); NumInstrumentedVtableReads++; return true; } - const unsigned Alignment = IsWrite - ? cast(I)->getAlignment() - : cast(I)->getAlignment(); - const bool IsVolatile = - ClDistinguishVolatile && (IsWrite ? cast(I)->isVolatile() - : cast(I)->isVolatile()); + + const unsigned Alignment = IsWrite ? cast(II.Inst)->getAlignment() + : cast(II.Inst)->getAlignment(); + const bool IsCompoundRW = + ClCompoundReadBeforeWrite && (II.Flags & InstructionInfo::kCompoundRW); + const bool IsVolatile = ClDistinguishVolatile && + (IsWrite ? cast(II.Inst)->isVolatile() + : cast(II.Inst)->isVolatile()); + assert((!IsVolatile || !IsCompoundRW) && "Compound volatile invalid!"); + Type *OrigTy = cast(Addr->getType())->getElementType(); const uint32_t TypeSize = DL.getTypeStoreSizeInBits(OrigTy); FunctionCallee OnAccessFunc = nullptr; if (Alignment == 0 || Alignment >= 8 || (Alignment % (TypeSize / 8)) == 0) { - if (IsVolatile) + if (IsCompoundRW) + OnAccessFunc = TsanCompoundRW[Idx]; + else if (IsVolatile) OnAccessFunc = IsWrite ? TsanVolatileWrite[Idx] : TsanVolatileRead[Idx]; else OnAccessFunc = IsWrite ? TsanWrite[Idx] : TsanRead[Idx]; } else { - if (IsVolatile) + if (IsCompoundRW) + OnAccessFunc = TsanUnalignedCompoundRW[Idx]; + else if (IsVolatile) OnAccessFunc = IsWrite ? TsanUnalignedVolatileWrite[Idx] : TsanUnalignedVolatileRead[Idx]; else OnAccessFunc = IsWrite ? TsanUnalignedWrite[Idx] : TsanUnalignedRead[Idx]; } IRB.CreateCall(OnAccessFunc, IRB.CreatePointerCast(Addr, IRB.getInt8PtrTy())); - if (IsWrite) NumInstrumentedWrites++; - else NumInstrumentedReads++; + if (IsCompoundRW || IsWrite) + NumInstrumentedWrites++; + if (IsCompoundRW || !IsWrite) + NumInstrumentedReads++; return true; } diff --git a/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.cpp b/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.cpp index cd4f636ff132..fb6216bb2177 100644 --- a/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.cpp +++ b/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.cpp @@ -11,10 +11,10 @@ //===----------------------------------------------------------------------===// #include "ValueProfilePlugins.inc" +#include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/InitializePasses.h" - #include using namespace llvm; diff --git a/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.h b/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.h index c3f549c2e7cc..584a60ab451e 100644 --- a/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.h +++ b/llvm/lib/Transforms/Instrumentation/ValueProfileCollector.h @@ -17,13 +17,16 @@ #define LLVM_ANALYSIS_PROFILE_GEN_ANALYSIS_H #include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/PassManager.h" -#include "llvm/Pass.h" #include "llvm/ProfileData/InstrProf.h" +#include +#include namespace llvm { +class Function; +class Instruction; +class Value; + /// Utility analysis that determines what values are worth profiling. /// The actual logic is inside the ValueProfileCollectorImpl, whose job is to /// populate the Candidates vector. diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp index 46bc586fe688..7f7f2dc89b7e 100644 --- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp +++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.cpp @@ -22,6 +22,7 @@ #include "DependencyAnalysis.h" #include "ObjCARC.h" #include "ProvenanceAnalysis.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/CFG.h" using namespace llvm; @@ -51,10 +52,8 @@ bool llvm::objcarc::CanAlterRefCount(const Instruction *Inst, const Value *Ptr, if (AliasAnalysis::onlyReadsMemory(MRB)) return false; if (AliasAnalysis::onlyAccessesArgPointees(MRB)) { - const DataLayout &DL = Inst->getModule()->getDataLayout(); for (const Value *Op : Call->args()) { - if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && - PA.related(Ptr, Op, DL)) + if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op)) return true; } return false; @@ -85,8 +84,6 @@ bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr, if (Class == ARCInstKind::Call) return false; - const DataLayout &DL = Inst->getModule()->getDataLayout(); - // Consider various instructions which may have pointer arguments which are // not "uses". if (const ICmpInst *ICI = dyn_cast(Inst)) { @@ -99,26 +96,24 @@ bool llvm::objcarc::CanUse(const Instruction *Inst, const Value *Ptr, // For calls, just check the arguments (and not the callee operand). for (auto OI = CS->arg_begin(), OE = CS->arg_end(); OI != OE; ++OI) { const Value *Op = *OI; - if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && - PA.related(Ptr, Op, DL)) + if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op)) return true; } return false; } else if (const StoreInst *SI = dyn_cast(Inst)) { // Special-case stores, because we don't care about the stored value, just // the store address. - const Value *Op = GetUnderlyingObjCPtr(SI->getPointerOperand(), DL); + const Value *Op = GetUnderlyingObjCPtr(SI->getPointerOperand()); // If we can't tell what the underlying object was, assume there is a // dependence. - return IsPotentialRetainableObjPtr(Op, *PA.getAA()) && - PA.related(Op, Ptr, DL); + return IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Op, Ptr); } // Check each operand for a match. for (User::const_op_iterator OI = Inst->op_begin(), OE = Inst->op_end(); OI != OE; ++OI) { const Value *Op = *OI; - if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op, DL)) + if (IsPotentialRetainableObjPtr(Op, *PA.getAA()) && PA.related(Ptr, Op)) return true; } return false; @@ -214,15 +209,13 @@ llvm::objcarc::Depends(DependenceKind Flavor, Instruction *Inst, /// non-local dependencies on Arg. /// /// TODO: Cache results? -void -llvm::objcarc::FindDependencies(DependenceKind Flavor, - const Value *Arg, - BasicBlock *StartBB, Instruction *StartInst, - SmallPtrSetImpl &DependingInsts, - SmallPtrSetImpl &Visited, - ProvenanceAnalysis &PA) { +static bool findDependencies(DependenceKind Flavor, const Value *Arg, + BasicBlock *StartBB, Instruction *StartInst, + SmallPtrSetImpl &DependingInsts, + ProvenanceAnalysis &PA) { BasicBlock::iterator StartPos = StartInst->getIterator(); + SmallPtrSet Visited; SmallVector, 4> Worklist; Worklist.push_back(std::make_pair(StartBB, StartPos)); do { @@ -235,15 +228,14 @@ llvm::objcarc::FindDependencies(DependenceKind Flavor, if (LocalStartPos == StartBBBegin) { pred_iterator PI(LocalStartBB), PE(LocalStartBB, false); if (PI == PE) - // If we've reached the function entry, produce a null dependence. - DependingInsts.insert(nullptr); - else - // Add the predecessors to the worklist. - do { - BasicBlock *PredBB = *PI; - if (Visited.insert(PredBB).second) - Worklist.push_back(std::make_pair(PredBB, PredBB->end())); - } while (++PI != PE); + // Return if we've reached the function entry. + return false; + // Add the predecessors to the worklist. + do { + BasicBlock *PredBB = *PI; + if (Visited.insert(PredBB).second) + Worklist.push_back(std::make_pair(PredBB, PredBB->end())); + } while (++PI != PE); break; } @@ -262,9 +254,22 @@ llvm::objcarc::FindDependencies(DependenceKind Flavor, if (BB == StartBB) continue; for (const BasicBlock *Succ : successors(BB)) - if (Succ != StartBB && !Visited.count(Succ)) { - DependingInsts.insert(reinterpret_cast(-1)); - return; - } + if (Succ != StartBB && !Visited.count(Succ)) + return false; } + + return true; +} + +llvm::Instruction *llvm::objcarc::findSingleDependency(DependenceKind Flavor, + const Value *Arg, + BasicBlock *StartBB, + Instruction *StartInst, + ProvenanceAnalysis &PA) { + SmallPtrSet DependingInsts; + + if (!findDependencies(Flavor, Arg, StartBB, StartInst, DependingInsts, PA) || + DependingInsts.size() != 1) + return nullptr; + return *DependingInsts.begin(); } diff --git a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h index ed89c8c8fc89..cf4c05ebe91c 100644 --- a/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h +++ b/llvm/lib/Transforms/ObjCARC/DependencyAnalysis.h @@ -50,12 +50,12 @@ enum DependenceKind { RetainRVDep ///< Blocks objc_retainAutoreleasedReturnValue. }; -void FindDependencies(DependenceKind Flavor, - const Value *Arg, - BasicBlock *StartBB, Instruction *StartInst, - SmallPtrSetImpl &DependingInstructions, - SmallPtrSetImpl &Visited, - ProvenanceAnalysis &PA); +/// Find dependent instructions. If there is exactly one dependent instruction, +/// return it. Otherwise, return null. +llvm::Instruction *findSingleDependency(DependenceKind Flavor, const Value *Arg, + BasicBlock *StartBB, + Instruction *StartInst, + ProvenanceAnalysis &PA); bool Depends(DependenceKind Flavor, Instruction *Inst, const Value *Arg, diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp index f4da51650a7d..970136392fdd 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.cpp @@ -29,8 +29,8 @@ void llvm::initializeObjCARCOpts(PassRegistry &Registry) { initializeObjCARCAAWrapperPassPass(Registry); initializeObjCARCAPElimPass(Registry); initializeObjCARCExpandPass(Registry); - initializeObjCARCContractPass(Registry); - initializeObjCARCOptPass(Registry); + initializeObjCARCContractLegacyPassPass(Registry); + initializeObjCARCOptLegacyPassPass(Registry); initializePAEvalPass(Registry); } diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARC.h b/llvm/lib/Transforms/ObjCARC/ObjCARC.h index b496842fcfc5..8227a8c6f75f 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARC.h +++ b/llvm/lib/Transforms/ObjCARC/ObjCARC.h @@ -23,9 +23,7 @@ #define LLVM_LIB_TRANSFORMS_OBJCARC_OBJCARC_H #include "llvm/Analysis/ObjCARCAnalysisUtils.h" -#include "llvm/Analysis/ObjCARCInstKind.h" #include "llvm/Transforms/Utils/Local.h" -#include "llvm/Transforms/ObjCARC.h" namespace llvm { namespace objcarc { diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp index ac1db27f5e64..6a928f2c7ffb 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp @@ -26,9 +26,11 @@ #include "ObjCARC.h" #include "llvm/ADT/STLExtras.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/ObjCARC.h" using namespace llvm; using namespace llvm::objcarc; @@ -36,39 +38,10 @@ using namespace llvm::objcarc; #define DEBUG_TYPE "objc-arc-ap-elim" namespace { - /// Autorelease pool elimination. - class ObjCARCAPElim : public ModulePass { - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool runOnModule(Module &M) override; - - static bool MayAutorelease(const CallBase &CB, unsigned Depth = 0); - static bool OptimizeBB(BasicBlock *BB); - - public: - static char ID; - ObjCARCAPElim() : ModulePass(ID) { - initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry()); - } - }; -} - -char ObjCARCAPElim::ID = 0; -INITIALIZE_PASS(ObjCARCAPElim, - "objc-arc-apelim", - "ObjC ARC autorelease pool elimination", - false, false) - -Pass *llvm::createObjCARCAPElimPass() { - return new ObjCARCAPElim(); -} - -void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); -} /// Interprocedurally determine if calls made by the given call site can /// possibly produce autoreleases. -bool ObjCARCAPElim::MayAutorelease(const CallBase &CB, unsigned Depth) { +bool MayAutorelease(const CallBase &CB, unsigned Depth = 0) { if (const Function *Callee = CB.getCalledFunction()) { if (!Callee->hasExactDefinition()) return true; @@ -87,7 +60,7 @@ bool ObjCARCAPElim::MayAutorelease(const CallBase &CB, unsigned Depth) { return true; } -bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) { +bool OptimizeBB(BasicBlock *BB) { bool Changed = false; Instruction *Push = nullptr; @@ -125,17 +98,13 @@ bool ObjCARCAPElim::OptimizeBB(BasicBlock *BB) { return Changed; } -bool ObjCARCAPElim::runOnModule(Module &M) { +bool runImpl(Module &M) { if (!EnableARCOpts) return false; // If nothing in the Module uses ARC, don't do anything. if (!ModuleHasARC(M)) return false; - - if (skipModule(M)) - return false; - // Find the llvm.global_ctors variable, as the first step in // identifying the global constructors. In theory, unnecessary autorelease // pools could occur anywhere, but in practice it's pretty rare. Global @@ -175,3 +144,40 @@ bool ObjCARCAPElim::runOnModule(Module &M) { return Changed; } + +/// Autorelease pool elimination. +class ObjCARCAPElim : public ModulePass { + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnModule(Module &M) override; + +public: + static char ID; + ObjCARCAPElim() : ModulePass(ID) { + initializeObjCARCAPElimPass(*PassRegistry::getPassRegistry()); + } +}; +} // namespace + +char ObjCARCAPElim::ID = 0; +INITIALIZE_PASS(ObjCARCAPElim, "objc-arc-apelim", + "ObjC ARC autorelease pool elimination", false, false) + +Pass *llvm::createObjCARCAPElimPass() { return new ObjCARCAPElim(); } + +void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); +} + +bool ObjCARCAPElim::runOnModule(Module &M) { + if (skipModule(M)) + return false; + return runImpl(M); +} + +PreservedAnalyses ObjCARCAPElimPass::run(Module &M, ModuleAnalysisManager &AM) { + if (!runImpl(M)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp index 7fd4857c4490..86d161116e8c 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -30,15 +30,18 @@ #include "ObjCARC.h" #include "ProvenanceAnalysis.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/InlineAsm.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/ObjCARC.h" using namespace llvm; using namespace llvm::objcarc; @@ -53,59 +56,63 @@ STATISTIC(NumStoreStrongs, "Number objc_storeStrong calls formed"); //===----------------------------------------------------------------------===// namespace { - /// Late ARC optimizations - /// - /// These change the IR in a way that makes it difficult to be analyzed by - /// ObjCARCOpt, so it's run late. - class ObjCARCContract : public FunctionPass { - bool Changed; - AliasAnalysis *AA; - DominatorTree *DT; - ProvenanceAnalysis PA; - ARCRuntimeEntryPoints EP; - - /// A flag indicating whether this optimization pass should run. - bool Run; - - /// The inline asm string to insert between calls and RetainRV calls to make - /// the optimization work on targets which need it. - const MDString *RVInstMarker; - - /// The set of inserted objc_storeStrong calls. If at the end of walking the - /// function we have found no alloca instructions, these calls can be marked - /// "tail". - SmallPtrSet StoreStrongCalls; - - /// Returns true if we eliminated Inst. - bool tryToPeepholeInstruction( - Function &F, Instruction *Inst, inst_iterator &Iter, - SmallPtrSetImpl &DepInsts, - SmallPtrSetImpl &Visited, - bool &TailOkForStoreStrong, - const DenseMap &BlockColors); - - bool optimizeRetainCall(Function &F, Instruction *Retain); - - bool - contractAutorelease(Function &F, Instruction *Autorelease, - ARCInstKind Class, - SmallPtrSetImpl &DependingInstructions, - SmallPtrSetImpl &Visited); - - void tryToContractReleaseIntoStoreStrong( - Instruction *Release, inst_iterator &Iter, - const DenseMap &BlockColors); - - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool doInitialization(Module &M) override; - bool runOnFunction(Function &F) override; - - public: - static char ID; - ObjCARCContract() : FunctionPass(ID) { - initializeObjCARCContractPass(*PassRegistry::getPassRegistry()); - } - }; +/// Late ARC optimizations +/// +/// These change the IR in a way that makes it difficult to be analyzed by +/// ObjCARCOpt, so it's run late. + +class ObjCARCContract { + bool Changed; + AAResults *AA; + DominatorTree *DT; + ProvenanceAnalysis PA; + ARCRuntimeEntryPoints EP; + + /// A flag indicating whether this optimization pass should run. + bool Run; + + /// The inline asm string to insert between calls and RetainRV calls to make + /// the optimization work on targets which need it. + const MDString *RVInstMarker; + + /// The set of inserted objc_storeStrong calls. If at the end of walking the + /// function we have found no alloca instructions, these calls can be marked + /// "tail". + SmallPtrSet StoreStrongCalls; + + /// Returns true if we eliminated Inst. + bool tryToPeepholeInstruction( + Function &F, Instruction *Inst, inst_iterator &Iter, + bool &TailOkForStoreStrong, + const DenseMap &BlockColors); + + bool optimizeRetainCall(Function &F, Instruction *Retain); + + bool contractAutorelease(Function &F, Instruction *Autorelease, + ARCInstKind Class); + + void tryToContractReleaseIntoStoreStrong( + Instruction *Release, inst_iterator &Iter, + const DenseMap &BlockColors); + +public: + bool init(Module &M); + bool run(Function &F, AAResults *AA, DominatorTree *DT); +}; + +class ObjCARCContractLegacyPass : public FunctionPass { + ObjCARCContract OCARCC; + +public: + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool doInitialization(Module &M) override; + bool runOnFunction(Function &F) override; + + static char ID; + ObjCARCContractLegacyPass() : FunctionPass(ID) { + initializeObjCARCContractLegacyPassPass(*PassRegistry::getPassRegistry()); + } +}; } //===----------------------------------------------------------------------===// @@ -149,32 +156,17 @@ bool ObjCARCContract::optimizeRetainCall(Function &F, Instruction *Retain) { } /// Merge an autorelease with a retain into a fused call. -bool ObjCARCContract::contractAutorelease( - Function &F, Instruction *Autorelease, ARCInstKind Class, - SmallPtrSetImpl &DependingInstructions, - SmallPtrSetImpl &Visited) { +bool ObjCARCContract::contractAutorelease(Function &F, Instruction *Autorelease, + ARCInstKind Class) { const Value *Arg = GetArgRCIdentityRoot(Autorelease); // Check that there are no instructions between the retain and the autorelease // (such as an autorelease_pop) which may change the count. - CallInst *Retain = nullptr; - if (Class == ARCInstKind::AutoreleaseRV) - FindDependencies(RetainAutoreleaseRVDep, Arg, - Autorelease->getParent(), Autorelease, - DependingInstructions, Visited, PA); - else - FindDependencies(RetainAutoreleaseDep, Arg, - Autorelease->getParent(), Autorelease, - DependingInstructions, Visited, PA); - - Visited.clear(); - if (DependingInstructions.size() != 1) { - DependingInstructions.clear(); - return false; - } - - Retain = dyn_cast_or_null(*DependingInstructions.begin()); - DependingInstructions.clear(); + DependenceKind DK = Class == ARCInstKind::AutoreleaseRV + ? RetainAutoreleaseRVDep + : RetainAutoreleaseDep; + auto *Retain = dyn_cast_or_null( + findSingleDependency(DK, Arg, Autorelease->getParent(), Autorelease, PA)); if (!Retain || GetBasicARCInstKind(Retain) != ARCInstKind::Retain || GetArgRCIdentityRoot(Retain) != Arg) @@ -204,7 +196,7 @@ bool ObjCARCContract::contractAutorelease( static StoreInst *findSafeStoreForStoreStrongContraction(LoadInst *Load, Instruction *Release, ProvenanceAnalysis &PA, - AliasAnalysis *AA) { + AAResults *AA) { StoreInst *Store = nullptr; bool SawRelease = false; @@ -442,8 +434,7 @@ void ObjCARCContract::tryToContractReleaseIntoStoreStrong( bool ObjCARCContract::tryToPeepholeInstruction( Function &F, Instruction *Inst, inst_iterator &Iter, - SmallPtrSetImpl &DependingInsts, - SmallPtrSetImpl &Visited, bool &TailOkForStoreStrongs, + bool &TailOkForStoreStrongs, const DenseMap &BlockColors) { // Only these library routines return their argument. In particular, // objc_retainBlock does not necessarily return its argument. @@ -454,7 +445,7 @@ bool ObjCARCContract::tryToPeepholeInstruction( return false; case ARCInstKind::Autorelease: case ARCInstKind::AutoreleaseRV: - return contractAutorelease(F, Inst, Class, DependingInsts, Visited); + return contractAutorelease(F, Inst, Class); case ARCInstKind::Retain: // Attempt to convert retains to retainrvs if they are next to function // calls. @@ -485,7 +476,7 @@ bool ObjCARCContract::tryToPeepholeInstruction( --BBI; } while (IsNoopInstruction(&*BBI)); - if (&*BBI == GetArgRCIdentityRoot(Inst)) { + if (GetRCIdentityRoot(&*BBI) == GetArgRCIdentityRoot(Inst)) { LLVM_DEBUG(dbgs() << "Adding inline asm marker for the return value " "optimization.\n"); Changed = true; @@ -542,7 +533,22 @@ bool ObjCARCContract::tryToPeepholeInstruction( // Top Level Driver //===----------------------------------------------------------------------===// -bool ObjCARCContract::runOnFunction(Function &F) { +bool ObjCARCContract::init(Module &M) { + // If nothing in the Module uses ARC, don't do anything. + Run = ModuleHasARC(M); + if (!Run) + return false; + + EP.init(&M); + + // Initialize RVInstMarker. + const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker"; + RVInstMarker = dyn_cast_or_null(M.getModuleFlag(MarkerKey)); + + return false; +} + +bool ObjCARCContract::run(Function &F, AAResults *A, DominatorTree *D) { if (!EnableARCOpts) return false; @@ -551,10 +557,9 @@ bool ObjCARCContract::runOnFunction(Function &F) { return false; Changed = false; - AA = &getAnalysis().getAAResults(); - DT = &getAnalysis().getDomTree(); - - PA.setAA(&getAnalysis().getAAResults()); + AA = A; + DT = D; + PA.setAA(A); DenseMap BlockColors; if (F.hasPersonalityFn() && @@ -574,9 +579,6 @@ bool ObjCARCContract::runOnFunction(Function &F) { // For ObjC library calls which return their argument, replace uses of the // argument with uses of the call return value, if it dominates the use. This // reduces register pressure. - SmallPtrSet DependingInstructions; - SmallPtrSet Visited; - for (inst_iterator I = inst_begin(&F), E = inst_end(&F); I != E;) { Instruction *Inst = &*I++; @@ -584,8 +586,8 @@ bool ObjCARCContract::runOnFunction(Function &F) { // First try to peephole Inst. If there is nothing further we can do in // terms of undoing objc-arc-expand, process the next inst. - if (tryToPeepholeInstruction(F, Inst, I, DependingInstructions, Visited, - TailOkForStoreStrongs, BlockColors)) + if (tryToPeepholeInstruction(F, Inst, I, TailOkForStoreStrongs, + BlockColors)) continue; // Otherwise, try to undo objc-arc-expand. @@ -720,33 +722,45 @@ bool ObjCARCContract::runOnFunction(Function &F) { // Misc Pass Manager //===----------------------------------------------------------------------===// -char ObjCARCContract::ID = 0; -INITIALIZE_PASS_BEGIN(ObjCARCContract, "objc-arc-contract", +char ObjCARCContractLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(ObjCARCContractLegacyPass, "objc-arc-contract", "ObjC ARC contraction", false, false) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) -INITIALIZE_PASS_END(ObjCARCContract, "objc-arc-contract", +INITIALIZE_PASS_END(ObjCARCContractLegacyPass, "objc-arc-contract", "ObjC ARC contraction", false, false) -void ObjCARCContract::getAnalysisUsage(AnalysisUsage &AU) const { +void ObjCARCContractLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); AU.setPreservesCFG(); } -Pass *llvm::createObjCARCContractPass() { return new ObjCARCContract(); } - -bool ObjCARCContract::doInitialization(Module &M) { - // If nothing in the Module uses ARC, don't do anything. - Run = ModuleHasARC(M); - if (!Run) - return false; +Pass *llvm::createObjCARCContractPass() { + return new ObjCARCContractLegacyPass(); +} - EP.init(&M); +bool ObjCARCContractLegacyPass::doInitialization(Module &M) { + return OCARCC.init(M); +} - // Initialize RVInstMarker. - const char *MarkerKey = "clang.arc.retainAutoreleasedReturnValueMarker"; - RVInstMarker = dyn_cast_or_null(M.getModuleFlag(MarkerKey)); +bool ObjCARCContractLegacyPass::runOnFunction(Function &F) { + auto *AA = &getAnalysis().getAAResults(); + auto *DT = &getAnalysis().getDomTree(); + return OCARCC.run(F, AA, DT); +} - return false; +PreservedAnalyses ObjCARCContractPass::run(Function &F, + FunctionAnalysisManager &AM) { + ObjCARCContract OCAC; + OCAC.init(*F.getParent()); + + bool Changed = OCAC.run(F, &AM.getResult(F), + &AM.getResult(F)); + if (Changed) { + PreservedAnalyses PA; + PA.preserveSet(); + return PA; + } + return PreservedAnalyses::all(); } diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp index f8d872a7c995..d2121dcebe91 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCExpand.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Value.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -34,57 +35,20 @@ #include "llvm/Support/Casting.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/ObjCARC.h" #define DEBUG_TYPE "objc-arc-expand" -namespace llvm { - class Module; -} - using namespace llvm; using namespace llvm::objcarc; namespace { - /// Early ARC transformations. - class ObjCARCExpand : public FunctionPass { - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool doInitialization(Module &M) override; - bool runOnFunction(Function &F) override; - - /// A flag indicating whether this optimization pass should run. - bool Run; - - public: - static char ID; - ObjCARCExpand() : FunctionPass(ID) { - initializeObjCARCExpandPass(*PassRegistry::getPassRegistry()); - } - }; -} - -char ObjCARCExpand::ID = 0; -INITIALIZE_PASS(ObjCARCExpand, - "objc-arc-expand", "ObjC ARC expansion", false, false) - -Pass *llvm::createObjCARCExpandPass() { - return new ObjCARCExpand(); -} - -void ObjCARCExpand::getAnalysisUsage(AnalysisUsage &AU) const { - AU.setPreservesCFG(); -} - -bool ObjCARCExpand::doInitialization(Module &M) { - Run = ModuleHasARC(M); - return false; -} - -bool ObjCARCExpand::runOnFunction(Function &F) { +static bool runImpl(Function &F) { if (!EnableARCOpts) return false; // If nothing in the Module uses ARC, don't do anything. - if (!Run) + if (!ModuleHasARC(*F.getParent())) return false; bool Changed = false; @@ -126,3 +90,37 @@ bool ObjCARCExpand::runOnFunction(Function &F) { return Changed; } + +/// Early ARC transformations. +class ObjCARCExpand : public FunctionPass { + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool runOnFunction(Function &F) override; + +public: + static char ID; + ObjCARCExpand() : FunctionPass(ID) { + initializeObjCARCExpandPass(*PassRegistry::getPassRegistry()); + } +}; +} // namespace + +char ObjCARCExpand::ID = 0; +INITIALIZE_PASS(ObjCARCExpand, "objc-arc-expand", "ObjC ARC expansion", false, + false) + +Pass *llvm::createObjCARCExpandPass() { return new ObjCARCExpand(); } + +void ObjCARCExpand::getAnalysisUsage(AnalysisUsage &AU) const { + AU.setPreservesCFG(); +} + +bool ObjCARCExpand::runOnFunction(Function &F) { return runImpl(F); } + +PreservedAnalyses ObjCARCExpandPass::run(Function &F, + FunctionAnalysisManager &AM) { + if (!runImpl(F)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp index cb1fa804fa11..1c447499519c 100644 --- a/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp +++ b/llvm/lib/Transforms/ObjCARC/ObjCARCOpts.cpp @@ -65,6 +65,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/ObjCARC.h" #include #include #include @@ -480,123 +481,133 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, BBState &BBInfo) { namespace { /// The main ARC optimization pass. - class ObjCARCOpt : public FunctionPass { - bool Changed; - ProvenanceAnalysis PA; - - /// A cache of references to runtime entry point constants. - ARCRuntimeEntryPoints EP; - - /// A cache of MDKinds that can be passed into other functions to propagate - /// MDKind identifiers. - ARCMDKindCache MDKindCache; - - /// A flag indicating whether this optimization pass should run. - bool Run; - - /// A flag indicating whether the optimization that removes or moves - /// retain/release pairs should be performed. - bool DisableRetainReleasePairing = false; - - /// Flags which determine whether each of the interesting runtime functions - /// is in fact used in the current function. - unsigned UsedInThisFunction; - - bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV); - void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV, - ARCInstKind &Class); - void OptimizeIndividualCalls(Function &F); - - /// Optimize an individual call, optionally passing the - /// GetArgRCIdentityRoot if it has already been computed. - void OptimizeIndividualCallImpl( - Function &F, DenseMap &BlockColors, - Instruction *Inst, ARCInstKind Class, const Value *Arg); - - /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the - /// optimization occurs, returns true to indicate that the caller should - /// assume the instructions are dead. - bool OptimizeInlinedAutoreleaseRVCall( - Function &F, DenseMap &BlockColors, - Instruction *Inst, const Value *&Arg, ARCInstKind Class, - Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg); - - void CheckForCFGHazards(const BasicBlock *BB, - DenseMap &BBStates, - BBState &MyStates) const; - bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB, - BlotMapVector &Retains, - BBState &MyStates); - bool VisitBottomUp(BasicBlock *BB, - DenseMap &BBStates, - BlotMapVector &Retains); - bool VisitInstructionTopDown(Instruction *Inst, - DenseMap &Releases, - BBState &MyStates); - bool VisitTopDown(BasicBlock *BB, - DenseMap &BBStates, - DenseMap &Releases); - bool Visit(Function &F, DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases); - - void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, - BlotMapVector &Retains, - DenseMap &Releases, - SmallVectorImpl &DeadInsts, Module *M); - - bool - PairUpRetainsAndReleases(DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases, Module *M, - Instruction * Retain, - SmallVectorImpl &DeadInsts, - RRInfo &RetainsToMove, RRInfo &ReleasesToMove, - Value *Arg, bool KnownSafe, - bool &AnyPairsCompletelyEliminated); - - bool PerformCodePlacement(DenseMap &BBStates, - BlotMapVector &Retains, - DenseMap &Releases, Module *M); - - void OptimizeWeakCalls(Function &F); - - bool OptimizeSequences(Function &F); - - void OptimizeReturns(Function &F); +class ObjCARCOpt { + bool Changed; + ProvenanceAnalysis PA; + + /// A cache of references to runtime entry point constants. + ARCRuntimeEntryPoints EP; + + /// A cache of MDKinds that can be passed into other functions to propagate + /// MDKind identifiers. + ARCMDKindCache MDKindCache; + + /// A flag indicating whether this optimization pass should run. + bool Run; + + /// A flag indicating whether the optimization that removes or moves + /// retain/release pairs should be performed. + bool DisableRetainReleasePairing = false; + + /// Flags which determine whether each of the interesting runtime functions + /// is in fact used in the current function. + unsigned UsedInThisFunction; + + bool OptimizeRetainRVCall(Function &F, Instruction *RetainRV); + void OptimizeAutoreleaseRVCall(Function &F, Instruction *AutoreleaseRV, + ARCInstKind &Class); + void OptimizeIndividualCalls(Function &F); + + /// Optimize an individual call, optionally passing the + /// GetArgRCIdentityRoot if it has already been computed. + void OptimizeIndividualCallImpl( + Function &F, DenseMap &BlockColors, + Instruction *Inst, ARCInstKind Class, const Value *Arg); + + /// Try to optimize an AutoreleaseRV with a RetainRV or ClaimRV. If the + /// optimization occurs, returns true to indicate that the caller should + /// assume the instructions are dead. + bool OptimizeInlinedAutoreleaseRVCall( + Function &F, DenseMap &BlockColors, + Instruction *Inst, const Value *&Arg, ARCInstKind Class, + Instruction *AutoreleaseRV, const Value *&AutoreleaseRVArg); + + void CheckForCFGHazards(const BasicBlock *BB, + DenseMap &BBStates, + BBState &MyStates) const; + bool VisitInstructionBottomUp(Instruction *Inst, BasicBlock *BB, + BlotMapVector &Retains, + BBState &MyStates); + bool VisitBottomUp(BasicBlock *BB, + DenseMap &BBStates, + BlotMapVector &Retains); + bool VisitInstructionTopDown(Instruction *Inst, + DenseMap &Releases, + BBState &MyStates); + bool VisitTopDown(BasicBlock *BB, + DenseMap &BBStates, + DenseMap &Releases); + bool Visit(Function &F, DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases); + + void MoveCalls(Value *Arg, RRInfo &RetainsToMove, RRInfo &ReleasesToMove, + BlotMapVector &Retains, + DenseMap &Releases, + SmallVectorImpl &DeadInsts, Module *M); + + bool PairUpRetainsAndReleases(DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases, Module *M, + Instruction *Retain, + SmallVectorImpl &DeadInsts, + RRInfo &RetainsToMove, RRInfo &ReleasesToMove, + Value *Arg, bool KnownSafe, + bool &AnyPairsCompletelyEliminated); + + bool PerformCodePlacement(DenseMap &BBStates, + BlotMapVector &Retains, + DenseMap &Releases, Module *M); + + void OptimizeWeakCalls(Function &F); + + bool OptimizeSequences(Function &F); + + void OptimizeReturns(Function &F); #ifndef NDEBUG - void GatherStatistics(Function &F, bool AfterOptimization = false); + void GatherStatistics(Function &F, bool AfterOptimization = false); #endif - void getAnalysisUsage(AnalysisUsage &AU) const override; - bool doInitialization(Module &M) override; - bool runOnFunction(Function &F) override; - void releaseMemory() override; - public: - static char ID; - - ObjCARCOpt() : FunctionPass(ID) { - initializeObjCARCOptPass(*PassRegistry::getPassRegistry()); - } - }; + void init(Module &M); + bool run(Function &F, AAResults &AA); + void releaseMemory(); +}; + +/// The main ARC optimization pass. +class ObjCARCOptLegacyPass : public FunctionPass { +public: + ObjCARCOptLegacyPass() : FunctionPass(ID) { + initializeObjCARCOptLegacyPassPass(*PassRegistry::getPassRegistry()); + } + void getAnalysisUsage(AnalysisUsage &AU) const override; + bool doInitialization(Module &M) override { + OCAO.init(M); + return false; + } + bool runOnFunction(Function &F) override { + return OCAO.run(F, getAnalysis().getAAResults()); + } + void releaseMemory() override { OCAO.releaseMemory(); } + static char ID; +private: + ObjCARCOpt OCAO; +}; } // end anonymous namespace -char ObjCARCOpt::ID = 0; +char ObjCARCOptLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(ObjCARCOpt, - "objc-arc", "ObjC ARC optimization", false, false) +INITIALIZE_PASS_BEGIN(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization", + false, false) INITIALIZE_PASS_DEPENDENCY(ObjCARCAAWrapperPass) -INITIALIZE_PASS_END(ObjCARCOpt, - "objc-arc", "ObjC ARC optimization", false, false) +INITIALIZE_PASS_END(ObjCARCOptLegacyPass, "objc-arc", "ObjC ARC optimization", + false, false) -Pass *llvm::createObjCARCOptPass() { - return new ObjCARCOpt(); -} +Pass *llvm::createObjCARCOptPass() { return new ObjCARCOptLegacyPass(); } -void ObjCARCOpt::getAnalysisUsage(AnalysisUsage &AU) const { +void ObjCARCOptLegacyPass::getAnalysisUsage(AnalysisUsage &AU) const { AU.addRequired(); AU.addRequired(); // ARC optimization doesn't currently split critical edges. @@ -664,7 +675,7 @@ bool ObjCARCOpt::OptimizeInlinedAutoreleaseRVCall( SmallVector ArgUsers; getEquivalentPHIs(*PN, ArgUsers); - if (llvm::find(ArgUsers, AutoreleaseRVArg) == ArgUsers.end()) + if (!llvm::is_contained(ArgUsers, AutoreleaseRVArg)) return false; } @@ -1114,8 +1125,7 @@ void ObjCARCOpt::OptimizeIndividualCallImpl( if (!HasNull) continue; - SmallPtrSet DependingInstructions; - SmallPtrSet Visited; + Instruction *DepInst = nullptr; // Check that there is nothing that cares about the reference // count between the call and the phi. @@ -1127,13 +1137,13 @@ void ObjCARCOpt::OptimizeIndividualCallImpl( case ARCInstKind::Release: // These can't be moved across things that care about the retain // count. - FindDependencies(NeedsPositiveRetainCount, Arg, Inst->getParent(), Inst, - DependingInstructions, Visited, PA); + DepInst = findSingleDependency(NeedsPositiveRetainCount, Arg, + Inst->getParent(), Inst, PA); break; case ARCInstKind::Autorelease: // These can't be moved across autorelease pool scope boundaries. - FindDependencies(AutoreleasePoolBoundary, Arg, Inst->getParent(), Inst, - DependingInstructions, Visited, PA); + DepInst = findSingleDependency(AutoreleasePoolBoundary, Arg, + Inst->getParent(), Inst, PA); break; case ARCInstKind::ClaimRV: case ARCInstKind::RetainRV: @@ -1147,9 +1157,7 @@ void ObjCARCOpt::OptimizeIndividualCallImpl( llvm_unreachable("Invalid dependence flavor"); } - if (DependingInstructions.size() != 1) - continue; - if (*DependingInstructions.begin() != PN) + if (DepInst != PN) continue; Changed = true; @@ -2223,25 +2231,21 @@ bool ObjCARCOpt::OptimizeSequences(Function &F) { /// Check if there is a dependent call earlier that does not have anything in /// between the Retain and the call that can affect the reference count of their /// shared pointer argument. Note that Retain need not be in BB. -static bool -HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain, - SmallPtrSetImpl &DepInsts, - SmallPtrSetImpl &Visited, - ProvenanceAnalysis &PA) { - FindDependencies(CanChangeRetainCount, Arg, Retain->getParent(), Retain, - DepInsts, Visited, PA); - if (DepInsts.size() != 1) - return false; - - auto *Call = dyn_cast_or_null(*DepInsts.begin()); +static CallInst *HasSafePathToPredecessorCall(const Value *Arg, + Instruction *Retain, + ProvenanceAnalysis &PA) { + auto *Call = dyn_cast_or_null(findSingleDependency( + CanChangeRetainCount, Arg, Retain->getParent(), Retain, PA)); // Check that the pointer is the return value of the call. if (!Call || Arg != Call) - return false; + return nullptr; // Check that the call is a regular call. ARCInstKind Class = GetBasicARCInstKind(Call); - return Class == ARCInstKind::CallOrUser || Class == ARCInstKind::Call; + return Class == ARCInstKind::CallOrUser || Class == ARCInstKind::Call + ? Call + : nullptr; } /// Find a dependent retain that precedes the given autorelease for which there @@ -2250,15 +2254,9 @@ HasSafePathToPredecessorCall(const Value *Arg, Instruction *Retain, static CallInst * FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB, Instruction *Autorelease, - SmallPtrSetImpl &DepInsts, - SmallPtrSetImpl &Visited, ProvenanceAnalysis &PA) { - FindDependencies(CanChangeRetainCount, Arg, - BB, Autorelease, DepInsts, Visited, PA); - if (DepInsts.size() != 1) - return nullptr; - - auto *Retain = dyn_cast_or_null(*DepInsts.begin()); + auto *Retain = dyn_cast_or_null( + findSingleDependency(CanChangeRetainCount, Arg, BB, Autorelease, PA)); // Check that we found a retain with the same argument. if (!Retain || !IsRetain(GetBasicARCInstKind(Retain)) || @@ -2275,15 +2273,11 @@ FindPredecessorRetainWithSafePath(const Value *Arg, BasicBlock *BB, static CallInst * FindPredecessorAutoreleaseWithSafePath(const Value *Arg, BasicBlock *BB, ReturnInst *Ret, - SmallPtrSetImpl &DepInsts, - SmallPtrSetImpl &V, ProvenanceAnalysis &PA) { - FindDependencies(NeedsPositiveRetainCount, Arg, - BB, Ret, DepInsts, V, PA); - if (DepInsts.size() != 1) - return nullptr; + SmallPtrSet DepInsts; + auto *Autorelease = dyn_cast_or_null( + findSingleDependency(NeedsPositiveRetainCount, Arg, BB, Ret, PA)); - auto *Autorelease = dyn_cast_or_null(*DepInsts.begin()); if (!Autorelease) return nullptr; ARCInstKind AutoreleaseClass = GetBasicARCInstKind(Autorelease); @@ -2309,8 +2303,6 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { LLVM_DEBUG(dbgs() << "\n== ObjCARCOpt::OptimizeReturns ==\n"); - SmallPtrSet DependingInstructions; - SmallPtrSet Visited; for (BasicBlock &BB: F) { ReturnInst *Ret = dyn_cast(&BB.back()); if (!Ret) @@ -2323,40 +2315,27 @@ void ObjCARCOpt::OptimizeReturns(Function &F) { // Look for an ``autorelease'' instruction that is a predecessor of Ret and // dependent on Arg such that there are no instructions dependent on Arg // that need a positive ref count in between the autorelease and Ret. - CallInst *Autorelease = FindPredecessorAutoreleaseWithSafePath( - Arg, &BB, Ret, DependingInstructions, Visited, PA); - DependingInstructions.clear(); - Visited.clear(); + CallInst *Autorelease = + FindPredecessorAutoreleaseWithSafePath(Arg, &BB, Ret, PA); if (!Autorelease) continue; CallInst *Retain = FindPredecessorRetainWithSafePath( - Arg, Autorelease->getParent(), Autorelease, DependingInstructions, - Visited, PA); - DependingInstructions.clear(); - Visited.clear(); + Arg, Autorelease->getParent(), Autorelease, PA); if (!Retain) continue; // Check that there is nothing that can affect the reference count // between the retain and the call. Note that Retain need not be in BB. - bool HasSafePathToCall = HasSafePathToPredecessorCall(Arg, Retain, - DependingInstructions, - Visited, PA); + CallInst *Call = HasSafePathToPredecessorCall(Arg, Retain, PA); // Don't remove retainRV/autoreleaseRV pairs if the call isn't a tail call. - if (HasSafePathToCall && - GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV && - GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV && - !cast(*DependingInstructions.begin())->isTailCall()) - continue; - - DependingInstructions.clear(); - Visited.clear(); - - if (!HasSafePathToCall) + if (!Call || + (!Call->isTailCall() && + GetBasicARCInstKind(Retain) == ARCInstKind::RetainRV && + GetBasicARCInstKind(Autorelease) == ARCInstKind::AutoreleaseRV)) continue; // If so, we can zap the retain and autorelease. @@ -2393,14 +2372,14 @@ ObjCARCOpt::GatherStatistics(Function &F, bool AfterOptimization) { } #endif -bool ObjCARCOpt::doInitialization(Module &M) { +void ObjCARCOpt::init(Module &M) { if (!EnableARCOpts) - return false; + return; // If nothing in the Module uses ARC, don't do anything. Run = ModuleHasARC(M); if (!Run) - return false; + return; // Intuitively, objc_retain and others are nocapture, however in practice // they are not, because they return their argument value. And objc_release @@ -2409,11 +2388,9 @@ bool ObjCARCOpt::doInitialization(Module &M) { // Initialize our runtime entry point cache. EP.init(&M); - - return false; } -bool ObjCARCOpt::runOnFunction(Function &F) { +bool ObjCARCOpt::run(Function &F, AAResults &AA) { if (!EnableARCOpts) return false; @@ -2427,7 +2404,7 @@ bool ObjCARCOpt::runOnFunction(Function &F) { << " >>>" "\n"); - PA.setAA(&getAnalysis().getAAResults()); + PA.setAA(&AA); #ifndef NDEBUG if (AreStatisticsEnabled()) { @@ -2484,3 +2461,17 @@ void ObjCARCOpt::releaseMemory() { /// @} /// + +PreservedAnalyses ObjCARCOptPass::run(Function &F, + FunctionAnalysisManager &AM) { + ObjCARCOpt OCAO; + OCAO.init(*F.getParent()); + + bool Changed = OCAO.run(F, AM.getResult(F)); + if (Changed) { + PreservedAnalyses PA; + PA.preserveSet(); + return PA; + } + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp index c6138edba95a..3d59b2edc55c 100644 --- a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp +++ b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.cpp @@ -40,22 +40,19 @@ using namespace llvm::objcarc; bool ProvenanceAnalysis::relatedSelect(const SelectInst *A, const Value *B) { - const DataLayout &DL = A->getModule()->getDataLayout(); // If the values are Selects with the same condition, we can do a more precise // check: just check for relations between the values on corresponding arms. if (const SelectInst *SB = dyn_cast(B)) if (A->getCondition() == SB->getCondition()) - return related(A->getTrueValue(), SB->getTrueValue(), DL) || - related(A->getFalseValue(), SB->getFalseValue(), DL); + return related(A->getTrueValue(), SB->getTrueValue()) || + related(A->getFalseValue(), SB->getFalseValue()); // Check both arms of the Select node individually. - return related(A->getTrueValue(), B, DL) || - related(A->getFalseValue(), B, DL); + return related(A->getTrueValue(), B) || related(A->getFalseValue(), B); } bool ProvenanceAnalysis::relatedPHI(const PHINode *A, const Value *B) { - const DataLayout &DL = A->getModule()->getDataLayout(); // If the values are PHIs in the same block, we can do a more precise as well // as efficient check: just check for relations between the values on // corresponding edges. @@ -63,7 +60,7 @@ bool ProvenanceAnalysis::relatedPHI(const PHINode *A, if (PNB->getParent() == A->getParent()) { for (unsigned i = 0, e = A->getNumIncomingValues(); i != e; ++i) if (related(A->getIncomingValue(i), - PNB->getIncomingValueForBlock(A->getIncomingBlock(i)), DL)) + PNB->getIncomingValueForBlock(A->getIncomingBlock(i)))) return true; return false; } @@ -71,7 +68,7 @@ bool ProvenanceAnalysis::relatedPHI(const PHINode *A, // Check each unique source of the PHI node against B. SmallPtrSet UniqueSrc; for (Value *PV1 : A->incoming_values()) { - if (UniqueSrc.insert(PV1).second && related(PV1, B, DL)) + if (UniqueSrc.insert(PV1).second && related(PV1, B)) return true; } @@ -112,8 +109,7 @@ static bool IsStoredObjCPointer(const Value *P) { return false; } -bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B, - const DataLayout &DL) { +bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B) { // Ask regular AliasAnalysis, for a first approximation. switch (AA->alias(A, B)) { case NoAlias: @@ -160,10 +156,9 @@ bool ProvenanceAnalysis::relatedCheck(const Value *A, const Value *B, return true; } -bool ProvenanceAnalysis::related(const Value *A, const Value *B, - const DataLayout &DL) { - A = GetUnderlyingObjCPtrCached(A, DL, UnderlyingObjCPtrCache); - B = GetUnderlyingObjCPtrCached(B, DL, UnderlyingObjCPtrCache); +bool ProvenanceAnalysis::related(const Value *A, const Value *B) { + A = GetUnderlyingObjCPtrCached(A, UnderlyingObjCPtrCache); + B = GetUnderlyingObjCPtrCached(B, UnderlyingObjCPtrCache); // Quick check. if (A == B) @@ -178,7 +173,7 @@ bool ProvenanceAnalysis::related(const Value *A, const Value *B, if (!Pair.second) return Pair.first->second; - bool Result = relatedCheck(A, B, DL); + bool Result = relatedCheck(A, B); CachedResults[ValuePairTy(A, B)] = Result; return Result; } diff --git a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h index 8fd842fd42d6..a63e356ce1fc 100644 --- a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h +++ b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysis.h @@ -26,12 +26,12 @@ #define LLVM_LIB_TRANSFORMS_OBJCARC_PROVENANCEANALYSIS_H #include "llvm/ADT/DenseMap.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/ValueHandle.h" #include namespace llvm { +class AAResults; class DataLayout; class PHINode; class SelectInst; @@ -49,7 +49,7 @@ namespace objcarc { /// not two pointers have the same provenance source and thus could /// potentially be related. class ProvenanceAnalysis { - AliasAnalysis *AA; + AAResults *AA; using ValuePairTy = std::pair; using CachedResultsTy = DenseMap; @@ -58,7 +58,7 @@ class ProvenanceAnalysis { DenseMap UnderlyingObjCPtrCache; - bool relatedCheck(const Value *A, const Value *B, const DataLayout &DL); + bool relatedCheck(const Value *A, const Value *B); bool relatedSelect(const SelectInst *A, const Value *B); bool relatedPHI(const PHINode *A, const Value *B); @@ -67,11 +67,11 @@ public: ProvenanceAnalysis(const ProvenanceAnalysis &) = delete; ProvenanceAnalysis &operator=(const ProvenanceAnalysis &) = delete; - void setAA(AliasAnalysis *aa) { AA = aa; } + void setAA(AAResults *aa) { AA = aa; } - AliasAnalysis *getAA() const { return AA; } + AAResults *getAA() const { return AA; } - bool related(const Value *A, const Value *B, const DataLayout &DL); + bool related(const Value *A, const Value *B); void clear() { CachedResults.clear(); diff --git a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysisEvaluator.cpp b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysisEvaluator.cpp index 99a2055aba94..6fdfe787d438 100644 --- a/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysisEvaluator.cpp +++ b/llvm/lib/Transforms/ObjCARC/ProvenanceAnalysisEvaluator.cpp @@ -12,6 +12,7 @@ #include "llvm/Analysis/Passes.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -66,7 +67,6 @@ bool PAEval::runOnFunction(Function &F) { ProvenanceAnalysis PA; PA.setAA(&getAnalysis().getAAResults()); - const DataLayout &DL = F.getParent()->getDataLayout(); for (Value *V1 : Values) { StringRef NameV1 = getName(V1); @@ -75,7 +75,7 @@ bool PAEval::runOnFunction(Function &F) { if (NameV1 >= NameV2) continue; errs() << NameV1 << " and " << NameV2; - if (PA.related(V1, V2, DL)) + if (PA.related(V1, V2)) errs() << " are related.\n"; else errs() << " are not related.\n"; diff --git a/llvm/lib/Transforms/ObjCARC/PtrState.cpp b/llvm/lib/Transforms/ObjCARC/PtrState.cpp index 26dd416d6184..6071ec3e4d91 100644 --- a/llvm/lib/Transforms/ObjCARC/PtrState.cpp +++ b/llvm/lib/Transforms/ObjCARC/PtrState.cpp @@ -232,7 +232,7 @@ bool BottomUpPtrState::HandlePotentialAlterRefCount(Instruction *Inst, Sequence S = GetSeq(); // Check for possible releases. - if (!CanAlterRefCount(Inst, Ptr, PA, Class)) + if (!CanDecrementRefCount(Inst, Ptr, PA, Class)) return false; LLVM_DEBUG(dbgs() << " CanAlterRefCount: Seq: " << S << "; " @@ -383,7 +383,7 @@ bool TopDownPtrState::HandlePotentialAlterRefCount(Instruction *Inst, ARCInstKind Class) { // Check for possible releases. Treat clang.arc.use as a releasing instruction // to prevent sinking a retain past it. - if (!CanAlterRefCount(Inst, Ptr, PA, Class) && + if (!CanDecrementRefCount(Inst, Ptr, PA, Class) && Class != ARCInstKind::IntrinsicUser) return false; diff --git a/llvm/lib/Transforms/Scalar/ADCE.cpp b/llvm/lib/Transforms/Scalar/ADCE.cpp index c3709b9afffb..2b649732a799 100644 --- a/llvm/lib/Transforms/Scalar/ADCE.cpp +++ b/llvm/lib/Transforms/Scalar/ADCE.cpp @@ -643,7 +643,7 @@ void AggressiveDeadCodeElimination::computeReversePostOrder() { SmallPtrSet Visited; unsigned PostOrder = 0; for (auto &BB : F) { - if (succ_begin(&BB) != succ_end(&BB)) + if (!succ_empty(&BB)) continue; for (BasicBlock *Block : inverse_post_order_ext(&BB,Visited)) BlockInfo[Block].PostOrder = PostOrder++; diff --git a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp new file mode 100644 index 000000000000..a02d88fe066f --- /dev/null +++ b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp @@ -0,0 +1,90 @@ +//===-- AnnotationRemarks.cpp - Generate remarks for annotated instrs. ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Generate remarks for instructions marked with !annotation. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/AnnotationRemarks.h" +#include "llvm/ADT/MapVector.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Transforms/Scalar.h" + +using namespace llvm; +using namespace llvm::ore; + +#define DEBUG_TYPE "annotation-remarks" +#define REMARK_PASS DEBUG_TYPE + +static void runImpl(Function &F) { + if (!OptimizationRemarkEmitter::allowExtraAnalysis(F, REMARK_PASS)) + return; + + OptimizationRemarkEmitter ORE(&F); + // For now, just generate a summary of the annotated instructions. + MapVector Mapping; + for (Instruction &I : instructions(F)) { + if (!I.hasMetadata(LLVMContext::MD_annotation)) + continue; + for (const MDOperand &Op : + I.getMetadata(LLVMContext::MD_annotation)->operands()) { + auto Iter = Mapping.insert({cast(Op.get())->getString(), 0}); + Iter.first->second++; + } + } + + Instruction *IP = &*F.begin()->begin(); + for (const auto &KV : Mapping) + ORE.emit(OptimizationRemarkAnalysis(REMARK_PASS, "AnnotationSummary", IP) + << "Annotated " << NV("count", KV.second) << " instructions with " + << NV("type", KV.first)); +} + +namespace { + +struct AnnotationRemarksLegacy : public FunctionPass { + static char ID; + + AnnotationRemarksLegacy() : FunctionPass(ID) { + initializeAnnotationRemarksLegacyPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + runImpl(F); + return false; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesAll(); + } +}; + +} // end anonymous namespace + +char AnnotationRemarksLegacy::ID = 0; + +INITIALIZE_PASS_BEGIN(AnnotationRemarksLegacy, "annotation-remarks", + "Annotation Remarks", false, false) +INITIALIZE_PASS_END(AnnotationRemarksLegacy, "annotation-remarks", + "Annotation Remarks", false, false) + +FunctionPass *llvm::createAnnotationRemarksLegacyPass() { + return new AnnotationRemarksLegacy(); +} + +PreservedAnalyses AnnotationRemarksPass::run(Function &F, + FunctionAnalysisManager &AM) { + runImpl(F); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp index b26bd1114bd4..2eb94b721d96 100644 --- a/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp +++ b/llvm/lib/Transforms/Scalar/CallSiteSplitting.cpp @@ -208,7 +208,7 @@ static bool canSplitCallSite(CallBase &CB, TargetTransformInfo &TTI) { // instructions before the call is less then DuplicationThreshold. The // instructions before the call will be duplicated in the split blocks and // corresponding uses will be updated. - unsigned Cost = 0; + InstructionCost Cost = 0; for (auto &InstBeforeCall : llvm::make_range(CallSiteBB->begin(), CB.getIterator())) { Cost += TTI.getInstructionCost(&InstBeforeCall, diff --git a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp index 7c14b69d658d..fdab74fc94c5 100644 --- a/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp +++ b/llvm/lib/Transforms/Scalar/ConstantHoisting.cpp @@ -366,9 +366,9 @@ void ConstantHoistingPass::collectConstantCandidates( ConstInt->getValue(), ConstInt->getType(), TargetTransformInfo::TCK_SizeAndLatency); else - Cost = TTI->getIntImmCostInst(Inst->getOpcode(), Idx, ConstInt->getValue(), - ConstInt->getType(), - TargetTransformInfo::TCK_SizeAndLatency); + Cost = TTI->getIntImmCostInst( + Inst->getOpcode(), Idx, ConstInt->getValue(), ConstInt->getType(), + TargetTransformInfo::TCK_SizeAndLatency, Inst); // Ignore cheap integer constants. if (Cost > TargetTransformInfo::TCC_Basic) { @@ -418,8 +418,9 @@ void ConstantHoistingPass::collectConstantCandidates( // usually lowered to a load from constant pool. Such operation is unlikely // to be cheaper than compute it by , which can be lowered to // an ADD instruction or folded into Load/Store instruction. - int Cost = TTI->getIntImmCostInst(Instruction::Add, 1, Offset, PtrIntTy, - TargetTransformInfo::TCK_SizeAndLatency); + int Cost = + TTI->getIntImmCostInst(Instruction::Add, 1, Offset, PtrIntTy, + TargetTransformInfo::TCK_SizeAndLatency, Inst); ConstCandVecType &ExprCandVec = ConstGEPCandMap[BaseGV]; ConstCandMapType::iterator Itr; bool Inserted; @@ -950,7 +951,7 @@ bool ConstantHoistingPass::runImpl(Function &Fn, TargetTransformInfo &TTI, // base constant. if (!ConstIntCandVec.empty()) findBaseConstants(nullptr); - for (auto &MapEntry : ConstGEPCandMap) + for (const auto &MapEntry : ConstGEPCandMap) if (!MapEntry.second.empty()) findBaseConstants(MapEntry.first); @@ -959,7 +960,7 @@ bool ConstantHoistingPass::runImpl(Function &Fn, TargetTransformInfo &TTI, bool MadeChange = false; if (!ConstIntInfoVec.empty()) MadeChange = emitBaseConstants(nullptr); - for (auto MapEntry : ConstGEPInfoMap) + for (const auto &MapEntry : ConstGEPInfoMap) if (!MapEntry.second.empty()) MadeChange |= emitBaseConstants(MapEntry.first); diff --git a/llvm/lib/Transforms/Scalar/ConstantProp.cpp b/llvm/lib/Transforms/Scalar/ConstantProp.cpp deleted file mode 100644 index 73bf1d521b1d..000000000000 --- a/llvm/lib/Transforms/Scalar/ConstantProp.cpp +++ /dev/null @@ -1,121 +0,0 @@ -//===- ConstantProp.cpp - Code to perform Simple Constant Propagation -----===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements constant propagation and merging: -// -// Specifically, this: -// * Converts instructions like "add int 1, 2" into 3 -// -// Notice that: -// * This pass has a habit of making definitions be dead. It is a good idea -// to run a DIE pass sometime after running this pass. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/ConstantFolding.h" -#include "llvm/Analysis/TargetLibraryInfo.h" -#include "llvm/IR/Constant.h" -#include "llvm/IR/InstIterator.h" -#include "llvm/IR/Instruction.h" -#include "llvm/InitializePasses.h" -#include "llvm/Pass.h" -#include "llvm/Support/DebugCounter.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/Local.h" -using namespace llvm; - -#define DEBUG_TYPE "constprop" - -STATISTIC(NumInstKilled, "Number of instructions killed"); -DEBUG_COUNTER(CPCounter, "constprop-transform", - "Controls which instructions are killed"); - -namespace { - struct ConstantPropagation : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - ConstantPropagation() : FunctionPass(ID) { - initializeConstantPropagationPass(*PassRegistry::getPassRegistry()); - } - - bool runOnFunction(Function &F) override; - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - AU.addRequired(); - } - }; -} - -char ConstantPropagation::ID = 0; -INITIALIZE_PASS_BEGIN(ConstantPropagation, "constprop", - "Simple constant propagation", false, false) -INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) -INITIALIZE_PASS_END(ConstantPropagation, "constprop", - "Simple constant propagation", false, false) - -FunctionPass *llvm::createConstantPropagationPass() { - return new ConstantPropagation(); -} - -bool ConstantPropagation::runOnFunction(Function &F) { - if (skipFunction(F)) - return false; - - // Initialize the worklist to all of the instructions ready to process... - SmallPtrSet WorkList; - // The SmallVector of WorkList ensures that we do iteration at stable order. - // We use two containers rather than one SetVector, since remove is - // linear-time, and we don't care enough to remove from Vec. - SmallVector WorkListVec; - for (Instruction &I : instructions(&F)) { - WorkList.insert(&I); - WorkListVec.push_back(&I); - } - - bool Changed = false; - const DataLayout &DL = F.getParent()->getDataLayout(); - TargetLibraryInfo *TLI = - &getAnalysis().getTLI(F); - - while (!WorkList.empty()) { - SmallVector NewWorkListVec; - for (auto *I : WorkListVec) { - WorkList.erase(I); // Remove element from the worklist... - - if (!I->use_empty()) // Don't muck with dead instructions... - if (Constant *C = ConstantFoldInstruction(I, DL, TLI)) { - if (!DebugCounter::shouldExecute(CPCounter)) - continue; - - // Add all of the users of this instruction to the worklist, they might - // be constant propagatable now... - for (User *U : I->users()) { - // If user not in the set, then add it to the vector. - if (WorkList.insert(cast(U)).second) - NewWorkListVec.push_back(cast(U)); - } - - // Replace all of the uses of a variable with uses of the constant. - I->replaceAllUsesWith(C); - - if (isInstructionTriviallyDead(I, TLI)) { - I->eraseFromParent(); - ++NumInstKilled; - } - - // We made a change to the function... - Changed = true; - } - } - WorkListVec = std::move(NewWorkListVec); - } - return Changed; -} diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp new file mode 100644 index 000000000000..3b8af6f21ce5 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -0,0 +1,407 @@ +//===-- ConstraintElimination.cpp - Eliminate conds using constraints. ----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Eliminate conditions based on constraints collected from dominating +// conditions. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/ConstraintElimination.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/ConstraintSystem.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/IR/DataLayout.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/DebugCounter.h" +#include "llvm/Transforms/Scalar.h" + +using namespace llvm; +using namespace PatternMatch; + +#define DEBUG_TYPE "constraint-elimination" + +STATISTIC(NumCondsRemoved, "Number of instructions removed"); +DEBUG_COUNTER(EliminatedCounter, "conds-eliminated", + "Controls which conditions are eliminated"); + +static int64_t MaxConstraintValue = std::numeric_limits::max(); + +// Decomposes \p V into a vector of pairs of the form { c, X } where c * X. The +// sum of the pairs equals \p V. The first pair is the constant-factor and X +// must be nullptr. If the expression cannot be decomposed, returns an empty +// vector. +static SmallVector, 4> decompose(Value *V) { + if (auto *CI = dyn_cast(V)) { + if (CI->isNegative() || CI->uge(MaxConstraintValue)) + return {}; + return {{CI->getSExtValue(), nullptr}}; + } + auto *GEP = dyn_cast(V); + if (GEP && GEP->getNumOperands() == 2) { + if (isa(GEP->getOperand(GEP->getNumOperands() - 1))) { + return {{cast(GEP->getOperand(GEP->getNumOperands() - 1)) + ->getSExtValue(), + nullptr}, + {1, GEP->getPointerOperand()}}; + } + Value *Op0; + ConstantInt *CI; + if (match(GEP->getOperand(GEP->getNumOperands() - 1), + m_NUWShl(m_Value(Op0), m_ConstantInt(CI)))) + return {{0, nullptr}, + {1, GEP->getPointerOperand()}, + {std::pow(int64_t(2), CI->getSExtValue()), Op0}}; + if (match(GEP->getOperand(GEP->getNumOperands() - 1), + m_ZExt(m_NUWShl(m_Value(Op0), m_ConstantInt(CI))))) + return {{0, nullptr}, + {1, GEP->getPointerOperand()}, + {std::pow(int64_t(2), CI->getSExtValue()), Op0}}; + + return {{0, nullptr}, + {1, GEP->getPointerOperand()}, + {1, GEP->getOperand(GEP->getNumOperands() - 1)}}; + } + + Value *Op0; + Value *Op1; + ConstantInt *CI; + if (match(V, m_NUWAdd(m_Value(Op0), m_ConstantInt(CI)))) + return {{CI->getSExtValue(), nullptr}, {1, Op0}}; + if (match(V, m_NUWAdd(m_Value(Op0), m_Value(Op1)))) + return {{0, nullptr}, {1, Op0}, {1, Op1}}; + + if (match(V, m_NUWSub(m_Value(Op0), m_ConstantInt(CI)))) + return {{-1 * CI->getSExtValue(), nullptr}, {1, Op0}}; + if (match(V, m_NUWSub(m_Value(Op0), m_Value(Op1)))) + return {{0, nullptr}, {1, Op0}, {1, Op1}}; + + return {{0, nullptr}, {1, V}}; +} + +/// Turn a condition \p CmpI into a constraint vector, using indices from \p +/// Value2Index. If \p ShouldAdd is true, new indices are added for values not +/// yet in \p Value2Index. +static SmallVector +getConstraint(CmpInst::Predicate Pred, Value *Op0, Value *Op1, + DenseMap &Value2Index, bool ShouldAdd) { + int64_t Offset1 = 0; + int64_t Offset2 = 0; + + auto TryToGetIndex = [ShouldAdd, + &Value2Index](Value *V) -> Optional { + if (ShouldAdd) { + Value2Index.insert({V, Value2Index.size() + 1}); + return Value2Index[V]; + } + auto I = Value2Index.find(V); + if (I == Value2Index.end()) + return None; + return I->second; + }; + + if (Pred == CmpInst::ICMP_UGT || Pred == CmpInst::ICMP_UGE) + return getConstraint(CmpInst::getSwappedPredicate(Pred), Op1, Op0, + Value2Index, ShouldAdd); + + // Only ULE and ULT predicates are supported at the moment. + if (Pred != CmpInst::ICMP_ULE && Pred != CmpInst::ICMP_ULT) + return {}; + + auto ADec = decompose(Op0); + auto BDec = decompose(Op1); + // Skip if decomposing either of the values failed. + if (ADec.empty() || BDec.empty()) + return {}; + + // Skip trivial constraints without any variables. + if (ADec.size() == 1 && BDec.size() == 1) + return {}; + + Offset1 = ADec[0].first; + Offset2 = BDec[0].first; + Offset1 *= -1; + + // Create iterator ranges that skip the constant-factor. + auto VariablesA = make_range(std::next(ADec.begin()), ADec.end()); + auto VariablesB = make_range(std::next(BDec.begin()), BDec.end()); + + // Check if each referenced value in the constraint is already in the system + // or can be added (if ShouldAdd is true). + for (const auto &KV : + concat>(VariablesA, VariablesB)) + if (!TryToGetIndex(KV.second)) + return {}; + + // Build result constraint, by first adding all coefficients from A and then + // subtracting all coefficients from B. + SmallVector R(Value2Index.size() + 1, 0); + for (const auto &KV : VariablesA) + R[Value2Index[KV.second]] += KV.first; + + for (const auto &KV : VariablesB) + R[Value2Index[KV.second]] -= KV.first; + + R[0] = Offset1 + Offset2 + (Pred == CmpInst::ICMP_ULT ? -1 : 0); + return R; +} + +static SmallVector +getConstraint(CmpInst *Cmp, DenseMap &Value2Index, + bool ShouldAdd) { + return getConstraint(Cmp->getPredicate(), Cmp->getOperand(0), + Cmp->getOperand(1), Value2Index, ShouldAdd); +} + +namespace { +/// Represents either a condition that holds on entry to a block or a basic +/// block, with their respective Dominator DFS in and out numbers. +struct ConstraintOrBlock { + unsigned NumIn; + unsigned NumOut; + bool IsBlock; + bool Not; + union { + BasicBlock *BB; + CmpInst *Condition; + }; + + ConstraintOrBlock(DomTreeNode *DTN) + : NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), IsBlock(true), + BB(DTN->getBlock()) {} + ConstraintOrBlock(DomTreeNode *DTN, CmpInst *Condition, bool Not) + : NumIn(DTN->getDFSNumIn()), NumOut(DTN->getDFSNumOut()), IsBlock(false), + Not(Not), Condition(Condition) {} +}; + +struct StackEntry { + unsigned NumIn; + unsigned NumOut; + CmpInst *Condition; + bool IsNot; + + StackEntry(unsigned NumIn, unsigned NumOut, CmpInst *Condition, bool IsNot) + : NumIn(NumIn), NumOut(NumOut), Condition(Condition), IsNot(IsNot) {} +}; +} // namespace + +static bool eliminateConstraints(Function &F, DominatorTree &DT) { + bool Changed = false; + DT.updateDFSNumbers(); + ConstraintSystem CS; + + SmallVector WorkList; + + // First, collect conditions implied by branches and blocks with their + // Dominator DFS in and out numbers. + for (BasicBlock &BB : F) { + if (!DT.getNode(&BB)) + continue; + WorkList.emplace_back(DT.getNode(&BB)); + + auto *Br = dyn_cast(BB.getTerminator()); + if (!Br || !Br->isConditional()) + continue; + + // If the condition is an OR of 2 compares and the false successor only has + // the current block as predecessor, queue both negated conditions for the + // false successor. + Value *Op0, *Op1; + if (match(Br->getCondition(), m_LogicalOr(m_Value(Op0), m_Value(Op1))) && + match(Op0, m_Cmp()) && match(Op1, m_Cmp())) { + BasicBlock *FalseSuccessor = Br->getSuccessor(1); + if (FalseSuccessor->getSinglePredecessor()) { + WorkList.emplace_back(DT.getNode(FalseSuccessor), cast(Op0), + true); + WorkList.emplace_back(DT.getNode(FalseSuccessor), cast(Op1), + true); + } + continue; + } + + // If the condition is an AND of 2 compares and the true successor only has + // the current block as predecessor, queue both conditions for the true + // successor. + if (match(Br->getCondition(), m_LogicalAnd(m_Value(Op0), m_Value(Op1))) && + match(Op0, m_Cmp()) && match(Op1, m_Cmp())) { + BasicBlock *TrueSuccessor = Br->getSuccessor(0); + if (TrueSuccessor->getSinglePredecessor()) { + WorkList.emplace_back(DT.getNode(TrueSuccessor), cast(Op0), + false); + WorkList.emplace_back(DT.getNode(TrueSuccessor), cast(Op1), + false); + } + continue; + } + + auto *CmpI = dyn_cast(Br->getCondition()); + if (!CmpI) + continue; + if (Br->getSuccessor(0)->getSinglePredecessor()) + WorkList.emplace_back(DT.getNode(Br->getSuccessor(0)), CmpI, false); + if (Br->getSuccessor(1)->getSinglePredecessor()) + WorkList.emplace_back(DT.getNode(Br->getSuccessor(1)), CmpI, true); + } + + // Next, sort worklist by dominance, so that dominating blocks and conditions + // come before blocks and conditions dominated by them. If a block and a + // condition have the same numbers, the condition comes before the block, as + // it holds on entry to the block. + sort(WorkList, [](const ConstraintOrBlock &A, const ConstraintOrBlock &B) { + return std::tie(A.NumIn, A.IsBlock) < std::tie(B.NumIn, B.IsBlock); + }); + + // Finally, process ordered worklist and eliminate implied conditions. + SmallVector DFSInStack; + DenseMap Value2Index; + for (ConstraintOrBlock &CB : WorkList) { + // First, pop entries from the stack that are out-of-scope for CB. Remove + // the corresponding entry from the constraint system. + while (!DFSInStack.empty()) { + auto &E = DFSInStack.back(); + LLVM_DEBUG(dbgs() << "Top of stack : " << E.NumIn << " " << E.NumOut + << "\n"); + LLVM_DEBUG(dbgs() << "CB: " << CB.NumIn << " " << CB.NumOut << "\n"); + assert(E.NumIn <= CB.NumIn); + if (CB.NumOut <= E.NumOut) + break; + LLVM_DEBUG(dbgs() << "Removing " << *E.Condition << " " << E.IsNot + << "\n"); + DFSInStack.pop_back(); + CS.popLastConstraint(); + } + + LLVM_DEBUG({ + dbgs() << "Processing "; + if (CB.IsBlock) + dbgs() << *CB.BB; + else + dbgs() << *CB.Condition; + dbgs() << "\n"; + }); + + // For a block, check if any CmpInsts become known based on the current set + // of constraints. + if (CB.IsBlock) { + for (Instruction &I : *CB.BB) { + auto *Cmp = dyn_cast(&I); + if (!Cmp) + continue; + auto R = getConstraint(Cmp, Value2Index, false); + if (R.empty() || R.size() == 1) + continue; + if (CS.isConditionImplied(R)) { + if (!DebugCounter::shouldExecute(EliminatedCounter)) + continue; + + LLVM_DEBUG(dbgs() << "Condition " << *Cmp + << " implied by dominating constraints\n"); + LLVM_DEBUG({ + for (auto &E : reverse(DFSInStack)) + dbgs() << " C " << *E.Condition << " " << E.IsNot << "\n"; + }); + Cmp->replaceAllUsesWith( + ConstantInt::getTrue(F.getParent()->getContext())); + NumCondsRemoved++; + Changed = true; + } + if (CS.isConditionImplied(ConstraintSystem::negate(R))) { + if (!DebugCounter::shouldExecute(EliminatedCounter)) + continue; + + LLVM_DEBUG(dbgs() << "Condition !" << *Cmp + << " implied by dominating constraints\n"); + LLVM_DEBUG({ + for (auto &E : reverse(DFSInStack)) + dbgs() << " C " << *E.Condition << " " << E.IsNot << "\n"; + }); + Cmp->replaceAllUsesWith( + ConstantInt::getFalse(F.getParent()->getContext())); + NumCondsRemoved++; + Changed = true; + } + } + continue; + } + + // Otherwise, add the condition to the system and stack, if we can transform + // it into a constraint. + auto R = getConstraint(CB.Condition, Value2Index, true); + if (R.empty()) + continue; + + LLVM_DEBUG(dbgs() << "Adding " << *CB.Condition << " " << CB.Not << "\n"); + if (CB.Not) + R = ConstraintSystem::negate(R); + + // If R has been added to the system, queue it for removal once it goes + // out-of-scope. + if (CS.addVariableRowFill(R)) + DFSInStack.emplace_back(CB.NumIn, CB.NumOut, CB.Condition, CB.Not); + } + + return Changed; +} + +PreservedAnalyses ConstraintEliminationPass::run(Function &F, + FunctionAnalysisManager &AM) { + auto &DT = AM.getResult(F); + if (!eliminateConstraints(F, DT)) + return PreservedAnalyses::all(); + + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + PA.preserveSet(); + return PA; +} + +namespace { + +class ConstraintElimination : public FunctionPass { +public: + static char ID; + + ConstraintElimination() : FunctionPass(ID) { + initializeConstraintEliminationPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + auto &DT = getAnalysis().getDomTree(); + return eliminateConstraints(F, DT); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + AU.addRequired(); + AU.addPreserved(); + AU.addPreserved(); + } +}; + +} // end anonymous namespace + +char ConstraintElimination::ID = 0; + +INITIALIZE_PASS_BEGIN(ConstraintElimination, "constraint-elimination", + "Constraint Elimination", false, false) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) +INITIALIZE_PASS_END(ConstraintElimination, "constraint-elimination", + "Constraint Elimination", false, false) + +FunctionPass *llvm::createConstraintEliminationPass() { + return new ConstraintElimination(); +} diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index cd2f4ca36f3b..b671d68031a8 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -58,8 +58,11 @@ STATISTIC(NumMemAccess, "Number of memory access targets propagated"); STATISTIC(NumCmps, "Number of comparisons propagated"); STATISTIC(NumReturns, "Number of return values propagated"); STATISTIC(NumDeadCases, "Number of switch cases removed"); +STATISTIC(NumSDivSRemsNarrowed, + "Number of sdivs/srems whose width was decreased"); STATISTIC(NumSDivs, "Number of sdiv converted to udiv"); -STATISTIC(NumUDivs, "Number of udivs whose width was decreased"); +STATISTIC(NumUDivURemsNarrowed, + "Number of udivs/urems whose width was decreased"); STATISTIC(NumAShrs, "Number of ashr converted to lshr"); STATISTIC(NumSRems, "Number of srem converted to urem"); STATISTIC(NumSExt, "Number of sext converted to zext"); @@ -126,7 +129,7 @@ static bool processSelect(SelectInst *S, LazyValueInfo *LVI) { if (S->getType()->isVectorTy()) return false; if (isa(S->getCondition())) return false; - Constant *C = LVI->getConstant(S->getCondition(), S->getParent(), S); + Constant *C = LVI->getConstant(S->getCondition(), S); if (!C) return false; ConstantInt *CI = dyn_cast(C); @@ -283,7 +286,7 @@ static bool processMemAccess(Instruction *I, LazyValueInfo *LVI) { if (isa(Pointer)) return false; - Constant *C = LVI->getConstant(Pointer, I->getParent(), I); + Constant *C = LVI->getConstant(Pointer, I); if (!C) return false; ++NumMemAccess; @@ -301,18 +304,9 @@ static bool processCmp(CmpInst *Cmp, LazyValueInfo *LVI) { if (!C) return false; - // As a policy choice, we choose not to waste compile time on anything where - // the comparison is testing local values. While LVI can sometimes reason - // about such cases, it's not its primary purpose. We do make sure to do - // the block local query for uses from terminator instructions, but that's - // handled in the code for each terminator. As an exception, we allow phi - // nodes, for which LVI can thread the condition into predecessors. - auto *I = dyn_cast(Op0); - if (I && I->getParent() == Cmp->getParent() && !isa(I)) - return false; - LazyValueInfo::Tristate Result = - LVI->getPredicateAt(Cmp->getPredicate(), Op0, C, Cmp); + LVI->getPredicateAt(Cmp->getPredicate(), Op0, C, Cmp, + /*UseBlockValue=*/true); if (Result == LazyValueInfo::Unknown) return false; @@ -336,15 +330,6 @@ static bool processSwitch(SwitchInst *I, LazyValueInfo *LVI, Value *Cond = I->getCondition(); BasicBlock *BB = I->getParent(); - // If the condition was defined in same block as the switch then LazyValueInfo - // currently won't say anything useful about it, though in theory it could. - if (isa(Cond) && cast(Cond)->getParent() == BB) - return false; - - // If the switch is unreachable then trying to improve it is a waste of time. - pred_iterator PB = pred_begin(BB), PE = pred_end(BB); - if (PB == PE) return false; - // Analyse each switch case in turn. bool Changed = false; DenseMap SuccessorsCount; @@ -357,35 +342,9 @@ static bool processSwitch(SwitchInst *I, LazyValueInfo *LVI, for (auto CI = SI->case_begin(), CE = SI->case_end(); CI != CE;) { ConstantInt *Case = CI->getCaseValue(); - - // Check to see if the switch condition is equal to/not equal to the case - // value on every incoming edge, equal/not equal being the same each time. - LazyValueInfo::Tristate State = LazyValueInfo::Unknown; - for (pred_iterator PI = PB; PI != PE; ++PI) { - // Is the switch condition equal to the case value? - LazyValueInfo::Tristate Value = LVI->getPredicateOnEdge(CmpInst::ICMP_EQ, - Cond, Case, *PI, - BB, SI); - // Give up on this case if nothing is known. - if (Value == LazyValueInfo::Unknown) { - State = LazyValueInfo::Unknown; - break; - } - - // If this was the first edge to be visited, record that all other edges - // need to give the same result. - if (PI == PB) { - State = Value; - continue; - } - - // If this case is known to fire for some edges and known not to fire for - // others then there is nothing we can do - give up. - if (Value != State) { - State = LazyValueInfo::Unknown; - break; - } - } + LazyValueInfo::Tristate State = + LVI->getPredicateAt(CmpInst::ICMP_EQ, Cond, Case, I, + /* UseBlockValue */ true); if (State == LazyValueInfo::False) { // This case never fires - remove it. @@ -429,10 +388,8 @@ static bool processSwitch(SwitchInst *I, LazyValueInfo *LVI, // See if we can prove that the given binary op intrinsic will not overflow. static bool willNotOverflow(BinaryOpIntrinsic *BO, LazyValueInfo *LVI) { - ConstantRange LRange = LVI->getConstantRange( - BO->getLHS(), BO->getParent(), BO); - ConstantRange RRange = LVI->getConstantRange( - BO->getRHS(), BO->getParent(), BO); + ConstantRange LRange = LVI->getConstantRange(BO->getLHS(), BO); + ConstantRange RRange = LVI->getConstantRange(BO->getRHS(), BO); ConstantRange NWRegion = ConstantRange::makeGuaranteedNoWrapRegion( BO->getBinaryOp(), RRange, BO->getNoWrapKind()); return NWRegion.contains(LRange); @@ -532,8 +489,6 @@ static void processSaturatingInst(SaturatingInst *SI, LazyValueInfo *LVI) { /// Infer nonnull attributes for the arguments at the specified callsite. static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) { - SmallVector ArgNos; - unsigned ArgNo = 0; if (auto *WO = dyn_cast(&CB)) { if (WO->getLHS()->getType()->isIntegerTy() && willNotOverflow(WO, LVI)) { @@ -549,6 +504,8 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) { } } + bool Changed = false; + // Deopt bundle operands are intended to capture state with minimal // perturbance of the code otherwise. If we can find a constant value for // any such operand and remove a use of the original value, that's @@ -557,22 +514,22 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) { // idiomatically, appear along rare conditional paths, it's reasonable likely // we may have a conditional fact with which LVI can fold. if (auto DeoptBundle = CB.getOperandBundle(LLVMContext::OB_deopt)) { - bool Progress = false; for (const Use &ConstU : DeoptBundle->Inputs) { Use &U = const_cast(ConstU); Value *V = U.get(); if (V->getType()->isVectorTy()) continue; if (isa(V)) continue; - Constant *C = LVI->getConstant(V, CB.getParent(), &CB); + Constant *C = LVI->getConstant(V, &CB); if (!C) continue; U.set(C); - Progress = true; + Changed = true; } - if (Progress) - return true; } + SmallVector ArgNos; + unsigned ArgNo = 0; + for (Value *V : CB.args()) { PointerType *Type = dyn_cast(V->getType()); // Try to mark pointer typed parameters as non-null. We skip the @@ -590,7 +547,7 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) { assert(ArgNo == CB.arg_size() && "sanity check"); if (ArgNos.empty()) - return false; + return Changed; AttributeList AS = CB.getAttributes(); LLVMContext &Ctx = CB.getContext(); @@ -601,13 +558,79 @@ static bool processCallSite(CallBase &CB, LazyValueInfo *LVI) { return true; } -static bool hasPositiveOperands(BinaryOperator *SDI, LazyValueInfo *LVI) { - Constant *Zero = ConstantInt::get(SDI->getType(), 0); - for (Value *O : SDI->operands()) { - auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SGE, O, Zero, SDI); - if (Result != LazyValueInfo::True) - return false; +static bool isNonNegative(Value *V, LazyValueInfo *LVI, Instruction *CxtI) { + Constant *Zero = ConstantInt::get(V->getType(), 0); + auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SGE, V, Zero, CxtI); + return Result == LazyValueInfo::True; +} + +static bool isNonPositive(Value *V, LazyValueInfo *LVI, Instruction *CxtI) { + Constant *Zero = ConstantInt::get(V->getType(), 0); + auto Result = LVI->getPredicateAt(ICmpInst::ICMP_SLE, V, Zero, CxtI); + return Result == LazyValueInfo::True; +} + +enum class Domain { NonNegative, NonPositive, Unknown }; + +Domain getDomain(Value *V, LazyValueInfo *LVI, Instruction *CxtI) { + if (isNonNegative(V, LVI, CxtI)) + return Domain::NonNegative; + if (isNonPositive(V, LVI, CxtI)) + return Domain::NonPositive; + return Domain::Unknown; +} + +/// Try to shrink a sdiv/srem's width down to the smallest power of two that's +/// sufficient to contain its operands. +static bool narrowSDivOrSRem(BinaryOperator *Instr, LazyValueInfo *LVI) { + assert(Instr->getOpcode() == Instruction::SDiv || + Instr->getOpcode() == Instruction::SRem); + if (Instr->getType()->isVectorTy()) + return false; + + // Find the smallest power of two bitwidth that's sufficient to hold Instr's + // operands. + unsigned OrigWidth = Instr->getType()->getIntegerBitWidth(); + + // What is the smallest bit width that can accomodate the entire value ranges + // of both of the operands? + std::array, 2> CRs; + unsigned MinSignedBits = 0; + for (auto I : zip(Instr->operands(), CRs)) { + std::get<1>(I) = LVI->getConstantRange(std::get<0>(I), Instr); + MinSignedBits = std::max(std::get<1>(I)->getMinSignedBits(), MinSignedBits); } + + // sdiv/srem is UB if divisor is -1 and divident is INT_MIN, so unless we can + // prove that such a combination is impossible, we need to bump the bitwidth. + if (CRs[1]->contains(APInt::getAllOnesValue(OrigWidth)) && + CRs[0]->contains( + APInt::getSignedMinValue(MinSignedBits).sextOrSelf(OrigWidth))) + ++MinSignedBits; + + // Don't shrink below 8 bits wide. + unsigned NewWidth = std::max(PowerOf2Ceil(MinSignedBits), 8); + + // NewWidth might be greater than OrigWidth if OrigWidth is not a power of + // two. + if (NewWidth >= OrigWidth) + return false; + + ++NumSDivSRemsNarrowed; + IRBuilder<> B{Instr}; + auto *TruncTy = Type::getIntNTy(Instr->getContext(), NewWidth); + auto *LHS = B.CreateTruncOrBitCast(Instr->getOperand(0), TruncTy, + Instr->getName() + ".lhs.trunc"); + auto *RHS = B.CreateTruncOrBitCast(Instr->getOperand(1), TruncTy, + Instr->getName() + ".rhs.trunc"); + auto *BO = B.CreateBinOp(Instr->getOpcode(), LHS, RHS, Instr->getName()); + auto *Sext = B.CreateSExt(BO, Instr->getType(), Instr->getName() + ".sext"); + if (auto *BinOp = dyn_cast(BO)) + if (BinOp->getOpcode() == Instruction::SDiv) + BinOp->setIsExact(Instr->isExact()); + + Instr->replaceAllUsesWith(Sext); + Instr->eraseFromParent(); return true; } @@ -621,21 +644,23 @@ static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) { // Find the smallest power of two bitwidth that's sufficient to hold Instr's // operands. - auto OrigWidth = Instr->getType()->getIntegerBitWidth(); - ConstantRange OperandRange(OrigWidth, /*isFullSet=*/false); + + // What is the smallest bit width that can accomodate the entire value ranges + // of both of the operands? + unsigned MaxActiveBits = 0; for (Value *Operand : Instr->operands()) { - OperandRange = OperandRange.unionWith( - LVI->getConstantRange(Operand, Instr->getParent())); + ConstantRange CR = LVI->getConstantRange(Operand, Instr); + MaxActiveBits = std::max(CR.getActiveBits(), MaxActiveBits); } // Don't shrink below 8 bits wide. - unsigned NewWidth = std::max( - PowerOf2Ceil(OperandRange.getUnsignedMax().getActiveBits()), 8); + unsigned NewWidth = std::max(PowerOf2Ceil(MaxActiveBits), 8); + // NewWidth might be greater than OrigWidth if OrigWidth is not a power of // two. - if (NewWidth >= OrigWidth) + if (NewWidth >= Instr->getType()->getIntegerBitWidth()) return false; - ++NumUDivs; + ++NumUDivURemsNarrowed; IRBuilder<> B{Instr}; auto *TruncTy = Type::getIntNTy(Instr->getContext(), NewWidth); auto *LHS = B.CreateTruncOrBitCast(Instr->getOperand(0), TruncTy, @@ -654,52 +679,135 @@ static bool processUDivOrURem(BinaryOperator *Instr, LazyValueInfo *LVI) { } static bool processSRem(BinaryOperator *SDI, LazyValueInfo *LVI) { - if (SDI->getType()->isVectorTy() || !hasPositiveOperands(SDI, LVI)) + assert(SDI->getOpcode() == Instruction::SRem); + if (SDI->getType()->isVectorTy()) return false; + struct Operand { + Value *V; + Domain D; + }; + std::array Ops; + + for (const auto I : zip(Ops, SDI->operands())) { + Operand &Op = std::get<0>(I); + Op.V = std::get<1>(I); + Op.D = getDomain(Op.V, LVI, SDI); + if (Op.D == Domain::Unknown) + return false; + } + + // We know domains of both of the operands! ++NumSRems; - auto *BO = BinaryOperator::CreateURem(SDI->getOperand(0), SDI->getOperand(1), - SDI->getName(), SDI); - BO->setDebugLoc(SDI->getDebugLoc()); - SDI->replaceAllUsesWith(BO); + + // We need operands to be non-negative, so negate each one that isn't. + for (Operand &Op : Ops) { + if (Op.D == Domain::NonNegative) + continue; + auto *BO = + BinaryOperator::CreateNeg(Op.V, Op.V->getName() + ".nonneg", SDI); + BO->setDebugLoc(SDI->getDebugLoc()); + Op.V = BO; + } + + auto *URem = + BinaryOperator::CreateURem(Ops[0].V, Ops[1].V, SDI->getName(), SDI); + URem->setDebugLoc(SDI->getDebugLoc()); + + Value *Res = URem; + + // If the divident was non-positive, we need to negate the result. + if (Ops[0].D == Domain::NonPositive) + Res = BinaryOperator::CreateNeg(Res, Res->getName() + ".neg", SDI); + + SDI->replaceAllUsesWith(Res); SDI->eraseFromParent(); - // Try to process our new urem. - processUDivOrURem(BO, LVI); + // Try to simplify our new urem. + processUDivOrURem(URem, LVI); return true; } /// See if LazyValueInfo's ability to exploit edge conditions or range -/// information is sufficient to prove the both operands of this SDiv are -/// positive. If this is the case, replace the SDiv with a UDiv. Even for local +/// information is sufficient to prove the signs of both operands of this SDiv. +/// If this is the case, replace the SDiv with a UDiv. Even for local /// conditions, this can sometimes prove conditions instcombine can't by /// exploiting range information. static bool processSDiv(BinaryOperator *SDI, LazyValueInfo *LVI) { - if (SDI->getType()->isVectorTy() || !hasPositiveOperands(SDI, LVI)) + assert(SDI->getOpcode() == Instruction::SDiv); + if (SDI->getType()->isVectorTy()) return false; + struct Operand { + Value *V; + Domain D; + }; + std::array Ops; + + for (const auto I : zip(Ops, SDI->operands())) { + Operand &Op = std::get<0>(I); + Op.V = std::get<1>(I); + Op.D = getDomain(Op.V, LVI, SDI); + if (Op.D == Domain::Unknown) + return false; + } + + // We know domains of both of the operands! ++NumSDivs; - auto *BO = BinaryOperator::CreateUDiv(SDI->getOperand(0), SDI->getOperand(1), - SDI->getName(), SDI); - BO->setDebugLoc(SDI->getDebugLoc()); - BO->setIsExact(SDI->isExact()); - SDI->replaceAllUsesWith(BO); + + // We need operands to be non-negative, so negate each one that isn't. + for (Operand &Op : Ops) { + if (Op.D == Domain::NonNegative) + continue; + auto *BO = + BinaryOperator::CreateNeg(Op.V, Op.V->getName() + ".nonneg", SDI); + BO->setDebugLoc(SDI->getDebugLoc()); + Op.V = BO; + } + + auto *UDiv = + BinaryOperator::CreateUDiv(Ops[0].V, Ops[1].V, SDI->getName(), SDI); + UDiv->setDebugLoc(SDI->getDebugLoc()); + UDiv->setIsExact(SDI->isExact()); + + Value *Res = UDiv; + + // If the operands had two different domains, we need to negate the result. + if (Ops[0].D != Ops[1].D) + Res = BinaryOperator::CreateNeg(Res, Res->getName() + ".neg", SDI); + + SDI->replaceAllUsesWith(Res); SDI->eraseFromParent(); // Try to simplify our new udiv. - processUDivOrURem(BO, LVI); + processUDivOrURem(UDiv, LVI); return true; } +static bool processSDivOrSRem(BinaryOperator *Instr, LazyValueInfo *LVI) { + assert(Instr->getOpcode() == Instruction::SDiv || + Instr->getOpcode() == Instruction::SRem); + if (Instr->getType()->isVectorTy()) + return false; + + if (Instr->getOpcode() == Instruction::SDiv) + if (processSDiv(Instr, LVI)) + return true; + + if (Instr->getOpcode() == Instruction::SRem) + if (processSRem(Instr, LVI)) + return true; + + return narrowSDivOrSRem(Instr, LVI); +} + static bool processAShr(BinaryOperator *SDI, LazyValueInfo *LVI) { if (SDI->getType()->isVectorTy()) return false; - Constant *Zero = ConstantInt::get(SDI->getType(), 0); - if (LVI->getPredicateAt(ICmpInst::ICMP_SGE, SDI->getOperand(0), Zero, SDI) != - LazyValueInfo::True) + if (!isNonNegative(SDI->getOperand(0), LVI, SDI)) return false; ++NumAShrs; @@ -719,9 +827,7 @@ static bool processSExt(SExtInst *SDI, LazyValueInfo *LVI) { Value *Base = SDI->getOperand(0); - Constant *Zero = ConstantInt::get(Base->getType(), 0); - if (LVI->getPredicateAt(ICmpInst::ICMP_SGE, Base, Zero, SDI) != - LazyValueInfo::True) + if (!isNonNegative(Base, LVI, SDI)) return false; ++NumSExt; @@ -748,14 +854,12 @@ static bool processBinOp(BinaryOperator *BinOp, LazyValueInfo *LVI) { if (NSW && NUW) return false; - BasicBlock *BB = BinOp->getParent(); - Instruction::BinaryOps Opcode = BinOp->getOpcode(); Value *LHS = BinOp->getOperand(0); Value *RHS = BinOp->getOperand(1); - ConstantRange LRange = LVI->getConstantRange(LHS, BB, BinOp); - ConstantRange RRange = LVI->getConstantRange(RHS, BB, BinOp); + ConstantRange LRange = LVI->getConstantRange(LHS, BinOp); + ConstantRange RRange = LVI->getConstantRange(RHS, BinOp); bool Changed = false; bool NewNUW = false, NewNSW = false; @@ -783,7 +887,6 @@ static bool processAnd(BinaryOperator *BinOp, LazyValueInfo *LVI) { // Pattern match (and lhs, C) where C includes a superset of bits which might // be set in lhs. This is a common truncation idiom created by instcombine. - BasicBlock *BB = BinOp->getParent(); Value *LHS = BinOp->getOperand(0); ConstantInt *RHS = dyn_cast(BinOp->getOperand(1)); if (!RHS || !RHS->getValue().isMask()) @@ -792,7 +895,7 @@ static bool processAnd(BinaryOperator *BinOp, LazyValueInfo *LVI) { // We can only replace the AND with LHS based on range info if the range does // not include undef. ConstantRange LRange = - LVI->getConstantRange(LHS, BB, BinOp, /*UndefAllowed=*/false); + LVI->getConstantRange(LHS, BinOp, /*UndefAllowed=*/false); if (!LRange.getUnsignedMax().ule(RHS->getValue())) return false; @@ -804,7 +907,7 @@ static bool processAnd(BinaryOperator *BinOp, LazyValueInfo *LVI) { static Constant *getConstantAt(Value *V, Instruction *At, LazyValueInfo *LVI) { - if (Constant *C = LVI->getConstant(V, At->getParent(), At)) + if (Constant *C = LVI->getConstant(V, At)) return C; // TODO: The following really should be sunk inside LVI's core algorithm, or @@ -858,10 +961,8 @@ static bool runImpl(Function &F, LazyValueInfo *LVI, DominatorTree *DT, BBChanged |= processCallSite(cast(*II), LVI); break; case Instruction::SRem: - BBChanged |= processSRem(cast(II), LVI); - break; case Instruction::SDiv: - BBChanged |= processSDiv(cast(II), LVI); + BBChanged |= processSDivOrSRem(cast(II), LVI); break; case Instruction::UDiv: case Instruction::URem: @@ -929,11 +1030,19 @@ CorrelatedValuePropagationPass::run(Function &F, FunctionAnalysisManager &AM) { bool Changed = runImpl(F, LVI, DT, getBestSimplifyQuery(AM, F)); - if (!Changed) - return PreservedAnalyses::all(); PreservedAnalyses PA; - PA.preserve(); - PA.preserve(); - PA.preserve(); + if (!Changed) { + PA = PreservedAnalyses::all(); + } else { + PA.preserve(); + PA.preserve(); + PA.preserve(); + } + + // Keeping LVI alive is expensive, both because it uses a lot of memory, and + // because invalidating values in LVI is expensive. While CVP does preserve + // LVI, we know that passes after JumpThreading+CVP will not need the result + // of this analysis, so we forcefully discard it early. + PA.abandon(); return PA; } diff --git a/llvm/lib/Transforms/Scalar/DCE.cpp b/llvm/lib/Transforms/Scalar/DCE.cpp index 28947482e303..d55adf7c2d12 100644 --- a/llvm/lib/Transforms/Scalar/DCE.cpp +++ b/llvm/lib/Transforms/Scalar/DCE.cpp @@ -32,57 +32,10 @@ using namespace llvm; #define DEBUG_TYPE "dce" -STATISTIC(DIEEliminated, "Number of insts removed by DIE pass"); STATISTIC(DCEEliminated, "Number of insts removed"); DEBUG_COUNTER(DCECounter, "dce-transform", "Controls which instructions are eliminated"); -namespace { - //===--------------------------------------------------------------------===// - // DeadInstElimination pass implementation - // -struct DeadInstElimination : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - DeadInstElimination() : FunctionPass(ID) { - initializeDeadInstEliminationPass(*PassRegistry::getPassRegistry()); - } - bool runOnFunction(Function &F) override { - if (skipFunction(F)) - return false; - auto *TLIP = getAnalysisIfAvailable(); - TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr; - - bool Changed = false; - for (auto &BB : F) { - for (BasicBlock::iterator DI = BB.begin(); DI != BB.end(); ) { - Instruction *Inst = &*DI++; - if (isInstructionTriviallyDead(Inst, TLI)) { - if (!DebugCounter::shouldExecute(DCECounter)) - continue; - salvageDebugInfo(*Inst); - Inst->eraseFromParent(); - Changed = true; - ++DIEEliminated; - } - } - } - return Changed; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - } -}; -} - -char DeadInstElimination::ID = 0; -INITIALIZE_PASS(DeadInstElimination, "die", - "Dead Instruction Elimination", false, false) - -Pass *llvm::createDeadInstEliminationPass() { - return new DeadInstElimination(); -} - //===--------------------------------------------------------------------===// // RedundantDbgInstElimination pass implementation // @@ -116,6 +69,18 @@ Pass *llvm::createRedundantDbgInstEliminationPass() { return new RedundantDbgInstElimination(); } +PreservedAnalyses +RedundantDbgInstEliminationPass::run(Function &F, FunctionAnalysisManager &AM) { + bool Changed = false; + for (auto &BB : F) + Changed |= RemoveRedundantDbgInstrs(&BB); + if (!Changed) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} + //===--------------------------------------------------------------------===// // DeadCodeElimination pass implementation // @@ -178,7 +143,7 @@ static bool eliminateDeadCode(Function &F, TargetLibraryInfo *TLI) { } PreservedAnalyses DCEPass::run(Function &F, FunctionAnalysisManager &AM) { - if (!eliminateDeadCode(F, AM.getCachedResult(F))) + if (!eliminateDeadCode(F, &AM.getResult(F))) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -197,13 +162,14 @@ struct DCELegacyPass : public FunctionPass { if (skipFunction(F)) return false; - auto *TLIP = getAnalysisIfAvailable(); - TargetLibraryInfo *TLI = TLIP ? &TLIP->getTLI(F) : nullptr; + TargetLibraryInfo *TLI = + &getAnalysis().getTLI(F); return eliminateDeadCode(F, TLI); } void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); AU.setPreservesCFG(); } }; diff --git a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp index e58db03225ee..2979225c6016 100644 --- a/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp +++ b/llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp @@ -84,10 +84,13 @@ STATISTIC(NumFastStores, "Number of stores deleted"); STATISTIC(NumFastOther, "Number of other instrs removed"); STATISTIC(NumCompletePartials, "Number of stores dead by later partials"); STATISTIC(NumModifiedStores, "Number of stores modified"); -STATISTIC(NumNoopStores, "Number of noop stores deleted"); STATISTIC(NumCFGChecks, "Number of stores modified"); STATISTIC(NumCFGTries, "Number of stores modified"); STATISTIC(NumCFGSuccess, "Number of stores modified"); +STATISTIC(NumGetDomMemoryDefPassed, + "Number of times a valid candidate is returned from getDomMemoryDef"); +STATISTIC(NumDomMemDefChecks, + "Number iterations check for reads in getDomMemoryDef"); DEBUG_COUNTER(MemorySSACounter, "dse-memoryssa", "Controls which MemoryDefs are eliminated."); @@ -103,19 +106,42 @@ EnablePartialStoreMerging("enable-dse-partial-store-merging", cl::desc("Enable partial store merging in DSE")); static cl::opt - EnableMemorySSA("enable-dse-memoryssa", cl::init(false), cl::Hidden, + EnableMemorySSA("enable-dse-memoryssa", cl::init(true), cl::Hidden, cl::desc("Use the new MemorySSA-backed DSE.")); static cl::opt - MemorySSAScanLimit("dse-memoryssa-scanlimit", cl::init(100), cl::Hidden, + MemorySSAScanLimit("dse-memoryssa-scanlimit", cl::init(150), cl::Hidden, cl::desc("The number of memory instructions to scan for " "dead store elimination (default = 100)")); +static cl::opt MemorySSAUpwardsStepLimit( + "dse-memoryssa-walklimit", cl::init(90), cl::Hidden, + cl::desc("The maximum number of steps while walking upwards to find " + "MemoryDefs that may be killed (default = 90)")); + +static cl::opt MemorySSAPartialStoreLimit( + "dse-memoryssa-partial-store-limit", cl::init(5), cl::Hidden, + cl::desc("The maximum number candidates that only partially overwrite the " + "killing MemoryDef to consider" + " (default = 5)")); static cl::opt MemorySSADefsPerBlockLimit( "dse-memoryssa-defs-per-block-limit", cl::init(5000), cl::Hidden, cl::desc("The number of MemoryDefs we consider as candidates to eliminated " "other stores per basic block (default = 5000)")); +static cl::opt MemorySSASameBBStepCost( + "dse-memoryssa-samebb-cost", cl::init(1), cl::Hidden, + cl::desc( + "The cost of a step in the same basic block as the killing MemoryDef" + "(default = 1)")); + +static cl::opt + MemorySSAOtherBBStepCost("dse-memoryssa-otherbb-cost", cl::init(5), + cl::Hidden, + cl::desc("The cost of a step in a different basic " + "block than the killing MemoryDef" + "(default = 5)")); + static cl::opt MemorySSAPathCheckLimit( "dse-memoryssa-path-check-limit", cl::init(50), cl::Hidden, cl::desc("The maximum number of blocks to check when trying to prove that " @@ -203,11 +229,13 @@ static bool hasAnalyzableMemoryWrite(Instruction *I, case Intrinsic::memset: case Intrinsic::memmove: case Intrinsic::memcpy: + case Intrinsic::memcpy_inline: case Intrinsic::memcpy_element_unordered_atomic: case Intrinsic::memmove_element_unordered_atomic: case Intrinsic::memset_element_unordered_atomic: case Intrinsic::init_trampoline: case Intrinsic::lifetime_end: + case Intrinsic::masked_store: return true; } } @@ -231,23 +259,23 @@ static bool hasAnalyzableMemoryWrite(Instruction *I, /// Return a Location stored to by the specified instruction. If isRemovable /// returns true, this function and getLocForRead completely describe the memory /// operations for this instruction. -static MemoryLocation getLocForWrite(Instruction *Inst) { - +static MemoryLocation getLocForWrite(Instruction *Inst, + const TargetLibraryInfo &TLI) { if (StoreInst *SI = dyn_cast(Inst)) return MemoryLocation::get(SI); - if (auto *MI = dyn_cast(Inst)) { - // memcpy/memmove/memset. - MemoryLocation Loc = MemoryLocation::getForDest(MI); - return Loc; - } + // memcpy/memmove/memset. + if (auto *MI = dyn_cast(Inst)) + return MemoryLocation::getForDest(MI); if (IntrinsicInst *II = dyn_cast(Inst)) { switch (II->getIntrinsicID()) { default: return MemoryLocation(); // Unhandled intrinsic. case Intrinsic::init_trampoline: - return MemoryLocation(II->getArgOperand(0)); + return MemoryLocation::getAfter(II->getArgOperand(0)); + case Intrinsic::masked_store: + return MemoryLocation::getForArgument(II, 1, TLI); case Intrinsic::lifetime_end: { uint64_t Len = cast(II->getArgOperand(0))->getZExtValue(); return MemoryLocation(II->getArgOperand(1), Len); @@ -257,7 +285,7 @@ static MemoryLocation getLocForWrite(Instruction *Inst) { if (auto *CB = dyn_cast(Inst)) // All the supported TLI functions so far happen to have dest as their // first argument. - return MemoryLocation(CB->getArgOperand(0)); + return MemoryLocation::getAfter(CB->getArgOperand(0)); return MemoryLocation(); } @@ -294,11 +322,13 @@ static bool isRemovable(Instruction *I) { case Intrinsic::memset: case Intrinsic::memmove: case Intrinsic::memcpy: + case Intrinsic::memcpy_inline: // Don't remove volatile memory intrinsics. return !cast(II)->isVolatile(); case Intrinsic::memcpy_element_unordered_atomic: case Intrinsic::memmove_element_unordered_atomic: case Intrinsic::memset_element_unordered_atomic: + case Intrinsic::masked_store: return true; } } @@ -344,9 +374,10 @@ static bool isShortenableAtTheBeginning(Instruction *I) { } /// Return the pointer that is being written to. -static Value *getStoredPointerOperand(Instruction *I) { +static Value *getStoredPointerOperand(Instruction *I, + const TargetLibraryInfo &TLI) { //TODO: factor this to reuse getLocForWrite - MemoryLocation Loc = getLocForWrite(I); + MemoryLocation Loc = getLocForWrite(I, TLI); assert(Loc.Ptr && "unable to find pointer written for analyzable instruction?"); // TODO: most APIs don't expect const Value * @@ -372,31 +403,59 @@ enum OverwriteResult { OW_Complete, OW_End, OW_PartialEarlierWithFullLater, + OW_MaybePartial, OW_Unknown }; } // end anonymous namespace -/// Return 'OW_Complete' if a store to the 'Later' location completely -/// overwrites a store to the 'Earlier' location, 'OW_End' if the end of the -/// 'Earlier' location is completely overwritten by 'Later', 'OW_Begin' if the -/// beginning of the 'Earlier' location is overwritten by 'Later'. -/// 'OW_PartialEarlierWithFullLater' means that an earlier (big) store was -/// overwritten by a latter (smaller) store which doesn't write outside the big -/// store's memory locations. Returns 'OW_Unknown' if nothing can be determined. -static OverwriteResult isOverwrite(const MemoryLocation &Later, - const MemoryLocation &Earlier, - const DataLayout &DL, - const TargetLibraryInfo &TLI, - int64_t &EarlierOff, int64_t &LaterOff, - Instruction *DepWrite, - InstOverlapIntervalsTy &IOL, - AliasAnalysis &AA, - const Function *F) { +/// Check if two instruction are masked stores that completely +/// overwrite one another. More specifically, \p Later has to +/// overwrite \p Earlier. +template +static OverwriteResult isMaskedStoreOverwrite(const Instruction *Later, + const Instruction *Earlier, + AATy &AA) { + const auto *IIL = dyn_cast(Later); + const auto *IIE = dyn_cast(Earlier); + if (IIL == nullptr || IIE == nullptr) + return OW_Unknown; + if (IIL->getIntrinsicID() != Intrinsic::masked_store || + IIE->getIntrinsicID() != Intrinsic::masked_store) + return OW_Unknown; + // Pointers. + Value *LP = IIL->getArgOperand(1)->stripPointerCasts(); + Value *EP = IIE->getArgOperand(1)->stripPointerCasts(); + if (LP != EP && !AA.isMustAlias(LP, EP)) + return OW_Unknown; + // Masks. + // TODO: check that Later's mask is a superset of the Earlier's mask. + if (IIL->getArgOperand(3) != IIE->getArgOperand(3)) + return OW_Unknown; + return OW_Complete; +} + +/// Return 'OW_Complete' if a store to the 'Later' location (by \p LaterI +/// instruction) completely overwrites a store to the 'Earlier' location. +/// (by \p EarlierI instruction). +/// Return OW_MaybePartial if \p Later does not completely overwrite +/// \p Earlier, but they both write to the same underlying object. In that +/// case, use isPartialOverwrite to check if \p Later partially overwrites +/// \p Earlier. Returns 'OW_Unknown' if nothing can be determined. +template +static OverwriteResult +isOverwrite(const Instruction *LaterI, const Instruction *EarlierI, + const MemoryLocation &Later, const MemoryLocation &Earlier, + const DataLayout &DL, const TargetLibraryInfo &TLI, + int64_t &EarlierOff, int64_t &LaterOff, AATy &AA, + const Function *F) { // FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll // get imprecise values here, though (except for unknown sizes). - if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) - return OW_Unknown; + if (!Later.Size.isPrecise() || !Earlier.Size.isPrecise()) { + // Masked stores have imprecise locations, but we can reason about them + // to some extent. + return isMaskedStoreOverwrite(LaterI, EarlierI, AA); + } const uint64_t LaterSize = Later.Size.getValue(); const uint64_t EarlierSize = Earlier.Size.getValue(); @@ -415,8 +474,7 @@ static OverwriteResult isOverwrite(const MemoryLocation &Later, // Check to see if the later store is to the entire object (either a global, // an alloca, or a byval/inalloca argument). If so, then it clearly // overwrites any other store to the same object. - const Value *UO1 = GetUnderlyingObject(P1, DL), - *UO2 = GetUnderlyingObject(P2, DL); + const Value *UO1 = getUnderlyingObject(P1), *UO2 = getUnderlyingObject(P2); // If we can't resolve the same pointers to the same object, then we can't // analyze them at all. @@ -441,26 +499,59 @@ static OverwriteResult isOverwrite(const MemoryLocation &Later, if (BP1 != BP2) return OW_Unknown; - // The later store completely overlaps the earlier store if: - // - // 1. Both start at the same offset and the later one's size is greater than - // or equal to the earlier one's, or - // - // |--earlier--| - // |-- later --| - // - // 2. The earlier store has an offset greater than the later offset, but which - // still lies completely within the later store. - // - // |--earlier--| - // |----- later ------| + // The later access completely overlaps the earlier store if and only if + // both start and end of the earlier one is "inside" the later one: + // |<->|--earlier--|<->| + // |-------later-------| + // Accesses may overlap if and only if start of one of them is "inside" + // another one: + // |<->|--earlier--|<----->| + // |-------later-------| + // OR + // |----- earlier -----| + // |<->|---later---|<----->| // // We have to be careful here as *Off is signed while *.Size is unsigned. - if (EarlierOff >= LaterOff && - LaterSize >= EarlierSize && - uint64_t(EarlierOff - LaterOff) + EarlierSize <= LaterSize) - return OW_Complete; + // Check if the earlier access starts "not before" the later one. + if (EarlierOff >= LaterOff) { + // If the earlier access ends "not after" the later access then the earlier + // one is completely overwritten by the later one. + if (uint64_t(EarlierOff - LaterOff) + EarlierSize <= LaterSize) + return OW_Complete; + // If start of the earlier access is "before" end of the later access then + // accesses overlap. + else if ((uint64_t)(EarlierOff - LaterOff) < LaterSize) + return OW_MaybePartial; + } + // If start of the later access is "before" end of the earlier access then + // accesses overlap. + else if ((uint64_t)(LaterOff - EarlierOff) < EarlierSize) { + return OW_MaybePartial; + } + + // Can reach here only if accesses are known not to overlap. There is no + // dedicated code to indicate no overlap so signal "unknown". + return OW_Unknown; +} + +/// Return 'OW_Complete' if a store to the 'Later' location completely +/// overwrites a store to the 'Earlier' location, 'OW_End' if the end of the +/// 'Earlier' location is completely overwritten by 'Later', 'OW_Begin' if the +/// beginning of the 'Earlier' location is overwritten by 'Later'. +/// 'OW_PartialEarlierWithFullLater' means that an earlier (big) store was +/// overwritten by a latter (smaller) store which doesn't write outside the big +/// store's memory locations. Returns 'OW_Unknown' if nothing can be determined. +/// NOTE: This function must only be called if both \p Later and \p Earlier +/// write to the same underlying object with valid \p EarlierOff and \p +/// LaterOff. +static OverwriteResult isPartialOverwrite(const MemoryLocation &Later, + const MemoryLocation &Earlier, + int64_t EarlierOff, int64_t LaterOff, + Instruction *DepWrite, + InstOverlapIntervalsTy &IOL) { + const uint64_t LaterSize = Later.Size.getValue(); + const uint64_t EarlierSize = Earlier.Size.getValue(); // We may now overlap, although the overlap is not complete. There might also // be other incomplete overlaps, and together, they might cover the complete // earlier write. @@ -627,11 +718,10 @@ static bool isPossibleSelfRead(Instruction *Inst, /// modified between the first and the second instruction. /// Precondition: Second instruction must be dominated by the first /// instruction. -static bool memoryIsNotModifiedBetween(Instruction *FirstI, - Instruction *SecondI, - AliasAnalysis *AA, - const DataLayout &DL, - DominatorTree *DT) { +template +static bool +memoryIsNotModifiedBetween(Instruction *FirstI, Instruction *SecondI, AATy &AA, + const DataLayout &DL, DominatorTree *DT) { // Do a backwards scan through the CFG from SecondI to FirstI. Look for // instructions which can modify the memory location accessed by SecondI. // @@ -680,7 +770,7 @@ static bool memoryIsNotModifiedBetween(Instruction *FirstI, for (; BI != EI; ++BI) { Instruction *I = &*BI; if (I->mayWriteToMemory() && I != SecondI) - if (isModSet(AA->getModRefInfo(I, MemLoc.getWithNewPtr(Ptr)))) + if (isModSet(AA.getModRefInfo(I, MemLoc.getWithNewPtr(Ptr)))) return false; } if (B != FirstBB) { @@ -736,10 +826,9 @@ static bool handleFree(CallInst *F, AliasAnalysis *AA, MapVector &ThrowableInst) { bool MadeChange = false; - MemoryLocation Loc = MemoryLocation(F->getOperand(0)); + MemoryLocation Loc = MemoryLocation::getAfter(F->getOperand(0)); SmallVector Blocks; Blocks.push_back(F->getParent()); - const DataLayout &DL = F->getModule()->getDataLayout(); while (!Blocks.empty()) { BasicBlock *BB = Blocks.pop_back_val(); @@ -755,7 +844,7 @@ static bool handleFree(CallInst *F, AliasAnalysis *AA, break; Value *DepPointer = - GetUnderlyingObject(getStoredPointerOperand(Dependency), DL); + getUnderlyingObject(getStoredPointerOperand(Dependency, *TLI)); // Check for aliasing. if (!AA->isMustAlias(F->getArgOperand(0), DepPointer)) @@ -795,7 +884,7 @@ static void removeAccessedObjects(const MemoryLocation &LoadedLoc, const DataLayout &DL, AliasAnalysis *AA, const TargetLibraryInfo *TLI, const Function *F) { - const Value *UnderlyingPointer = GetUnderlyingObject(LoadedLoc.Ptr, DL); + const Value *UnderlyingPointer = getUnderlyingObject(LoadedLoc.Ptr); // A constant can't be in the dead pointer set. if (isa(UnderlyingPointer)) @@ -848,7 +937,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, // Treat byval or inalloca arguments the same, stores to them are dead at the // end of the function. for (Argument &AI : BB.getParent()->args()) - if (AI.hasPassPointeeByValueAttr()) + if (AI.hasPassPointeeByValueCopyAttr()) DeadStackObjects.insert(&AI); const DataLayout &DL = BB.getModule()->getDataLayout(); @@ -861,7 +950,7 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, if (hasAnalyzableMemoryWrite(&*BBI, *TLI) && isRemovable(&*BBI)) { // See through pointer-to-pointer bitcasts SmallVector Pointers; - GetUnderlyingObjects(getStoredPointerOperand(&*BBI), Pointers, DL); + getUnderlyingObjects(getStoredPointerOperand(&*BBI, *TLI), Pointers); // Stores to stack values are valid candidates for removal. bool AllDead = true; @@ -980,8 +1069,8 @@ static bool handleEndBlock(BasicBlock &BB, AliasAnalysis *AA, } static bool tryToShorten(Instruction *EarlierWrite, int64_t &EarlierOffset, - int64_t &EarlierSize, int64_t LaterOffset, - int64_t LaterSize, bool IsOverwriteEnd) { + uint64_t &EarlierSize, int64_t LaterOffset, + uint64_t LaterSize, bool IsOverwriteEnd) { // TODO: base this on the target vector size so that if the earlier // store was too small to get vector writes anyway then its likely // a good idea to shorten it @@ -1036,16 +1125,23 @@ static bool tryToShorten(Instruction *EarlierWrite, int64_t &EarlierOffset, static bool tryToShortenEnd(Instruction *EarlierWrite, OverlapIntervalsTy &IntervalMap, - int64_t &EarlierStart, int64_t &EarlierSize) { + int64_t &EarlierStart, uint64_t &EarlierSize) { if (IntervalMap.empty() || !isShortenableAtTheEnd(EarlierWrite)) return false; OverlapIntervalsTy::iterator OII = --IntervalMap.end(); int64_t LaterStart = OII->second; - int64_t LaterSize = OII->first - LaterStart; + uint64_t LaterSize = OII->first - LaterStart; + + assert(OII->first - LaterStart >= 0 && "Size expected to be positive"); - if (LaterStart > EarlierStart && LaterStart < EarlierStart + EarlierSize && - LaterStart + LaterSize >= EarlierStart + EarlierSize) { + if (LaterStart > EarlierStart && + // Note: "LaterStart - EarlierStart" is known to be positive due to + // preceding check. + (uint64_t)(LaterStart - EarlierStart) < EarlierSize && + // Note: "EarlierSize - (uint64_t)(LaterStart - EarlierStart)" is known to + // be non negative due to preceding checks. + LaterSize >= EarlierSize - (uint64_t)(LaterStart - EarlierStart)) { if (tryToShorten(EarlierWrite, EarlierStart, EarlierSize, LaterStart, LaterSize, true)) { IntervalMap.erase(OII); @@ -1057,16 +1153,23 @@ static bool tryToShortenEnd(Instruction *EarlierWrite, static bool tryToShortenBegin(Instruction *EarlierWrite, OverlapIntervalsTy &IntervalMap, - int64_t &EarlierStart, int64_t &EarlierSize) { + int64_t &EarlierStart, uint64_t &EarlierSize) { if (IntervalMap.empty() || !isShortenableAtTheBeginning(EarlierWrite)) return false; OverlapIntervalsTy::iterator OII = IntervalMap.begin(); int64_t LaterStart = OII->second; - int64_t LaterSize = OII->first - LaterStart; + uint64_t LaterSize = OII->first - LaterStart; - if (LaterStart <= EarlierStart && LaterStart + LaterSize > EarlierStart) { - assert(LaterStart + LaterSize < EarlierStart + EarlierSize && + assert(OII->first - LaterStart >= 0 && "Size expected to be positive"); + + if (LaterStart <= EarlierStart && + // Note: "EarlierStart - LaterStart" is known to be non negative due to + // preceding check. + LaterSize > (uint64_t)(EarlierStart - LaterStart)) { + // Note: "LaterSize - (uint64_t)(EarlierStart - LaterStart)" is known to be + // positive due to preceding checks. + assert(LaterSize - (uint64_t)(EarlierStart - LaterStart) < EarlierSize && "Should have been handled as OW_Complete"); if (tryToShorten(EarlierWrite, EarlierStart, EarlierSize, LaterStart, LaterSize, false)) { @@ -1077,18 +1180,18 @@ static bool tryToShortenBegin(Instruction *EarlierWrite, return false; } -static bool removePartiallyOverlappedStores(AliasAnalysis *AA, - const DataLayout &DL, - InstOverlapIntervalsTy &IOL) { +static bool removePartiallyOverlappedStores(const DataLayout &DL, + InstOverlapIntervalsTy &IOL, + const TargetLibraryInfo &TLI) { bool Changed = false; for (auto OI : IOL) { Instruction *EarlierWrite = OI.first; - MemoryLocation Loc = getLocForWrite(EarlierWrite); + MemoryLocation Loc = getLocForWrite(EarlierWrite, TLI); assert(isRemovable(EarlierWrite) && "Expect only removable instruction"); const Value *Ptr = Loc.Ptr->stripPointerCasts(); int64_t EarlierStart = 0; - int64_t EarlierSize = int64_t(Loc.Size.getValue()); + uint64_t EarlierSize = Loc.Size.getValue(); GetPointerBaseWithConstantOffset(Ptr, EarlierStart, DL); OverlapIntervalsTy &IntervalMap = OI.second; Changed |= @@ -1118,7 +1221,7 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, if (LoadInst *DepLoad = dyn_cast(SI->getValueOperand())) { if (SI->getPointerOperand() == DepLoad->getPointerOperand() && isRemovable(SI) && - memoryIsNotModifiedBetween(DepLoad, SI, AA, DL, DT)) { + memoryIsNotModifiedBetween(DepLoad, SI, *AA, DL, DT)) { LLVM_DEBUG( dbgs() << "DSE: Remove Store Of Load from same pointer:\n LOAD: " @@ -1134,10 +1237,10 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, Constant *StoredConstant = dyn_cast(SI->getValueOperand()); if (StoredConstant && StoredConstant->isNullValue() && isRemovable(SI)) { Instruction *UnderlyingPointer = - dyn_cast(GetUnderlyingObject(SI->getPointerOperand(), DL)); + dyn_cast(getUnderlyingObject(SI->getPointerOperand())); if (UnderlyingPointer && isCallocLikeFn(UnderlyingPointer, TLI) && - memoryIsNotModifiedBetween(UnderlyingPointer, SI, AA, DL, DT)) { + memoryIsNotModifiedBetween(UnderlyingPointer, SI, *AA, DL, DT)) { LLVM_DEBUG( dbgs() << "DSE: Remove null store to the calloc'ed object:\n DEAD: " << *Inst << "\n OBJECT: " << *UnderlyingPointer << '\n'); @@ -1150,11 +1253,10 @@ static bool eliminateNoopStore(Instruction *Inst, BasicBlock::iterator &BBI, return false; } -static Constant * -tryToMergePartialOverlappingStores(StoreInst *Earlier, StoreInst *Later, - int64_t InstWriteOffset, - int64_t DepWriteOffset, const DataLayout &DL, - AliasAnalysis *AA, DominatorTree *DT) { +template +static Constant *tryToMergePartialOverlappingStores( + StoreInst *Earlier, StoreInst *Later, int64_t InstWriteOffset, + int64_t DepWriteOffset, const DataLayout &DL, AATy &AA, DominatorTree *DT) { if (Earlier && isa(Earlier->getValueOperand()) && DL.typeSizeEqualsStoreSize(Earlier->getValueOperand()->getType()) && @@ -1245,7 +1347,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, continue; // Figure out what location is being stored to. - MemoryLocation Loc = getLocForWrite(Inst); + MemoryLocation Loc = getLocForWrite(Inst, *TLI); // If we didn't get a useful location, fail. if (!Loc.Ptr) @@ -1269,7 +1371,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, Instruction *DepWrite = InstDep.getInst(); if (!hasAnalyzableMemoryWrite(DepWrite, *TLI)) break; - MemoryLocation DepLoc = getLocForWrite(DepWrite); + MemoryLocation DepLoc = getLocForWrite(DepWrite, *TLI); // If we didn't get a useful location, or if it isn't a size, bail out. if (!DepLoc.Ptr) break; @@ -1289,7 +1391,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, // to it is dead along the unwind edge. Otherwise, we need to preserve // the store. if (LastThrowing && DepWrite->comesBefore(LastThrowing)) { - const Value* Underlying = GetUnderlyingObject(DepLoc.Ptr, DL); + const Value *Underlying = getUnderlyingObject(DepLoc.Ptr); bool IsStoreDeadOnUnwind = isa(Underlying); if (!IsStoreDeadOnUnwind) { // We're looking for a call to an allocation function @@ -1311,9 +1413,13 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, if (isRemovable(DepWrite) && !isPossibleSelfRead(Inst, Loc, DepWrite, *TLI, *AA)) { int64_t InstWriteOffset, DepWriteOffset; - OverwriteResult OR = isOverwrite(Loc, DepLoc, DL, *TLI, DepWriteOffset, - InstWriteOffset, DepWrite, IOL, *AA, + OverwriteResult OR = isOverwrite(Inst, DepWrite, Loc, DepLoc, DL, *TLI, + DepWriteOffset, InstWriteOffset, *AA, BB.getParent()); + if (OR == OW_MaybePartial) + OR = isPartialOverwrite(Loc, DepLoc, DepWriteOffset, InstWriteOffset, + DepWrite, IOL); + if (OR == OW_Complete) { LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n DEAD: " << *DepWrite << "\n KILLER: " << *Inst << '\n'); @@ -1334,8 +1440,8 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, "when partial-overwrite " "tracking is enabled"); // The overwrite result is known, so these must be known, too. - int64_t EarlierSize = DepLoc.Size.getValue(); - int64_t LaterSize = Loc.Size.getValue(); + uint64_t EarlierSize = DepLoc.Size.getValue(); + uint64_t LaterSize = Loc.Size.getValue(); bool IsOverwriteEnd = (OR == OW_End); MadeChange |= tryToShorten(DepWrite, DepWriteOffset, EarlierSize, InstWriteOffset, LaterSize, IsOverwriteEnd); @@ -1344,7 +1450,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, auto *Earlier = dyn_cast(DepWrite); auto *Later = dyn_cast(Inst); if (Constant *C = tryToMergePartialOverlappingStores( - Earlier, Later, InstWriteOffset, DepWriteOffset, DL, AA, + Earlier, Later, InstWriteOffset, DepWriteOffset, DL, *AA, DT)) { auto *SI = new StoreInst( C, Earlier->getPointerOperand(), false, Earlier->getAlign(), @@ -1391,7 +1497,7 @@ static bool eliminateDeadStores(BasicBlock &BB, AliasAnalysis *AA, } if (EnablePartialOverwriteTracking) - MadeChange |= removePartiallyOverlappedStores(AA, DL, IOL); + MadeChange |= removePartiallyOverlappedStores(DL, IOL, *TLI); // If this block ends in a return, unwind, or unreachable, all allocas are // dead at its end, which means stores to them are also dead. @@ -1425,20 +1531,21 @@ namespace { // in between both MemoryDefs. A bit more concretely: // // For all MemoryDefs StartDef: -// 1. Get the next dominating clobbering MemoryDef (DomAccess) by walking +// 1. Get the next dominating clobbering MemoryDef (EarlierAccess) by walking // upwards. -// 2. Check that there are no reads between DomAccess and the StartDef by -// checking all uses starting at DomAccess and walking until we see StartDef. -// 3. For each found DomDef, check that: -// 1. There are no barrier instructions between DomDef and StartDef (like +// 2. Check that there are no reads between EarlierAccess and the StartDef by +// checking all uses starting at EarlierAccess and walking until we see +// StartDef. +// 3. For each found CurrentDef, check that: +// 1. There are no barrier instructions between CurrentDef and StartDef (like // throws or stores with ordering constraints). -// 2. StartDef is executed whenever DomDef is executed. -// 3. StartDef completely overwrites DomDef. -// 4. Erase DomDef from the function and MemorySSA. +// 2. StartDef is executed whenever CurrentDef is executed. +// 3. StartDef completely overwrites CurrentDef. +// 4. Erase CurrentDef from the function and MemorySSA. -// Returns true if \p M is an intrisnic that does not read or write memory. -bool isNoopIntrinsic(MemoryUseOrDef *M) { - if (const IntrinsicInst *II = dyn_cast(M->getMemoryInst())) { +// Returns true if \p I is an intrisnic that does not read or write memory. +bool isNoopIntrinsic(Instruction *I) { + if (const IntrinsicInst *II = dyn_cast(I)) { switch (II->getIntrinsicID()) { case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: @@ -1481,7 +1588,7 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) { return true; // Skip intrinsics that do not really read or modify memory. - if (isNoopIntrinsic(D)) + if (isNoopIntrinsic(D->getMemoryInst())) return true; return false; @@ -1490,10 +1597,21 @@ bool canSkipDef(MemoryDef *D, bool DefVisibleToCaller) { struct DSEState { Function &F; AliasAnalysis &AA; + + /// The single BatchAA instance that is used to cache AA queries. It will + /// not be invalidated over the whole run. This is safe, because: + /// 1. Only memory writes are removed, so the alias cache for memory + /// locations remains valid. + /// 2. No new instructions are added (only instructions removed), so cached + /// information for a deleted value cannot be accessed by a re-used new + /// value pointer. + BatchAAResults BatchAA; + MemorySSA &MSSA; DominatorTree &DT; PostDominatorTree &PDT; const TargetLibraryInfo &TLI; + const DataLayout &DL; // All MemoryDefs that potentially could kill other MemDefs. SmallVector MemDefs; @@ -1501,10 +1619,11 @@ struct DSEState { SmallPtrSet SkipStores; // Keep track of all of the objects that are invisible to the caller before // the function returns. - SmallPtrSet InvisibleToCallerBeforeRet; + // SmallPtrSet InvisibleToCallerBeforeRet; + DenseMap InvisibleToCallerBeforeRet; // Keep track of all of the objects that are invisible to the caller after // the function returns. - SmallPtrSet InvisibleToCallerAfterRet; + DenseMap InvisibleToCallerAfterRet; // Keep track of blocks with throwing instructions not modeled in MemorySSA. SmallPtrSet ThrowingBlocks; // Post-order numbers for each basic block. Used to figure out if memory @@ -1517,7 +1636,8 @@ struct DSEState { DSEState(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT, const TargetLibraryInfo &TLI) - : F(F), AA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI) {} + : F(F), AA(AA), BatchAA(AA), MSSA(MSSA), DT(DT), PDT(PDT), TLI(TLI), + DL(F.getParent()->getDataLayout()) {} static DSEState get(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT, @@ -1537,42 +1657,54 @@ struct DSEState { if (MD && State.MemDefs.size() < MemorySSADefsPerBlockLimit && (State.getLocForWriteEx(&I) || State.isMemTerminatorInst(&I))) State.MemDefs.push_back(MD); - - // Track whether alloca and alloca-like objects are visible in the - // caller before and after the function returns. Alloca objects are - // invalid in the caller, so they are neither visible before or after - // the function returns. - if (isa(&I)) { - State.InvisibleToCallerBeforeRet.insert(&I); - State.InvisibleToCallerAfterRet.insert(&I); - } - - // For alloca-like objects we need to check if they are captured before - // the function returns and if the return might capture the object. - if (isAllocLikeFn(&I, &TLI)) { - bool CapturesBeforeRet = PointerMayBeCaptured(&I, false, true); - if (!CapturesBeforeRet) { - State.InvisibleToCallerBeforeRet.insert(&I); - if (!PointerMayBeCaptured(&I, true, false)) - State.InvisibleToCallerAfterRet.insert(&I); - } - } } } // Treat byval or inalloca arguments the same as Allocas, stores to them are // dead at the end of the function. for (Argument &AI : F.args()) - if (AI.hasPassPointeeByValueAttr()) { + if (AI.hasPassPointeeByValueCopyAttr()) { // For byval, the caller doesn't know the address of the allocation. if (AI.hasByValAttr()) - State.InvisibleToCallerBeforeRet.insert(&AI); - State.InvisibleToCallerAfterRet.insert(&AI); + State.InvisibleToCallerBeforeRet.insert({&AI, true}); + State.InvisibleToCallerAfterRet.insert({&AI, true}); } return State; } + bool isInvisibleToCallerAfterRet(const Value *V) { + if (isa(V)) + return true; + auto I = InvisibleToCallerAfterRet.insert({V, false}); + if (I.second) { + if (!isInvisibleToCallerBeforeRet(V)) { + I.first->second = false; + } else { + auto *Inst = dyn_cast(V); + if (Inst && isAllocLikeFn(Inst, &TLI)) + I.first->second = !PointerMayBeCaptured(V, true, false); + } + } + return I.first->second; + } + + bool isInvisibleToCallerBeforeRet(const Value *V) { + if (isa(V)) + return true; + auto I = InvisibleToCallerBeforeRet.insert({V, false}); + if (I.second) { + auto *Inst = dyn_cast(V); + if (Inst && isAllocLikeFn(Inst, &TLI)) + // NOTE: This could be made more precise by PointerMayBeCapturedBefore + // with the killing MemoryDef. But we refrain from doing so for now to + // limit compile-time and this does not cause any changes to the number + // of stores removed on a large test set in practice. + I.first->second = !PointerMayBeCaptured(V, false, true); + } + return I.first->second; + } + Optional getLocForWriteEx(Instruction *I) const { if (!I->mayWriteToMemory()) return None; @@ -1581,6 +1713,11 @@ struct DSEState { return {MemoryLocation::getForDest(MTI)}; if (auto *CB = dyn_cast(I)) { + // If the functions may write to memory we do not know about, bail out. + if (!CB->onlyAccessesArgMemory() && + !CB->onlyAccessesInaccessibleMemOrArgMem()) + return None; + LibFunc LF; if (TLI.getLibFunc(*CB, LF) && TLI.has(LF)) { switch (LF) { @@ -1588,19 +1725,29 @@ struct DSEState { case LibFunc_strncpy: case LibFunc_strcat: case LibFunc_strncat: - return {MemoryLocation(CB->getArgOperand(0))}; + return {MemoryLocation::getAfter(CB->getArgOperand(0))}; default: break; } } + switch (CB->getIntrinsicID()) { + case Intrinsic::init_trampoline: + return {MemoryLocation::getAfter(CB->getArgOperand(0))}; + case Intrinsic::masked_store: + return {MemoryLocation::getForArgument(CB, 1, TLI)}; + default: + break; + } return None; } return MemoryLocation::getOrNone(I); } - /// Returns true if \p Use completely overwrites \p DefLoc. - bool isCompleteOverwrite(MemoryLocation DefLoc, Instruction *UseInst) const { + /// Returns true if \p UseInst completely overwrites \p DefLoc + /// (stored by \p DefInst). + bool isCompleteOverwrite(const MemoryLocation &DefLoc, Instruction *DefInst, + Instruction *UseInst) { // UseInst has a MemoryDef associated in MemorySSA. It's possible for a // MemoryDef to not write to memory, e.g. a volatile load is modeled as a // MemoryDef. @@ -1612,14 +1759,10 @@ struct DSEState { return false; int64_t InstWriteOffset, DepWriteOffset; - auto CC = getLocForWriteEx(UseInst); - InstOverlapIntervalsTy IOL; - - const DataLayout &DL = F.getParent()->getDataLayout(); - - return CC && - isOverwrite(*CC, DefLoc, DL, TLI, DepWriteOffset, InstWriteOffset, - UseInst, IOL, AA, &F) == OW_Complete; + if (auto CC = getLocForWriteEx(UseInst)) + return isOverwrite(UseInst, DefInst, *CC, DefLoc, DL, TLI, DepWriteOffset, + InstWriteOffset, BatchAA, &F) == OW_Complete; + return false; } /// Returns true if \p Def is not read before returning from the function. @@ -1650,10 +1793,12 @@ struct DSEState { } MemoryAccess *UseAccess = WorkList[I]; - if (isa(UseAccess)) { - PushMemUses(UseAccess); - continue; - } + // Simply adding the users of MemoryPhi to the worklist is not enough, + // because we might miss read clobbers in different iterations of a loop, + // for example. + // TODO: Add support for phi translation to handle the loop case. + if (isa(UseAccess)) + return false; // TODO: Checking for aliasing is expensive. Consider reducing the amount // of times this is called and/or caching it. @@ -1682,7 +1827,8 @@ struct DSEState { if (auto *CB = dyn_cast(I)) { if (isFreeCall(I, &TLI)) - return {std::make_pair(MemoryLocation(CB->getArgOperand(0)), true)}; + return {std::make_pair(MemoryLocation::getAfter(CB->getArgOperand(0)), + true)}; } return None; @@ -1696,9 +1842,10 @@ struct DSEState { isFreeCall(I, &TLI); } - /// Returns true if \p MaybeTerm is a memory terminator for the same - /// underlying object as \p DefLoc. - bool isMemTerminator(MemoryLocation DefLoc, Instruction *MaybeTerm) const { + /// Returns true if \p MaybeTerm is a memory terminator for \p Loc from + /// instruction \p AccessI. + bool isMemTerminator(const MemoryLocation &Loc, Instruction *AccessI, + Instruction *MaybeTerm) { Optional> MaybeTermLoc = getLocForTerminator(MaybeTerm); @@ -1707,15 +1854,31 @@ struct DSEState { // If the terminator is a free-like call, all accesses to the underlying // object can be considered terminated. + if (getUnderlyingObject(Loc.Ptr) != + getUnderlyingObject(MaybeTermLoc->first.Ptr)) + return false; + + auto TermLoc = MaybeTermLoc->first; if (MaybeTermLoc->second) { - DataLayout DL = MaybeTerm->getParent()->getModule()->getDataLayout(); - DefLoc = MemoryLocation(GetUnderlyingObject(DefLoc.Ptr, DL)); + const Value *LocUO = getUnderlyingObject(Loc.Ptr); + return BatchAA.isMustAlias(TermLoc.Ptr, LocUO); } - return AA.isMustAlias(MaybeTermLoc->first, DefLoc); + int64_t InstWriteOffset, DepWriteOffset; + return isOverwrite(MaybeTerm, AccessI, TermLoc, Loc, DL, TLI, + DepWriteOffset, InstWriteOffset, BatchAA, + &F) == OW_Complete; } // Returns true if \p Use may read from \p DefLoc. - bool isReadClobber(MemoryLocation DefLoc, Instruction *UseInst) const { + bool isReadClobber(const MemoryLocation &DefLoc, Instruction *UseInst) { + if (isNoopIntrinsic(UseInst)) + return false; + + // Monotonic or weaker atomic stores can be re-ordered and do not need to be + // treated as read clobber. + if (auto SI = dyn_cast(UseInst)) + return isStrongerThan(SI->getOrdering(), AtomicOrdering::Monotonic); + if (!UseInst->mayReadFromMemory()) return false; @@ -1723,88 +1886,246 @@ struct DSEState { if (CB->onlyAccessesInaccessibleMemory()) return false; - ModRefInfo MR = AA.getModRefInfo(UseInst, DefLoc); - // If necessary, perform additional analysis. - if (isRefSet(MR)) - MR = AA.callCapturesBefore(UseInst, DefLoc, &DT); - return isRefSet(MR); + // NOTE: For calls, the number of stores removed could be slightly improved + // by using AA.callCapturesBefore(UseInst, DefLoc, &DT), but that showed to + // be expensive compared to the benefits in practice. For now, avoid more + // expensive analysis to limit compile-time. + return isRefSet(BatchAA.getModRefInfo(UseInst, DefLoc)); + } + + /// Returns true if \p Ptr is guaranteed to be loop invariant for any possible + /// loop. In particular, this guarantees that it only references a single + /// MemoryLocation during execution of the containing function. + bool IsGuaranteedLoopInvariant(Value *Ptr) { + auto IsGuaranteedLoopInvariantBase = [this](Value *Ptr) { + Ptr = Ptr->stripPointerCasts(); + if (auto *I = dyn_cast(Ptr)) { + if (isa(Ptr)) + return true; + + if (isAllocLikeFn(I, &TLI)) + return true; + + return false; + } + return true; + }; + + Ptr = Ptr->stripPointerCasts(); + if (auto *GEP = dyn_cast(Ptr)) { + return IsGuaranteedLoopInvariantBase(GEP->getPointerOperand()) && + GEP->hasAllConstantIndices(); + } + return IsGuaranteedLoopInvariantBase(Ptr); } - // Find a MemoryDef writing to \p DefLoc and dominating \p Current, with no - // read access between them or on any other path to a function exit block if - // \p DefLoc is not accessible after the function returns. If there is no such - // MemoryDef, return None. The returned value may not (completely) overwrite - // \p DefLoc. Currently we bail out when we encounter an aliasing MemoryUse - // (read). + // Find a MemoryDef writing to \p DefLoc and dominating \p StartAccess, with + // no read access between them or on any other path to a function exit block + // if \p DefLoc is not accessible after the function returns. If there is no + // such MemoryDef, return None. The returned value may not (completely) + // overwrite \p DefLoc. Currently we bail out when we encounter an aliasing + // MemoryUse (read). Optional - getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *Current, - MemoryLocation DefLoc, bool DefVisibleToCallerBeforeRet, - bool DefVisibleToCallerAfterRet, int &ScanLimit) const { - MemoryAccess *DomAccess; + getDomMemoryDef(MemoryDef *KillingDef, MemoryAccess *StartAccess, + const MemoryLocation &DefLoc, const Value *DefUO, + unsigned &ScanLimit, unsigned &WalkerStepLimit, + bool IsMemTerm, unsigned &PartialLimit) { + if (ScanLimit == 0 || WalkerStepLimit == 0) { + LLVM_DEBUG(dbgs() << "\n ... hit scan limit\n"); + return None; + } + + MemoryAccess *Current = StartAccess; + Instruction *KillingI = KillingDef->getMemoryInst(); bool StepAgain; - LLVM_DEBUG(dbgs() << " trying to get dominating access for " << *Current - << "\n"); - // Find the next clobbering Mod access for DefLoc, starting at Current. + LLVM_DEBUG(dbgs() << " trying to get dominating access\n"); + + // Find the next clobbering Mod access for DefLoc, starting at StartAccess. + Optional CurrentLoc; do { StepAgain = false; + LLVM_DEBUG({ + dbgs() << " visiting " << *Current; + if (!MSSA.isLiveOnEntryDef(Current) && isa(Current)) + dbgs() << " (" << *cast(Current)->getMemoryInst() + << ")"; + dbgs() << "\n"; + }); + // Reached TOP. - if (MSSA.isLiveOnEntryDef(Current)) + if (MSSA.isLiveOnEntryDef(Current)) { + LLVM_DEBUG(dbgs() << " ... found LiveOnEntryDef\n"); return None; + } + + // Cost of a step. Accesses in the same block are more likely to be valid + // candidates for elimination, hence consider them cheaper. + unsigned StepCost = KillingDef->getBlock() == Current->getBlock() + ? MemorySSASameBBStepCost + : MemorySSAOtherBBStepCost; + if (WalkerStepLimit <= StepCost) { + LLVM_DEBUG(dbgs() << " ... hit walker step limit\n"); + return None; + } + WalkerStepLimit -= StepCost; + // Return for MemoryPhis. They cannot be eliminated directly and the + // caller is responsible for traversing them. if (isa(Current)) { - DomAccess = Current; - break; + LLVM_DEBUG(dbgs() << " ... found MemoryPhi\n"); + return Current; + } + + // Below, check if CurrentDef is a valid candidate to be eliminated by + // KillingDef. If it is not, check the next candidate. + MemoryDef *CurrentDef = cast(Current); + Instruction *CurrentI = CurrentDef->getMemoryInst(); + + if (canSkipDef(CurrentDef, !isInvisibleToCallerBeforeRet(DefUO))) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + continue; } - MemoryUseOrDef *CurrentUD = cast(Current); - // Look for access that clobber DefLoc. - DomAccess = MSSA.getSkipSelfWalker()->getClobberingMemoryAccess(CurrentUD, - DefLoc); - if (MSSA.isLiveOnEntryDef(DomAccess)) + + // Before we try to remove anything, check for any extra throwing + // instructions that block us from DSEing + if (mayThrowBetween(KillingI, CurrentI, DefUO)) { + LLVM_DEBUG(dbgs() << " ... skip, may throw!\n"); return None; + } - if (isa(DomAccess)) - break; + // Check for anything that looks like it will be a barrier to further + // removal + if (isDSEBarrier(DefUO, CurrentI)) { + LLVM_DEBUG(dbgs() << " ... skip, barrier\n"); + return None; + } + + // If Current is known to be on path that reads DefLoc or is a read + // clobber, bail out, as the path is not profitable. We skip this check + // for intrinsic calls, because the code knows how to handle memcpy + // intrinsics. + if (!isa(CurrentI) && isReadClobber(DefLoc, CurrentI)) + return None; + + // Quick check if there are direct uses that are read-clobbers. + if (any_of(Current->uses(), [this, &DefLoc, StartAccess](Use &U) { + if (auto *UseOrDef = dyn_cast(U.getUser())) + return !MSSA.dominates(StartAccess, UseOrDef) && + isReadClobber(DefLoc, UseOrDef->getMemoryInst()); + return false; + })) { + LLVM_DEBUG(dbgs() << " ... found a read clobber\n"); + return None; + } + + // If Current cannot be analyzed or is not removable, check the next + // candidate. + if (!hasAnalyzableMemoryWrite(CurrentI, TLI) || !isRemovable(CurrentI)) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + continue; + } + + // If Current does not have an analyzable write location, skip it + CurrentLoc = getLocForWriteEx(CurrentI); + if (!CurrentLoc) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + continue; + } - // Check if we can skip DomDef for DSE. - MemoryDef *DomDef = dyn_cast(DomAccess); - if (DomDef && canSkipDef(DomDef, DefVisibleToCallerBeforeRet)) { + // AliasAnalysis does not account for loops. Limit elimination to + // candidates for which we can guarantee they always store to the same + // memory location and not multiple locations in a loop. + if (Current->getBlock() != KillingDef->getBlock() && + !IsGuaranteedLoopInvariant(const_cast(CurrentLoc->Ptr))) { StepAgain = true; - Current = DomDef->getDefiningAccess(); + Current = CurrentDef->getDefiningAccess(); + WalkerStepLimit -= 1; + continue; } + if (IsMemTerm) { + // If the killing def is a memory terminator (e.g. lifetime.end), check + // the next candidate if the current Current does not write the same + // underlying object as the terminator. + if (!isMemTerminator(*CurrentLoc, CurrentI, KillingI)) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + } + continue; + } else { + int64_t InstWriteOffset, DepWriteOffset; + auto OR = isOverwrite(KillingI, CurrentI, DefLoc, *CurrentLoc, DL, TLI, + DepWriteOffset, InstWriteOffset, BatchAA, &F); + // If Current does not write to the same object as KillingDef, check + // the next candidate. + if (OR == OW_Unknown) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + } else if (OR == OW_MaybePartial) { + // If KillingDef only partially overwrites Current, check the next + // candidate if the partial step limit is exceeded. This aggressively + // limits the number of candidates for partial store elimination, + // which are less likely to be removable in the end. + if (PartialLimit <= 1) { + StepAgain = true; + Current = CurrentDef->getDefiningAccess(); + WalkerStepLimit -= 1; + continue; + } + PartialLimit -= 1; + } + } } while (StepAgain); // Accesses to objects accessible after the function returns can only be // eliminated if the access is killed along all paths to the exit. Collect // the blocks with killing (=completely overwriting MemoryDefs) and check if - // they cover all paths from DomAccess to any function exit. - SmallPtrSet KillingBlocks = {KillingDef->getBlock()}; - LLVM_DEBUG({ - dbgs() << " Checking for reads of " << *DomAccess; - if (isa(DomAccess)) - dbgs() << " (" << *cast(DomAccess)->getMemoryInst() << ")\n"; - else - dbgs() << ")\n"; - }); + // they cover all paths from EarlierAccess to any function exit. + SmallPtrSet KillingDefs; + KillingDefs.insert(KillingDef->getMemoryInst()); + MemoryAccess *EarlierAccess = Current; + Instruction *EarlierMemInst = + cast(EarlierAccess)->getMemoryInst(); + LLVM_DEBUG(dbgs() << " Checking for reads of " << *EarlierAccess << " (" + << *EarlierMemInst << ")\n"); SmallSetVector WorkList; auto PushMemUses = [&WorkList](MemoryAccess *Acc) { for (Use &U : Acc->uses()) WorkList.insert(cast(U.getUser())); }; - PushMemUses(DomAccess); - - // Check if DomDef may be read. + PushMemUses(EarlierAccess); + + // Optimistically collect all accesses for reads. If we do not find any + // read clobbers, add them to the cache. + SmallPtrSet KnownNoReads; + if (!EarlierMemInst->mayReadFromMemory()) + KnownNoReads.insert(EarlierAccess); + // Check if EarlierDef may be read. for (unsigned I = 0; I < WorkList.size(); I++) { MemoryAccess *UseAccess = WorkList[I]; LLVM_DEBUG(dbgs() << " " << *UseAccess); - if (--ScanLimit == 0) { + // Bail out if the number of accesses to check exceeds the scan limit. + if (ScanLimit < (WorkList.size() - I)) { LLVM_DEBUG(dbgs() << "\n ... hit scan limit\n"); return None; } + --ScanLimit; + NumDomMemDefChecks++; + KnownNoReads.insert(UseAccess); if (isa(UseAccess)) { + if (any_of(KillingDefs, [this, UseAccess](Instruction *KI) { + return DT.properlyDominates(KI->getParent(), + UseAccess->getBlock()); + })) { + LLVM_DEBUG(dbgs() << " ... skipping, dominated by killing block\n"); + continue; + } LLVM_DEBUG(dbgs() << "\n ... adding PHI uses\n"); PushMemUses(UseAccess); continue; @@ -1813,29 +2134,45 @@ struct DSEState { Instruction *UseInst = cast(UseAccess)->getMemoryInst(); LLVM_DEBUG(dbgs() << " (" << *UseInst << ")\n"); - if (isNoopIntrinsic(cast(UseAccess))) { - LLVM_DEBUG(dbgs() << " ... adding uses of intrinsic\n"); - PushMemUses(UseAccess); + if (any_of(KillingDefs, [this, UseInst](Instruction *KI) { + return DT.dominates(KI, UseInst); + })) { + LLVM_DEBUG(dbgs() << " ... skipping, dominated by killing def\n"); continue; } // A memory terminator kills all preceeding MemoryDefs and all succeeding // MemoryAccesses. We do not have to check it's users. - if (isMemTerminator(DefLoc, UseInst)) + if (isMemTerminator(*CurrentLoc, EarlierMemInst, UseInst)) { + LLVM_DEBUG( + dbgs() + << " ... skipping, memterminator invalidates following accesses\n"); continue; + } + + if (isNoopIntrinsic(cast(UseAccess)->getMemoryInst())) { + LLVM_DEBUG(dbgs() << " ... adding uses of intrinsic\n"); + PushMemUses(UseAccess); + continue; + } + + if (UseInst->mayThrow() && !isInvisibleToCallerBeforeRet(DefUO)) { + LLVM_DEBUG(dbgs() << " ... found throwing instruction\n"); + return None; + } // Uses which may read the original MemoryDef mean we cannot eliminate the // original MD. Stop walk. - if (isReadClobber(DefLoc, UseInst)) { + if (isReadClobber(*CurrentLoc, UseInst)) { LLVM_DEBUG(dbgs() << " ... found read clobber\n"); return None; } - // For the KillingDef and DomAccess we only have to check if it reads the - // memory location. + // For the KillingDef and EarlierAccess we only have to check if it reads + // the memory location. // TODO: It would probably be better to check for self-reads before // calling the function. - if (KillingDef == UseAccess || DomAccess == UseAccess) { + if (KillingDef == UseAccess || EarlierAccess == UseAccess) { LLVM_DEBUG(dbgs() << " ... skipping killing def/dom access\n"); continue; } @@ -1844,22 +2181,23 @@ struct DSEState { // the original location. Otherwise we have to check uses of *all* // MemoryDefs we discover, including non-aliasing ones. Otherwise we might // miss cases like the following - // 1 = Def(LoE) ; <----- DomDef stores [0,1] + // 1 = Def(LoE) ; <----- EarlierDef stores [0,1] // 2 = Def(1) ; (2, 1) = NoAlias, stores [2,3] // Use(2) ; MayAlias 2 *and* 1, loads [0, 3]. // (The Use points to the *first* Def it may alias) // 3 = Def(1) ; <---- Current (3, 2) = NoAlias, (3,1) = MayAlias, // stores [0,1] if (MemoryDef *UseDef = dyn_cast(UseAccess)) { - if (isCompleteOverwrite(DefLoc, UseInst)) { - if (DefVisibleToCallerAfterRet && UseAccess != DomAccess) { + if (isCompleteOverwrite(*CurrentLoc, EarlierMemInst, UseInst)) { + if (!isInvisibleToCallerAfterRet(DefUO) && + UseAccess != EarlierAccess) { BasicBlock *MaybeKillingBlock = UseInst->getParent(); if (PostOrderNumbers.find(MaybeKillingBlock)->second < - PostOrderNumbers.find(DomAccess->getBlock())->second) { + PostOrderNumbers.find(EarlierAccess->getBlock())->second) { - LLVM_DEBUG(dbgs() << " ... found killing block " - << MaybeKillingBlock->getName() << "\n"); - KillingBlocks.insert(MaybeKillingBlock); + LLVM_DEBUG(dbgs() + << " ... found killing def " << *UseInst << "\n"); + KillingDefs.insert(UseInst); } } } else @@ -1868,11 +2206,15 @@ struct DSEState { } // For accesses to locations visible after the function returns, make sure - // that the location is killed (=overwritten) along all paths from DomAccess - // to the exit. - if (DefVisibleToCallerAfterRet) { + // that the location is killed (=overwritten) along all paths from + // EarlierAccess to the exit. + if (!isInvisibleToCallerAfterRet(DefUO)) { + SmallPtrSet KillingBlocks; + for (Instruction *KD : KillingDefs) + KillingBlocks.insert(KD->getParent()); assert(!KillingBlocks.empty() && "Expected at least a single killing block"); + // Find the common post-dominator of all killing blocks. BasicBlock *CommonPred = *KillingBlocks.begin(); for (auto I = std::next(KillingBlocks.begin()), E = KillingBlocks.end(); @@ -1883,23 +2225,19 @@ struct DSEState { } // If CommonPred is in the set of killing blocks, just check if it - // post-dominates DomAccess. + // post-dominates EarlierAccess. if (KillingBlocks.count(CommonPred)) { - if (PDT.dominates(CommonPred, DomAccess->getBlock())) - return {DomAccess}; + if (PDT.dominates(CommonPred, EarlierAccess->getBlock())) + return {EarlierAccess}; return None; } - // If the common post-dominator does not post-dominate DomAccess, there - // is a path from DomAccess to an exit not going through a killing block. - if (PDT.dominates(CommonPred, DomAccess->getBlock())) { + // If the common post-dominator does not post-dominate EarlierAccess, + // there is a path from EarlierAccess to an exit not going through a + // killing block. + if (PDT.dominates(CommonPred, EarlierAccess->getBlock())) { SetVector WorkList; - // DomAccess's post-order number provides an upper bound of the blocks - // on a path starting at DomAccess. - unsigned UpperBound = - PostOrderNumbers.find(DomAccess->getBlock())->second; - // If CommonPred is null, there are multiple exits from the function. // They all have to be added to the worklist. if (CommonPred) @@ -1910,24 +2248,20 @@ struct DSEState { NumCFGTries++; // Check if all paths starting from an exit node go through one of the - // killing blocks before reaching DomAccess. + // killing blocks before reaching EarlierAccess. for (unsigned I = 0; I < WorkList.size(); I++) { NumCFGChecks++; BasicBlock *Current = WorkList[I]; if (KillingBlocks.count(Current)) continue; - if (Current == DomAccess->getBlock()) + if (Current == EarlierAccess->getBlock()) return None; - // DomAccess is reachable from the entry, so we don't have to explore - // unreachable blocks further. + // EarlierAccess is reachable from the entry, so we don't have to + // explore unreachable blocks further. if (!DT.isReachableFromEntry(Current)) continue; - unsigned CPO = PostOrderNumbers.find(Current)->second; - // Current block is not on a path starting at DomAccess. - if (CPO > UpperBound) - continue; for (BasicBlock *Pred : predecessors(Current)) WorkList.insert(Pred); @@ -1935,13 +2269,14 @@ struct DSEState { return None; } NumCFGSuccess++; - return {DomAccess}; + return {EarlierAccess}; } return None; } - // No aliasing MemoryUses of DomAccess found, DomAccess is potentially dead. - return {DomAccess}; + // No aliasing MemoryUses of EarlierAccess found, EarlierAccess is + // potentially dead. + return {EarlierAccess}; } // Delete dead memory defs @@ -1986,11 +2321,11 @@ struct DSEState { // checks extra maythrows (those that aren't MemoryDef's). MemoryDef that may // throw are handled during the walk from one def to the next. bool mayThrowBetween(Instruction *SI, Instruction *NI, - const Value *SILocUnd) const { + const Value *SILocUnd) { // First see if we can ignore it by using the fact that SI is an // alloca/alloca like object that is not visible to the caller during // execution of the function. - if (SILocUnd && InvisibleToCallerBeforeRet.count(SILocUnd)) + if (SILocUnd && isInvisibleToCallerBeforeRet(SILocUnd)) return false; if (SI->getParent() == NI->getParent()) @@ -2003,10 +2338,10 @@ struct DSEState { // * A memory instruction that may throw and \p SI accesses a non-stack // object. // * Atomic stores stronger that monotonic. - bool isDSEBarrier(const Value *SILocUnd, Instruction *NI) const { + bool isDSEBarrier(const Value *SILocUnd, Instruction *NI) { // If NI may throw it acts as a barrier, unless we are to an alloca/alloca // like object that does not escape. - if (NI->mayThrow() && !InvisibleToCallerBeforeRet.count(SILocUnd)) + if (NI->mayThrow() && !isInvisibleToCallerBeforeRet(SILocUnd)) return true; // If NI is an atomic load/store stronger than monotonic, do not try to @@ -2016,6 +2351,11 @@ struct DSEState { return isStrongerThanMonotonic(LI->getOrdering()); if (auto *SI = dyn_cast(NI)) return isStrongerThanMonotonic(SI->getOrdering()); + if (auto *ARMW = dyn_cast(NI)) + return isStrongerThanMonotonic(ARMW->getOrdering()); + if (auto *CmpXchg = dyn_cast(NI)) + return isStrongerThanMonotonic(CmpXchg->getSuccessOrdering()) || + isStrongerThanMonotonic(CmpXchg->getFailureOrdering()); llvm_unreachable("other instructions should be skipped in MemorySSA"); } return false; @@ -2024,40 +2364,37 @@ struct DSEState { /// Eliminate writes to objects that are not visible in the caller and are not /// accessed before returning from the function. bool eliminateDeadWritesAtEndOfFunction() { - const DataLayout &DL = F.getParent()->getDataLayout(); bool MadeChange = false; LLVM_DEBUG( dbgs() << "Trying to eliminate MemoryDefs at the end of the function\n"); for (int I = MemDefs.size() - 1; I >= 0; I--) { MemoryDef *Def = MemDefs[I]; - if (SkipStores.find(Def) != SkipStores.end() || - !isRemovable(Def->getMemoryInst())) + if (SkipStores.contains(Def) || !isRemovable(Def->getMemoryInst())) + continue; + + Instruction *DefI = Def->getMemoryInst(); + SmallVector Pointers; + auto DefLoc = getLocForWriteEx(DefI); + if (!DefLoc) + continue; + + // NOTE: Currently eliminating writes at the end of a function is limited + // to MemoryDefs with a single underlying object, to save compile-time. In + // practice it appears the case with multiple underlying objects is very + // uncommon. If it turns out to be important, we can use + // getUnderlyingObjects here instead. + const Value *UO = getUnderlyingObject(DefLoc->Ptr); + if (!UO || !isInvisibleToCallerAfterRet(UO)) continue; - // TODO: Consider doing the underlying object check first, if it is - // beneficial compile-time wise. if (isWriteAtEndOfFunction(Def)) { - Instruction *DefI = Def->getMemoryInst(); // See through pointer-to-pointer bitcasts - SmallVector Pointers; - GetUnderlyingObjects(getLocForWriteEx(DefI)->Ptr, Pointers, DL); - LLVM_DEBUG(dbgs() << " ... MemoryDef is not accessed until the end " "of the function\n"); - bool CanKill = true; - for (const Value *Pointer : Pointers) { - if (!InvisibleToCallerAfterRet.count(Pointer)) { - CanKill = false; - break; - } - } - - if (CanKill) { - deleteDeadInstruction(DefI); - ++NumFastStores; - MadeChange = true; - } + deleteDeadInstruction(DefI); + ++NumFastStores; + MadeChange = true; } } return MadeChange; @@ -2065,17 +2402,53 @@ struct DSEState { /// \returns true if \p Def is a no-op store, either because it /// directly stores back a loaded value or stores zero to a calloced object. - bool storeIsNoop(MemoryDef *Def, MemoryLocation DefLoc, const Value *DefUO) { + bool storeIsNoop(MemoryDef *Def, const MemoryLocation &DefLoc, + const Value *DefUO) { StoreInst *Store = dyn_cast(Def->getMemoryInst()); if (!Store) return false; if (auto *LoadI = dyn_cast(Store->getOperand(0))) { if (LoadI->getPointerOperand() == Store->getOperand(1)) { + // Get the defining access for the load. auto *LoadAccess = MSSA.getMemoryAccess(LoadI)->getDefiningAccess(); - // If both accesses share the same defining access, no instructions - // between them can modify the memory location. - return LoadAccess == Def->getDefiningAccess(); + // Fast path: the defining accesses are the same. + if (LoadAccess == Def->getDefiningAccess()) + return true; + + // Look through phi accesses. Recursively scan all phi accesses by + // adding them to a worklist. Bail when we run into a memory def that + // does not match LoadAccess. + SetVector ToCheck; + MemoryAccess *Current = + MSSA.getWalker()->getClobberingMemoryAccess(Def); + // We don't want to bail when we run into the store memory def. But, + // the phi access may point to it. So, pretend like we've already + // checked it. + ToCheck.insert(Def); + ToCheck.insert(Current); + // Start at current (1) to simulate already having checked Def. + for (unsigned I = 1; I < ToCheck.size(); ++I) { + Current = ToCheck[I]; + if (auto PhiAccess = dyn_cast(Current)) { + // Check all the operands. + for (auto &Use : PhiAccess->incoming_values()) + ToCheck.insert(cast(&Use)); + continue; + } + + // If we found a memory def, bail. This happens when we have an + // unrelated write in between an otherwise noop store. + assert(isa(Current) && + "Only MemoryDefs should reach here."); + // TODO: Skip no alias MemoryDefs that have no aliasing reads. + // We are searching for the definition of the store's destination. + // So, if that is the same definition as the load, then this is a + // noop. Otherwise, fail. + if (LoadAccess != Current) + return false; + } + return true; } } @@ -2099,7 +2472,6 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, MemorySSA &MSSA, DominatorTree &DT, PostDominatorTree &PDT, const TargetLibraryInfo &TLI) { - const DataLayout &DL = F.getParent()->getDataLayout(); bool MadeChange = false; DSEState State = DSEState::get(F, AA, MSSA, DT, PDT, TLI); @@ -2110,7 +2482,7 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, continue; Instruction *SI = KillingDef->getMemoryInst(); - auto MaybeSILoc = State.getLocForWriteEx(SI); + Optional MaybeSILoc; if (State.isMemTerminatorInst(SI)) MaybeSILoc = State.getLocForTerminator(SI).map( [](const std::pair &P) { return P.first; }); @@ -2124,38 +2496,23 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, } MemoryLocation SILoc = *MaybeSILoc; assert(SILoc.Ptr && "SILoc should not be null"); - const Value *SILocUnd = GetUnderlyingObject(SILoc.Ptr, DL); - - // Check if the store is a no-op. - if (isRemovable(SI) && State.storeIsNoop(KillingDef, SILoc, SILocUnd)) { - LLVM_DEBUG(dbgs() << "DSE: Remove No-Op Store:\n DEAD: " << *SI << '\n'); - State.deleteDeadInstruction(SI); - NumNoopStores++; - MadeChange = true; - continue; - } - - Instruction *DefObj = - const_cast(dyn_cast(SILocUnd)); - bool DefVisibleToCallerBeforeRet = - !State.InvisibleToCallerBeforeRet.count(SILocUnd); - bool DefVisibleToCallerAfterRet = - !State.InvisibleToCallerAfterRet.count(SILocUnd); - if (DefObj && isAllocLikeFn(DefObj, &TLI)) { - if (DefVisibleToCallerBeforeRet) - DefVisibleToCallerBeforeRet = - PointerMayBeCapturedBefore(DefObj, false, true, SI, &DT); - } + const Value *SILocUnd = getUnderlyingObject(SILoc.Ptr); MemoryAccess *Current = KillingDef; LLVM_DEBUG(dbgs() << "Trying to eliminate MemoryDefs killed by " << *KillingDef << " (" << *SI << ")\n"); - int ScanLimit = MemorySSAScanLimit; + unsigned ScanLimit = MemorySSAScanLimit; + unsigned WalkerStepLimit = MemorySSAUpwardsStepLimit; + unsigned PartialLimit = MemorySSAPartialStoreLimit; // Worklist of MemoryAccesses that may be killed by KillingDef. SetVector ToCheck; - ToCheck.insert(KillingDef->getDefiningAccess()); + if (SILocUnd) + ToCheck.insert(KillingDef->getDefiningAccess()); + + bool Shortend = false; + bool IsMemTerm = State.isMemTerminatorInst(SI); // Check if MemoryAccesses in the worklist are killed by KillingDef. for (unsigned I = 0; I < ToCheck.size(); I++) { Current = ToCheck[I]; @@ -2163,22 +2520,22 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, continue; Optional Next = State.getDomMemoryDef( - KillingDef, Current, SILoc, DefVisibleToCallerBeforeRet, - DefVisibleToCallerAfterRet, ScanLimit); + KillingDef, Current, SILoc, SILocUnd, ScanLimit, WalkerStepLimit, + IsMemTerm, PartialLimit); if (!Next) { LLVM_DEBUG(dbgs() << " finished walk\n"); continue; } - MemoryAccess *DomAccess = *Next; - LLVM_DEBUG(dbgs() << " Checking if we can kill " << *DomAccess); - if (isa(DomAccess)) { + MemoryAccess *EarlierAccess = *Next; + LLVM_DEBUG(dbgs() << " Checking if we can kill " << *EarlierAccess); + if (isa(EarlierAccess)) { LLVM_DEBUG(dbgs() << "\n ... adding incoming values to worklist\n"); - for (Value *V : cast(DomAccess)->incoming_values()) { + for (Value *V : cast(EarlierAccess)->incoming_values()) { MemoryAccess *IncomingAccess = cast(V); BasicBlock *IncomingBlock = IncomingAccess->getBlock(); - BasicBlock *PhiBlock = DomAccess->getBlock(); + BasicBlock *PhiBlock = EarlierAccess->getBlock(); // We only consider incoming MemoryAccesses that come before the // MemoryPhi. Otherwise we could discover candidates that do not @@ -2189,44 +2546,20 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, } continue; } - MemoryDef *NextDef = dyn_cast(DomAccess); + auto *NextDef = cast(EarlierAccess); Instruction *NI = NextDef->getMemoryInst(); LLVM_DEBUG(dbgs() << " (" << *NI << ")\n"); - - // Before we try to remove anything, check for any extra throwing - // instructions that block us from DSEing - if (State.mayThrowBetween(SI, NI, SILocUnd)) { - LLVM_DEBUG(dbgs() << " ... skip, may throw!\n"); - break; - } - - // Check for anything that looks like it will be a barrier to further - // removal - if (State.isDSEBarrier(SILocUnd, NI)) { - LLVM_DEBUG(dbgs() << " ... skip, barrier\n"); - continue; - } - ToCheck.insert(NextDef->getDefiningAccess()); - - if (!hasAnalyzableMemoryWrite(NI, TLI)) { - LLVM_DEBUG(dbgs() << " ... skip, cannot analyze def\n"); - continue; - } - - if (!isRemovable(NI)) { - LLVM_DEBUG(dbgs() << " ... skip, cannot remove def\n"); - continue; - } + NumGetDomMemoryDefPassed++; if (!DebugCounter::shouldExecute(MemorySSACounter)) continue; MemoryLocation NILoc = *State.getLocForWriteEx(NI); - if (State.isMemTerminatorInst(SI)) { - const Value *NIUnd = GetUnderlyingObject(NILoc.Ptr, DL); - if (!SILocUnd || SILocUnd != NIUnd) + if (IsMemTerm) { + const Value *NIUnd = getUnderlyingObject(NILoc.Ptr); + if (SILocUnd != NIUnd) continue; LLVM_DEBUG(dbgs() << "DSE: Remove Dead Store:\n DEAD: " << *NI << "\n KILLER: " << *SI << '\n'); @@ -2236,32 +2569,43 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, } else { // Check if NI overwrites SI. int64_t InstWriteOffset, DepWriteOffset; - auto Iter = State.IOLs.insert( - std::make_pair( - NI->getParent(), InstOverlapIntervalsTy())); - auto &IOL = Iter.first->second; - OverwriteResult OR = isOverwrite(SILoc, NILoc, DL, TLI, DepWriteOffset, - InstWriteOffset, NI, IOL, AA, &F); + OverwriteResult OR = + isOverwrite(SI, NI, SILoc, NILoc, State.DL, TLI, DepWriteOffset, + InstWriteOffset, State.BatchAA, &F); + if (OR == OW_MaybePartial) { + auto Iter = State.IOLs.insert( + std::make_pair( + NI->getParent(), InstOverlapIntervalsTy())); + auto &IOL = Iter.first->second; + OR = isPartialOverwrite(SILoc, NILoc, DepWriteOffset, InstWriteOffset, + NI, IOL); + } if (EnablePartialStoreMerging && OR == OW_PartialEarlierWithFullLater) { auto *Earlier = dyn_cast(NI); auto *Later = dyn_cast(SI); - if (Constant *Merged = tryToMergePartialOverlappingStores( - Earlier, Later, InstWriteOffset, DepWriteOffset, DL, &AA, - &DT)) { - - // Update stored value of earlier store to merged constant. - Earlier->setOperand(0, Merged); - ++NumModifiedStores; - MadeChange = true; - - // Remove later store and remove any outstanding overlap intervals - // for the updated store. - State.deleteDeadInstruction(Later); - auto I = State.IOLs.find(Earlier->getParent()); - if (I != State.IOLs.end()) - I->second.erase(Earlier); - break; + // We are re-using tryToMergePartialOverlappingStores, which requires + // Earlier to domiante Later. + // TODO: implement tryToMergeParialOverlappingStores using MemorySSA. + if (Earlier && Later && DT.dominates(Earlier, Later)) { + if (Constant *Merged = tryToMergePartialOverlappingStores( + Earlier, Later, InstWriteOffset, DepWriteOffset, State.DL, + State.BatchAA, &DT)) { + + // Update stored value of earlier store to merged constant. + Earlier->setOperand(0, Merged); + ++NumModifiedStores; + MadeChange = true; + + Shortend = true; + // Remove later store and remove any outstanding overlap intervals + // for the updated store. + State.deleteDeadInstruction(Later); + auto I = State.IOLs.find(Earlier->getParent()); + if (I != State.IOLs.end()) + I->second.erase(Earlier); + break; + } } } @@ -2274,11 +2618,21 @@ bool eliminateDeadStoresMemorySSA(Function &F, AliasAnalysis &AA, } } } + + // Check if the store is a no-op. + if (!Shortend && isRemovable(SI) && + State.storeIsNoop(KillingDef, SILoc, SILocUnd)) { + LLVM_DEBUG(dbgs() << "DSE: Remove No-Op Store:\n DEAD: " << *SI << '\n'); + State.deleteDeadInstruction(SI); + NumRedundantStores++; + MadeChange = true; + continue; + } } if (EnablePartialOverwriteTracking) for (auto &KV : State.IOLs) - MadeChange |= removePartiallyOverlappedStores(&AA, DL, KV.second); + MadeChange |= removePartiallyOverlappedStores(State.DL, KV.second, TLI); MadeChange |= State.eliminateDeadWritesAtEndOfFunction(); return MadeChange; diff --git a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp index d44a5979a8b2..3c6c444d6649 100644 --- a/llvm/lib/Transforms/Scalar/DivRemPairs.cpp +++ b/llvm/lib/Transforms/Scalar/DivRemPairs.cpp @@ -151,8 +151,8 @@ static DivRemWorklistTy getWorklist(Function &F) { // rare than division. for (auto &RemPair : RemMap) { // Find the matching division instruction from the division map. - Instruction *DivInst = DivMap[RemPair.first]; - if (!DivInst) + auto It = DivMap.find(RemPair.first); + if (It == DivMap.end()) continue; // We have a matching pair of div/rem instructions. @@ -160,7 +160,7 @@ static DivRemWorklistTy getWorklist(Function &F) { Instruction *RemInst = RemPair.second; // Place it in the worklist. - Worklist.emplace_back(DivInst, RemInst); + Worklist.emplace_back(It->second, RemInst); } return Worklist; @@ -315,14 +315,14 @@ static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, // %rem = sub %x, %mul // %rem = undef - undef = undef // If X is not frozen, %rem becomes undef after transformation. // TODO: We need a undef-specific checking function in ValueTracking - if (!isGuaranteedNotToBeUndefOrPoison(X, DivInst, &DT)) { + if (!isGuaranteedNotToBeUndefOrPoison(X, nullptr, DivInst, &DT)) { auto *FrX = new FreezeInst(X, X->getName() + ".frozen", DivInst); DivInst->setOperand(0, FrX); Sub->setOperand(0, FrX); } // Same for Y. If X = 1 and Y = (undef | 1), %rem in src is either 1 or 0, // but %rem in tgt can be one of many integer values. - if (!isGuaranteedNotToBeUndefOrPoison(Y, DivInst, &DT)) { + if (!isGuaranteedNotToBeUndefOrPoison(Y, nullptr, DivInst, &DT)) { auto *FrY = new FreezeInst(Y, Y->getName() + ".frozen", DivInst); DivInst->setOperand(1, FrY); Mul->setOperand(1, FrY); diff --git a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp index ddfc8555b0a0..180a82917fa9 100644 --- a/llvm/lib/Transforms/Scalar/EarlyCSE.cpp +++ b/llvm/lib/Transforms/Scalar/EarlyCSE.cpp @@ -154,33 +154,13 @@ static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A, std::swap(A, B); } - // Match canonical forms of abs/nabs/min/max. We are not using ValueTracking's + // Match canonical forms of min/max. We are not using ValueTracking's // more powerful matchSelectPattern() because it may rely on instruction flags // such as "nsw". That would be incompatible with the current hashing // mechanism that may remove flags to increase the likelihood of CSE. - // These are the canonical forms of abs(X) and nabs(X) created by instcombine: - // %N = sub i32 0, %X - // %C = icmp slt i32 %X, 0 - // %ABS = select i1 %C, i32 %N, i32 %X - // - // %N = sub i32 0, %X - // %C = icmp slt i32 %X, 0 - // %NABS = select i1 %C, i32 %X, i32 %N Flavor = SPF_UNKNOWN; CmpInst::Predicate Pred; - if (match(Cond, m_ICmp(Pred, m_Specific(B), m_ZeroInt())) && - Pred == ICmpInst::ICMP_SLT && match(A, m_Neg(m_Specific(B)))) { - // ABS: B < 0 ? -B : B - Flavor = SPF_ABS; - return true; - } - if (match(Cond, m_ICmp(Pred, m_Specific(A), m_ZeroInt())) && - Pred == ICmpInst::ICMP_SLT && match(B, m_Neg(m_Specific(A)))) { - // NABS: A < 0 ? A : -A - Flavor = SPF_NABS; - return true; - } if (!match(Cond, m_ICmp(Pred, m_Specific(A), m_Specific(B)))) { // Check for commuted variants of min/max by swapping predicate. @@ -196,6 +176,11 @@ static bool matchSelectWithOptionalNotCond(Value *V, Value *&Cond, Value *&A, case CmpInst::ICMP_ULT: Flavor = SPF_UMIN; break; case CmpInst::ICMP_SGT: Flavor = SPF_SMAX; break; case CmpInst::ICMP_SLT: Flavor = SPF_SMIN; break; + // Non-strict inequalities. + case CmpInst::ICMP_ULE: Flavor = SPF_UMIN; break; + case CmpInst::ICMP_UGE: Flavor = SPF_UMAX; break; + case CmpInst::ICMP_SLE: Flavor = SPF_SMIN; break; + case CmpInst::ICMP_SGE: Flavor = SPF_SMAX; break; default: break; } @@ -234,7 +219,7 @@ static unsigned getHashValueImpl(SimpleValue Val) { SelectPatternFlavor SPF; Value *Cond, *A, *B; if (matchSelectWithOptionalNotCond(Inst, Cond, A, B, SPF)) { - // Hash min/max/abs (cmp + select) to allow for commuted operands. + // Hash min/max (cmp + select) to allow for commuted operands. // Min/max may also have non-canonical compare predicate (eg, the compare for // smin may use 'sgt' rather than 'slt'), and non-canonical operands in the // compare. @@ -245,10 +230,6 @@ static unsigned getHashValueImpl(SimpleValue Val) { std::swap(A, B); return hash_combine(Inst->getOpcode(), SPF, A, B); } - if (SPF == SPF_ABS || SPF == SPF_NABS) { - // ABS/NABS always puts the input in A and its negation in B. - return hash_combine(Inst->getOpcode(), SPF, A, B); - } // Hash general selects to allow matching commuted true/false operands. @@ -288,6 +269,17 @@ static unsigned getHashValueImpl(SimpleValue Val) { isa(Inst)) && "Invalid/unknown instruction"); + // Handle intrinsics with commutative operands. + // TODO: Extend this to handle intrinsics with >2 operands where the 1st + // 2 operands are commutative. + auto *II = dyn_cast(Inst); + if (II && II->isCommutative() && II->getNumArgOperands() == 2) { + Value *LHS = II->getArgOperand(0), *RHS = II->getArgOperand(1); + if (LHS > RHS) + std::swap(LHS, RHS); + return hash_combine(II->getOpcode(), LHS, RHS); + } + // Mix in the opcode. return hash_combine( Inst->getOpcode(), @@ -340,7 +332,16 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) { LHSCmp->getSwappedPredicate() == RHSCmp->getPredicate(); } - // Min/max/abs can occur with commuted operands, non-canonical predicates, + // TODO: Extend this for >2 args by matching the trailing N-2 args. + auto *LII = dyn_cast(LHSI); + auto *RII = dyn_cast(RHSI); + if (LII && RII && LII->getIntrinsicID() == RII->getIntrinsicID() && + LII->isCommutative() && LII->getNumArgOperands() == 2) { + return LII->getArgOperand(0) == RII->getArgOperand(1) && + LII->getArgOperand(1) == RII->getArgOperand(0); + } + + // Min/max can occur with commuted operands, non-canonical predicates, // and/or non-canonical operands. // Selects can be non-trivially equivalent via inverted conditions and swaps. SelectPatternFlavor LSPF, RSPF; @@ -354,11 +355,6 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) { return ((LHSA == RHSA && LHSB == RHSB) || (LHSA == RHSB && LHSB == RHSA)); - if (LSPF == SPF_ABS || LSPF == SPF_NABS) { - // Abs results are placed in a defined order by matchSelectPattern. - return LHSA == RHSA && LHSB == RHSB; - } - // select Cond, A, B <--> select not(Cond), B, A if (CondL == CondR && LHSA == RHSA && LHSB == RHSB) return true; @@ -376,7 +372,7 @@ static bool isEqualImpl(SimpleValue LHS, SimpleValue RHS) { // This intentionally does NOT handle patterns with a double-negation in // the sense of not + not, because doing so could result in values // comparing - // as equal that hash differently in the min/max/abs cases like: + // as equal that hash differently in the min/max cases like: // select (cmp slt, X, Y), X, Y <--> select (not (not (cmp slt, X, Y))), X, Y // ^ hashes as min ^ would not hash as min // In the context of the EarlyCSE pass, however, such cases never reach @@ -631,11 +627,11 @@ private: StackNode &operator=(const StackNode &) = delete; // Accessors. - unsigned currentGeneration() { return CurrentGeneration; } - unsigned childGeneration() { return ChildGeneration; } + unsigned currentGeneration() const { return CurrentGeneration; } + unsigned childGeneration() const { return ChildGeneration; } void childGeneration(unsigned generation) { ChildGeneration = generation; } DomTreeNode *node() { return Node; } - DomTreeNode::const_iterator childIter() { return ChildIter; } + DomTreeNode::const_iterator childIter() const { return ChildIter; } DomTreeNode *nextChild() { DomTreeNode *child = *ChildIter; @@ -643,8 +639,8 @@ private: return child; } - DomTreeNode::const_iterator end() { return EndIter; } - bool isProcessed() { return Processed; } + DomTreeNode::const_iterator end() const { return EndIter; } + bool isProcessed() const { return Processed; } void process() { Processed = true; } private: @@ -663,29 +659,60 @@ private: public: ParseMemoryInst(Instruction *Inst, const TargetTransformInfo &TTI) : Inst(Inst) { - if (IntrinsicInst *II = dyn_cast(Inst)) + if (IntrinsicInst *II = dyn_cast(Inst)) { + IntrID = II->getIntrinsicID(); if (TTI.getTgtMemIntrinsic(II, Info)) - IsTargetMemInst = true; + return; + if (isHandledNonTargetIntrinsic(IntrID)) { + switch (IntrID) { + case Intrinsic::masked_load: + Info.PtrVal = Inst->getOperand(0); + Info.MatchingId = Intrinsic::masked_load; + Info.ReadMem = true; + Info.WriteMem = false; + Info.IsVolatile = false; + break; + case Intrinsic::masked_store: + Info.PtrVal = Inst->getOperand(1); + // Use the ID of masked load as the "matching id". This will + // prevent matching non-masked loads/stores with masked ones + // (which could be done), but at the moment, the code here + // does not support matching intrinsics with non-intrinsics, + // so keep the MatchingIds specific to masked instructions + // for now (TODO). + Info.MatchingId = Intrinsic::masked_load; + Info.ReadMem = false; + Info.WriteMem = true; + Info.IsVolatile = false; + break; + } + } + } } + Instruction *get() { return Inst; } + const Instruction *get() const { return Inst; } + bool isLoad() const { - if (IsTargetMemInst) return Info.ReadMem; + if (IntrID != 0) + return Info.ReadMem; return isa(Inst); } bool isStore() const { - if (IsTargetMemInst) return Info.WriteMem; + if (IntrID != 0) + return Info.WriteMem; return isa(Inst); } bool isAtomic() const { - if (IsTargetMemInst) + if (IntrID != 0) return Info.Ordering != AtomicOrdering::NotAtomic; return Inst->isAtomic(); } bool isUnordered() const { - if (IsTargetMemInst) + if (IntrID != 0) return Info.isUnordered(); if (LoadInst *LI = dyn_cast(Inst)) { @@ -698,7 +725,7 @@ private: } bool isVolatile() const { - if (IsTargetMemInst) + if (IntrID != 0) return Info.IsVolatile; if (LoadInst *LI = dyn_cast(Inst)) { @@ -716,11 +743,6 @@ private: return false; } - bool isMatchingMemLoc(const ParseMemoryInst &Inst) const { - return (getPointerOperand() == Inst.getPointerOperand() && - getMatchingId() == Inst.getMatchingId()); - } - bool isValid() const { return getPointerOperand() != nullptr; } // For regular (non-intrinsic) loads/stores, this is set to -1. For @@ -728,44 +750,83 @@ private: // field in the MemIntrinsicInfo structure. That field contains // non-negative values only. int getMatchingId() const { - if (IsTargetMemInst) return Info.MatchingId; + if (IntrID != 0) + return Info.MatchingId; return -1; } Value *getPointerOperand() const { - if (IsTargetMemInst) return Info.PtrVal; + if (IntrID != 0) + return Info.PtrVal; return getLoadStorePointerOperand(Inst); } bool mayReadFromMemory() const { - if (IsTargetMemInst) return Info.ReadMem; + if (IntrID != 0) + return Info.ReadMem; return Inst->mayReadFromMemory(); } bool mayWriteToMemory() const { - if (IsTargetMemInst) return Info.WriteMem; + if (IntrID != 0) + return Info.WriteMem; return Inst->mayWriteToMemory(); } private: - bool IsTargetMemInst = false; + Intrinsic::ID IntrID = 0; MemIntrinsicInfo Info; Instruction *Inst; }; + // This function is to prevent accidentally passing a non-target + // intrinsic ID to TargetTransformInfo. + static bool isHandledNonTargetIntrinsic(Intrinsic::ID ID) { + switch (ID) { + case Intrinsic::masked_load: + case Intrinsic::masked_store: + return true; + } + return false; + } + static bool isHandledNonTargetIntrinsic(const Value *V) { + if (auto *II = dyn_cast(V)) + return isHandledNonTargetIntrinsic(II->getIntrinsicID()); + return false; + } + bool processNode(DomTreeNode *Node); bool handleBranchCondition(Instruction *CondInst, const BranchInst *BI, const BasicBlock *BB, const BasicBlock *Pred); + Value *getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst, + unsigned CurrentGeneration); + + bool overridingStores(const ParseMemoryInst &Earlier, + const ParseMemoryInst &Later); + Value *getOrCreateResult(Value *Inst, Type *ExpectedType) const { if (auto *LI = dyn_cast(Inst)) return LI; if (auto *SI = dyn_cast(Inst)) return SI->getValueOperand(); assert(isa(Inst) && "Instruction not supported"); - return TTI.getOrCreateResultFromMemIntrinsic(cast(Inst), - ExpectedType); + auto *II = cast(Inst); + if (isHandledNonTargetIntrinsic(II->getIntrinsicID())) + return getOrCreateResultNonTargetMemIntrinsic(II, ExpectedType); + return TTI.getOrCreateResultFromMemIntrinsic(II, ExpectedType); + } + + Value *getOrCreateResultNonTargetMemIntrinsic(IntrinsicInst *II, + Type *ExpectedType) const { + switch (II->getIntrinsicID()) { + case Intrinsic::masked_load: + return II; + case Intrinsic::masked_store: + return II->getOperand(0); + } + return nullptr; } /// Return true if the instruction is known to only operate on memory @@ -775,6 +836,101 @@ private: bool isSameMemGeneration(unsigned EarlierGeneration, unsigned LaterGeneration, Instruction *EarlierInst, Instruction *LaterInst); + bool isNonTargetIntrinsicMatch(const IntrinsicInst *Earlier, + const IntrinsicInst *Later) { + auto IsSubmask = [](const Value *Mask0, const Value *Mask1) { + // Is Mask0 a submask of Mask1? + if (Mask0 == Mask1) + return true; + if (isa(Mask0) || isa(Mask1)) + return false; + auto *Vec0 = dyn_cast(Mask0); + auto *Vec1 = dyn_cast(Mask1); + if (!Vec0 || !Vec1) + return false; + assert(Vec0->getType() == Vec1->getType() && + "Masks should have the same type"); + for (int i = 0, e = Vec0->getNumOperands(); i != e; ++i) { + Constant *Elem0 = Vec0->getOperand(i); + Constant *Elem1 = Vec1->getOperand(i); + auto *Int0 = dyn_cast(Elem0); + if (Int0 && Int0->isZero()) + continue; + auto *Int1 = dyn_cast(Elem1); + if (Int1 && !Int1->isZero()) + continue; + if (isa(Elem0) || isa(Elem1)) + return false; + if (Elem0 == Elem1) + continue; + return false; + } + return true; + }; + auto PtrOp = [](const IntrinsicInst *II) { + if (II->getIntrinsicID() == Intrinsic::masked_load) + return II->getOperand(0); + if (II->getIntrinsicID() == Intrinsic::masked_store) + return II->getOperand(1); + llvm_unreachable("Unexpected IntrinsicInst"); + }; + auto MaskOp = [](const IntrinsicInst *II) { + if (II->getIntrinsicID() == Intrinsic::masked_load) + return II->getOperand(2); + if (II->getIntrinsicID() == Intrinsic::masked_store) + return II->getOperand(3); + llvm_unreachable("Unexpected IntrinsicInst"); + }; + auto ThruOp = [](const IntrinsicInst *II) { + if (II->getIntrinsicID() == Intrinsic::masked_load) + return II->getOperand(3); + llvm_unreachable("Unexpected IntrinsicInst"); + }; + + if (PtrOp(Earlier) != PtrOp(Later)) + return false; + + Intrinsic::ID IDE = Earlier->getIntrinsicID(); + Intrinsic::ID IDL = Later->getIntrinsicID(); + // We could really use specific intrinsic classes for masked loads + // and stores in IntrinsicInst.h. + if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_load) { + // Trying to replace later masked load with the earlier one. + // Check that the pointers are the same, and + // - masks and pass-throughs are the same, or + // - replacee's pass-through is "undef" and replacer's mask is a + // super-set of the replacee's mask. + if (MaskOp(Earlier) == MaskOp(Later) && ThruOp(Earlier) == ThruOp(Later)) + return true; + if (!isa(ThruOp(Later))) + return false; + return IsSubmask(MaskOp(Later), MaskOp(Earlier)); + } + if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_load) { + // Trying to replace a load of a stored value with the store's value. + // Check that the pointers are the same, and + // - load's mask is a subset of store's mask, and + // - load's pass-through is "undef". + if (!IsSubmask(MaskOp(Later), MaskOp(Earlier))) + return false; + return isa(ThruOp(Later)); + } + if (IDE == Intrinsic::masked_load && IDL == Intrinsic::masked_store) { + // Trying to remove a store of the loaded value. + // Check that the pointers are the same, and + // - store's mask is a subset of the load's mask. + return IsSubmask(MaskOp(Later), MaskOp(Earlier)); + } + if (IDE == Intrinsic::masked_store && IDL == Intrinsic::masked_store) { + // Trying to remove a dead store (earlier). + // Check that the pointers are the same, + // - the to-be-removed store's mask is a subset of the other store's + // mask. + return IsSubmask(MaskOp(Earlier), MaskOp(Later)); + } + return false; + } + void removeMSSA(Instruction &Inst) { if (!MSSA) return; @@ -877,9 +1033,14 @@ bool EarlyCSE::handleBranchCondition(Instruction *CondInst, auto *TorF = (BI->getSuccessor(0) == BB) ? ConstantInt::getTrue(BB->getContext()) : ConstantInt::getFalse(BB->getContext()); - auto MatchBinOp = [](Instruction *I, unsigned Opcode) { - if (BinaryOperator *BOp = dyn_cast(I)) - return BOp->getOpcode() == Opcode; + auto MatchBinOp = [](Instruction *I, unsigned Opcode, Value *&LHS, + Value *&RHS) { + if (Opcode == Instruction::And && + match(I, m_LogicalAnd(m_Value(LHS), m_Value(RHS)))) + return true; + else if (Opcode == Instruction::Or && + match(I, m_LogicalOr(m_Value(LHS), m_Value(RHS)))) + return true; return false; }; // If the condition is AND operation, we can propagate its operands into the @@ -910,8 +1071,9 @@ bool EarlyCSE::handleBranchCondition(Instruction *CondInst, } } - if (MatchBinOp(Curr, PropagateOpcode)) - for (auto &Op : cast(Curr)->operands()) + Value *LHS, *RHS; + if (MatchBinOp(Curr, PropagateOpcode, LHS, RHS)) + for (auto &Op : { LHS, RHS }) if (Instruction *OPI = dyn_cast(Op)) if (SimpleValue::canHandle(OPI) && Visited.insert(OPI).second) WorkList.push_back(OPI); @@ -920,6 +1082,86 @@ bool EarlyCSE::handleBranchCondition(Instruction *CondInst, return MadeChanges; } +Value *EarlyCSE::getMatchingValue(LoadValue &InVal, ParseMemoryInst &MemInst, + unsigned CurrentGeneration) { + if (InVal.DefInst == nullptr) + return nullptr; + if (InVal.MatchingId != MemInst.getMatchingId()) + return nullptr; + // We don't yet handle removing loads with ordering of any kind. + if (MemInst.isVolatile() || !MemInst.isUnordered()) + return nullptr; + // We can't replace an atomic load with one which isn't also atomic. + if (MemInst.isLoad() && !InVal.IsAtomic && MemInst.isAtomic()) + return nullptr; + // The value V returned from this function is used differently depending + // on whether MemInst is a load or a store. If it's a load, we will replace + // MemInst with V, if it's a store, we will check if V is the same as the + // available value. + bool MemInstMatching = !MemInst.isLoad(); + Instruction *Matching = MemInstMatching ? MemInst.get() : InVal.DefInst; + Instruction *Other = MemInstMatching ? InVal.DefInst : MemInst.get(); + + // For stores check the result values before checking memory generation + // (otherwise isSameMemGeneration may crash). + Value *Result = MemInst.isStore() + ? getOrCreateResult(Matching, Other->getType()) + : nullptr; + if (MemInst.isStore() && InVal.DefInst != Result) + return nullptr; + + // Deal with non-target memory intrinsics. + bool MatchingNTI = isHandledNonTargetIntrinsic(Matching); + bool OtherNTI = isHandledNonTargetIntrinsic(Other); + if (OtherNTI != MatchingNTI) + return nullptr; + if (OtherNTI && MatchingNTI) { + if (!isNonTargetIntrinsicMatch(cast(InVal.DefInst), + cast(MemInst.get()))) + return nullptr; + } + + if (!isOperatingOnInvariantMemAt(MemInst.get(), InVal.Generation) && + !isSameMemGeneration(InVal.Generation, CurrentGeneration, InVal.DefInst, + MemInst.get())) + return nullptr; + + if (!Result) + Result = getOrCreateResult(Matching, Other->getType()); + return Result; +} + +bool EarlyCSE::overridingStores(const ParseMemoryInst &Earlier, + const ParseMemoryInst &Later) { + // Can we remove Earlier store because of Later store? + + assert(Earlier.isUnordered() && !Earlier.isVolatile() && + "Violated invariant"); + if (Earlier.getPointerOperand() != Later.getPointerOperand()) + return false; + if (Earlier.getMatchingId() != Later.getMatchingId()) + return false; + // At the moment, we don't remove ordered stores, but do remove + // unordered atomic stores. There's no special requirement (for + // unordered atomics) about removing atomic stores only in favor of + // other atomic stores since we were going to execute the non-atomic + // one anyway and the atomic one might never have become visible. + if (!Earlier.isUnordered() || !Later.isUnordered()) + return false; + + // Deal with non-target memory intrinsics. + bool ENTI = isHandledNonTargetIntrinsic(Earlier.get()); + bool LNTI = isHandledNonTargetIntrinsic(Later.get()); + if (ENTI && LNTI) + return isNonTargetIntrinsicMatch(cast(Earlier.get()), + cast(Later.get())); + + // Because of the check above, at least one of them is false. + // For now disallow matching intrinsics with non-intrinsics, + // so assume that the stores match if neither is an intrinsic. + return ENTI == LNTI; +} + bool EarlyCSE::processNode(DomTreeNode *Node) { bool Changed = false; BasicBlock *BB = Node->getBlock(); @@ -990,6 +1232,14 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { continue; } + // Likewise, noalias intrinsics don't actually write. + if (match(&Inst, + m_Intrinsic())) { + LLVM_DEBUG(dbgs() << "EarlyCSE skipping noalias intrinsic: " << Inst + << '\n'); + continue; + } + // Skip sideeffect intrinsics, for the same reason as assume intrinsics. if (match(&Inst, m_Intrinsic())) { LLVM_DEBUG(dbgs() << "EarlyCSE skipping sideeffect: " << Inst << '\n'); @@ -1136,32 +1386,21 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { // we can assume the current load loads the same value as the dominating // load. LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand()); - if (InVal.DefInst != nullptr && - InVal.MatchingId == MemInst.getMatchingId() && - // We don't yet handle removing loads with ordering of any kind. - !MemInst.isVolatile() && MemInst.isUnordered() && - // We can't replace an atomic load with one which isn't also atomic. - InVal.IsAtomic >= MemInst.isAtomic() && - (isOperatingOnInvariantMemAt(&Inst, InVal.Generation) || - isSameMemGeneration(InVal.Generation, CurrentGeneration, - InVal.DefInst, &Inst))) { - Value *Op = getOrCreateResult(InVal.DefInst, Inst.getType()); - if (Op != nullptr) { - LLVM_DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << Inst - << " to: " << *InVal.DefInst << '\n'); - if (!DebugCounter::shouldExecute(CSECounter)) { - LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n"); - continue; - } - if (!Inst.use_empty()) - Inst.replaceAllUsesWith(Op); - salvageKnowledge(&Inst, &AC); - removeMSSA(Inst); - Inst.eraseFromParent(); - Changed = true; - ++NumCSELoad; + if (Value *Op = getMatchingValue(InVal, MemInst, CurrentGeneration)) { + LLVM_DEBUG(dbgs() << "EarlyCSE CSE LOAD: " << Inst + << " to: " << *InVal.DefInst << '\n'); + if (!DebugCounter::shouldExecute(CSECounter)) { + LLVM_DEBUG(dbgs() << "Skipping due to debug counter\n"); continue; } + if (!Inst.use_empty()) + Inst.replaceAllUsesWith(Op); + salvageKnowledge(&Inst, &AC); + removeMSSA(Inst); + Inst.eraseFromParent(); + Changed = true; + ++NumCSELoad; + continue; } // Otherwise, remember that we have this instruction. @@ -1231,13 +1470,7 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { if (MemInst.isValid() && MemInst.isStore()) { LoadValue InVal = AvailableLoads.lookup(MemInst.getPointerOperand()); if (InVal.DefInst && - InVal.DefInst == getOrCreateResult(&Inst, InVal.DefInst->getType()) && - InVal.MatchingId == MemInst.getMatchingId() && - // We don't yet handle removing stores with ordering of any kind. - !MemInst.isVolatile() && MemInst.isUnordered() && - (isOperatingOnInvariantMemAt(&Inst, InVal.Generation) || - isSameMemGeneration(InVal.Generation, CurrentGeneration, - InVal.DefInst, &Inst))) { + InVal.DefInst == getMatchingValue(InVal, MemInst, CurrentGeneration)) { // It is okay to have a LastStore to a different pointer here if MemorySSA // tells us that the load and store are from the same memory generation. // In that case, LastStore should keep its present value since we're @@ -1272,17 +1505,8 @@ bool EarlyCSE::processNode(DomTreeNode *Node) { if (MemInst.isValid() && MemInst.isStore()) { // We do a trivial form of DSE if there are two stores to the same // location with no intervening loads. Delete the earlier store. - // At the moment, we don't remove ordered stores, but do remove - // unordered atomic stores. There's no special requirement (for - // unordered atomics) about removing atomic stores only in favor of - // other atomic stores since we were going to execute the non-atomic - // one anyway and the atomic one might never have become visible. if (LastStore) { - ParseMemoryInst LastStoreMemInst(LastStore, TTI); - assert(LastStoreMemInst.isUnordered() && - !LastStoreMemInst.isVolatile() && - "Violated invariant"); - if (LastStoreMemInst.isMatchingMemLoc(MemInst)) { + if (overridingStores(ParseMemoryInst(LastStore, TTI), MemInst)) { LLVM_DEBUG(dbgs() << "EarlyCSE DEAD STORE: " << *LastStore << " due to: " << Inst << '\n'); if (!DebugCounter::shouldExecute(CSECounter)) { @@ -1443,6 +1667,7 @@ public: AU.addRequired(); AU.addRequired(); if (UseMemorySSA) { + AU.addRequired(); AU.addRequired(); AU.addPreserved(); } @@ -1484,6 +1709,7 @@ INITIALIZE_PASS_BEGIN(EarlyCSEMemSSALegacyPass, "early-cse-memssa", "Early CSE w/ MemorySSA", false, false) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) diff --git a/llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp b/llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp index 72512430b366..e54a270fb276 100644 --- a/llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp +++ b/llvm/lib/Transforms/Scalar/FlattenCFGPass.cpp @@ -12,6 +12,7 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/InstrTypes.h" #include "llvm/IR/ValueHandle.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" diff --git a/llvm/lib/Transforms/Scalar/Float2Int.cpp b/llvm/lib/Transforms/Scalar/Float2Int.cpp index 83f4c402ed4d..b6d82685e884 100644 --- a/llvm/lib/Transforms/Scalar/Float2Int.cpp +++ b/llvm/lib/Transforms/Scalar/Float2Int.cpp @@ -19,7 +19,6 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/APSInt.h" #include "llvm/ADT/SmallVector.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/IR/Constants.h" #include "llvm/IR/IRBuilder.h" diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp index b16f8591b5a4..c6b6d75aefe8 100644 --- a/llvm/lib/Transforms/Scalar/GVN.cpp +++ b/llvm/lib/Transforms/Scalar/GVN.cpp @@ -26,8 +26,8 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/DomTreeUpdater.h" @@ -36,6 +36,8 @@ #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemoryBuiltins.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/PHITransAddr.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -46,7 +48,6 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" @@ -98,21 +99,33 @@ STATISTIC(NumGVNSimpl, "Number of instructions simplified"); STATISTIC(NumGVNEqProp, "Number of equalities propagated"); STATISTIC(NumPRELoad, "Number of loads PRE'd"); +STATISTIC(IsValueFullyAvailableInBlockNumSpeculationsMax, + "Number of blocks speculated as available in " + "IsValueFullyAvailableInBlock(), max"); +STATISTIC(MaxBBSpeculationCutoffReachedTimes, + "Number of times we we reached gvn-max-block-speculations cut-off " + "preventing further exploration"); + static cl::opt GVNEnablePRE("enable-pre", cl::init(true), cl::Hidden); static cl::opt GVNEnableLoadPRE("enable-load-pre", cl::init(true)); static cl::opt GVNEnableLoadInLoopPRE("enable-load-in-loop-pre", cl::init(true)); +static cl::opt +GVNEnableSplitBackedgeInLoadPRE("enable-split-backedge-in-load-pre", + cl::init(true)); static cl::opt GVNEnableMemDep("enable-gvn-memdep", cl::init(true)); -// Maximum allowed recursion depth. -static cl::opt -MaxRecurseDepth("gvn-max-recurse-depth", cl::Hidden, cl::init(1000), cl::ZeroOrMore, - cl::desc("Max recurse depth in GVN (default = 1000)")); - static cl::opt MaxNumDeps( "gvn-max-num-deps", cl::Hidden, cl::init(100), cl::ZeroOrMore, cl::desc("Max number of dependences to attempt Load PRE (default = 100)")); +// This is based on IsValueFullyAvailableInBlockNumSpeculationsMax stat. +static cl::opt MaxBBSpeculations( + "gvn-max-block-speculations", cl::Hidden, cl::init(600), cl::ZeroOrMore, + cl::desc("Max number of blocks we're willing to speculate on (and recurse " + "into) when deducing if a value is fully available or not in GVN " + "(default = 600)")); + struct llvm::GVN::Expression { uint32_t opcode; bool commutative = false; @@ -282,9 +295,9 @@ GVN::Expression GVN::ValueTable::createExpr(Instruction *I) { if (I->isCommutative()) { // Ensure that commutative instructions that only differ by a permutation // of their operands get the same value number by sorting the operand value - // numbers. Since all commutative instructions have two operands it is more + // numbers. Since commutative operands are the 1st two operands it is more // efficient to sort by hand rather than using, say, std::sort. - assert(I->getNumOperands() == 2 && "Unsupported commutative instruction!"); + assert(I->getNumOperands() >= 2 && "Unsupported commutative instruction!"); if (e.varargs[0] > e.varargs[1]) std::swap(e.varargs[0], e.varargs[1]); e.commutative = true; @@ -353,9 +366,7 @@ GVN::Expression GVN::ValueTable::createExtractvalueExpr(ExtractValueInst *EI) { OI != OE; ++OI) e.varargs.push_back(lookupOrAdd(*OI)); - for (ExtractValueInst::idx_iterator II = EI->idx_begin(), IE = EI->idx_end(); - II != IE; ++II) - e.varargs.push_back(*II); + append_range(e.varargs, EI->indices()); return e; } @@ -399,9 +410,12 @@ uint32_t GVN::ValueTable::lookupOrAddCall(CallInst *C) { } if (local_dep.isDef()) { - CallInst* local_cdep = cast(local_dep.getInst()); + // For masked load/store intrinsics, the local_dep may actully be + // a normal load or store instruction. + CallInst *local_cdep = dyn_cast(local_dep.getInst()); - if (local_cdep->getNumArgOperands() != C->getNumArgOperands()) { + if (!local_cdep || + local_cdep->getNumArgOperands() != C->getNumArgOperands()) { valueNumbering[C] = nextValueNumber; return nextValueNumber++; } @@ -626,6 +640,11 @@ bool GVN::isLoadInLoopPREEnabled() const { return Options.AllowLoadInLoopPRE.getValueOr(GVNEnableLoadInLoopPRE); } +bool GVN::isLoadPRESplitBackedgeEnabled() const { + return Options.AllowLoadPRESplitBackedge.getValueOr( + GVNEnableSplitBackedgeInLoadPRE); +} + bool GVN::isMemDepEnabled() const { return Options.AllowMemDep.getValueOr(GVNEnableMemDep); } @@ -642,14 +661,18 @@ PreservedAnalyses GVN::run(Function &F, FunctionAnalysisManager &AM) { auto *MemDep = isMemDepEnabled() ? &AM.getResult(F) : nullptr; auto *LI = AM.getCachedResult(F); + auto *MSSA = AM.getCachedResult(F); auto &ORE = AM.getResult(F); - bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE); + bool Changed = runImpl(F, AC, DT, TLI, AA, MemDep, LI, &ORE, + MSSA ? &MSSA->getMSSA() : nullptr); if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserve(); PA.preserve(); PA.preserve(); + if (MSSA) + PA.preserve(); if (LI) PA.preserve(); return PA; @@ -667,6 +690,18 @@ LLVM_DUMP_METHOD void GVN::dump(DenseMap& d) const { } #endif +enum class AvailabilityState : char { + /// We know the block *is not* fully available. This is a fixpoint. + Unavailable = 0, + /// We know the block *is* fully available. This is a fixpoint. + Available = 1, + /// We do not know whether the block is fully available or not, + /// but we are currently speculating that it will be. + /// If it would have turned out that the block was, in fact, not fully + /// available, this would have been cleaned up into an Unavailable. + SpeculativelyAvailable = 2, +}; + /// Return true if we can prove that the value /// we're analyzing is fully available in the specified block. As we go, keep /// track of which blocks we know are fully alive in FullyAvailableBlocks. This @@ -675,76 +710,118 @@ LLVM_DUMP_METHOD void GVN::dump(DenseMap& d) const { /// 1) we know the block *is* fully available. /// 2) we do not know whether the block is fully available or not, but we are /// currently speculating that it will be. -/// 3) we are speculating for this block and have used that to speculate for -/// other blocks. -static bool IsValueFullyAvailableInBlock(BasicBlock *BB, - DenseMap &FullyAvailableBlocks, - uint32_t RecurseDepth) { - if (RecurseDepth > MaxRecurseDepth) - return false; - - // Optimistically assume that the block is fully available and check to see - // if we already know about this block in one lookup. - std::pair::iterator, bool> IV = - FullyAvailableBlocks.insert(std::make_pair(BB, 2)); - - // If the entry already existed for this block, return the precomputed value. - if (!IV.second) { - // If this is a speculative "available" value, mark it as being used for - // speculation of other blocks. - if (IV.first->second == 2) - IV.first->second = 3; - return IV.first->second != 0; - } - - // Otherwise, see if it is fully available in all predecessors. - pred_iterator PI = pred_begin(BB), PE = pred_end(BB); - - // If this block has no predecessors, it isn't live-in here. - if (PI == PE) - goto SpeculationFailure; +static bool IsValueFullyAvailableInBlock( + BasicBlock *BB, + DenseMap &FullyAvailableBlocks) { + SmallVector Worklist; + Optional UnavailableBB; + + // The number of times we didn't find an entry for a block in a map and + // optimistically inserted an entry marking block as speculatively available. + unsigned NumNewNewSpeculativelyAvailableBBs = 0; + +#ifndef NDEBUG + SmallSet NewSpeculativelyAvailableBBs; + SmallVector AvailableBBs; +#endif - for (; PI != PE; ++PI) - // If the value isn't fully available in one of our predecessors, then it - // isn't fully available in this block either. Undo our previous - // optimistic assumption and bail out. - if (!IsValueFullyAvailableInBlock(*PI, FullyAvailableBlocks,RecurseDepth+1)) - goto SpeculationFailure; + Worklist.emplace_back(BB); + while (!Worklist.empty()) { + BasicBlock *CurrBB = Worklist.pop_back_val(); // LIFO - depth-first! + // Optimistically assume that the block is Speculatively Available and check + // to see if we already know about this block in one lookup. + std::pair::iterator, bool> IV = + FullyAvailableBlocks.try_emplace( + CurrBB, AvailabilityState::SpeculativelyAvailable); + AvailabilityState &State = IV.first->second; + + // Did the entry already exist for this block? + if (!IV.second) { + if (State == AvailabilityState::Unavailable) { + UnavailableBB = CurrBB; + break; // Backpropagate unavailability info. + } - return true; +#ifndef NDEBUG + AvailableBBs.emplace_back(CurrBB); +#endif + continue; // Don't recurse further, but continue processing worklist. + } -// If we get here, we found out that this is not, after -// all, a fully-available block. We have a problem if we speculated on this and -// used the speculation to mark other blocks as available. -SpeculationFailure: - char &BBVal = FullyAvailableBlocks[BB]; + // No entry found for block. + ++NumNewNewSpeculativelyAvailableBBs; + bool OutOfBudget = NumNewNewSpeculativelyAvailableBBs > MaxBBSpeculations; + + // If we have exhausted our budget, mark this block as unavailable. + // Also, if this block has no predecessors, the value isn't live-in here. + if (OutOfBudget || pred_empty(CurrBB)) { + MaxBBSpeculationCutoffReachedTimes += (int)OutOfBudget; + State = AvailabilityState::Unavailable; + UnavailableBB = CurrBB; + break; // Backpropagate unavailability info. + } - // If we didn't speculate on this, just return with it set to false. - if (BBVal == 2) { - BBVal = 0; - return false; + // Tentatively consider this block as speculatively available. +#ifndef NDEBUG + NewSpeculativelyAvailableBBs.insert(CurrBB); +#endif + // And further recurse into block's predecessors, in depth-first order! + Worklist.append(pred_begin(CurrBB), pred_end(CurrBB)); } - // If we did speculate on this value, we could have blocks set to 1 that are - // incorrect. Walk the (transitive) successors of this block and mark them as - // 0 if set to one. - SmallVector BBWorklist; - BBWorklist.push_back(BB); - - do { - BasicBlock *Entry = BBWorklist.pop_back_val(); - // Note that this sets blocks to 0 (unavailable) if they happen to not - // already be in FullyAvailableBlocks. This is safe. - char &EntryVal = FullyAvailableBlocks[Entry]; - if (EntryVal == 0) continue; // Already unavailable. - - // Mark as unavailable. - EntryVal = 0; +#if LLVM_ENABLE_STATS + IsValueFullyAvailableInBlockNumSpeculationsMax.updateMax( + NumNewNewSpeculativelyAvailableBBs); +#endif - BBWorklist.append(succ_begin(Entry), succ_end(Entry)); - } while (!BBWorklist.empty()); + // If the block isn't marked as fixpoint yet + // (the Unavailable and Available states are fixpoints) + auto MarkAsFixpointAndEnqueueSuccessors = + [&](BasicBlock *BB, AvailabilityState FixpointState) { + auto It = FullyAvailableBlocks.find(BB); + if (It == FullyAvailableBlocks.end()) + return; // Never queried this block, leave as-is. + switch (AvailabilityState &State = It->second) { + case AvailabilityState::Unavailable: + case AvailabilityState::Available: + return; // Don't backpropagate further, continue processing worklist. + case AvailabilityState::SpeculativelyAvailable: // Fix it! + State = FixpointState; +#ifndef NDEBUG + assert(NewSpeculativelyAvailableBBs.erase(BB) && + "Found a speculatively available successor leftover?"); +#endif + // Queue successors for further processing. + Worklist.append(succ_begin(BB), succ_end(BB)); + return; + } + }; + + if (UnavailableBB) { + // Okay, we have encountered an unavailable block. + // Mark speculatively available blocks reachable from UnavailableBB as + // unavailable as well. Paths are terminated when they reach blocks not in + // FullyAvailableBlocks or they are not marked as speculatively available. + Worklist.clear(); + Worklist.append(succ_begin(*UnavailableBB), succ_end(*UnavailableBB)); + while (!Worklist.empty()) + MarkAsFixpointAndEnqueueSuccessors(Worklist.pop_back_val(), + AvailabilityState::Unavailable); + } + +#ifndef NDEBUG + Worklist.clear(); + for (BasicBlock *AvailableBB : AvailableBBs) + Worklist.append(succ_begin(AvailableBB), succ_end(AvailableBB)); + while (!Worklist.empty()) + MarkAsFixpointAndEnqueueSuccessors(Worklist.pop_back_val(), + AvailabilityState::Available); + + assert(NewSpeculativelyAvailableBBs.empty() && + "Must have fixed all the new speculatively available blocks."); +#endif - return false; + return !UnavailableBB; } /// Given a set of loads specified by ValuesPerBlock, @@ -963,7 +1040,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *LI, MemDepResult DepInfo, if (StoreInst *S = dyn_cast(DepInst)) { // Reject loads and stores that are to the same address but are of - // different types if we have to. If the stored value is larger or equal to + // different types if we have to. If the stored value is convertable to // the loaded value, we can reuse it. if (!canCoerceMustAliasedValueToLoad(S->getValueOperand(), LI->getType(), DL)) @@ -1062,7 +1139,6 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, // backwards through predecessors if needed. BasicBlock *LoadBB = LI->getParent(); BasicBlock *TmpBB = LoadBB; - bool IsSafeToSpeculativelyExecute = isSafeToSpeculativelyExecute(LI); // Check that there is no implicit control flow instructions above our load in // its block. If there is an instruction that doesn't always pass the @@ -1079,8 +1155,9 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, // because if the index is out of bounds we should deoptimize rather than // access the array. // Check that there is no guard in this block above our instruction. - if (!IsSafeToSpeculativelyExecute && ICF->isDominatedByICFIFromSameBlock(LI)) - return false; + bool MustEnsureSafetyOfSpeculativeExecution = + ICF->isDominatedByICFIFromSameBlock(LI); + while (TmpBB->getSinglePredecessor()) { TmpBB = TmpBB->getSinglePredecessor(); if (TmpBB == LoadBB) // Infinite (unreachable) loop. @@ -1097,8 +1174,8 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, return false; // Check that there is no implicit control flow in a block above. - if (!IsSafeToSpeculativelyExecute && ICF->hasICF(TmpBB)) - return false; + MustEnsureSafetyOfSpeculativeExecution = + MustEnsureSafetyOfSpeculativeExecution || ICF->hasICF(TmpBB); } assert(TmpBB); @@ -1107,11 +1184,11 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, // Check to see how many predecessors have the loaded value fully // available. MapVector PredLoads; - DenseMap FullyAvailableBlocks; + DenseMap FullyAvailableBlocks; for (const AvailableValueInBlock &AV : ValuesPerBlock) - FullyAvailableBlocks[AV.BB] = true; + FullyAvailableBlocks[AV.BB] = AvailabilityState::Available; for (BasicBlock *UnavailableBB : UnavailableBlocks) - FullyAvailableBlocks[UnavailableBB] = false; + FullyAvailableBlocks[UnavailableBB] = AvailabilityState::Unavailable; SmallVector CriticalEdgePred; for (BasicBlock *Pred : predecessors(LoadBB)) { @@ -1124,7 +1201,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, return false; } - if (IsValueFullyAvailableInBlock(Pred, FullyAvailableBlocks, 0)) { + if (IsValueFullyAvailableInBlock(Pred, FullyAvailableBlocks)) { continue; } @@ -1151,6 +1228,16 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, return false; } + // Do not split backedge as it will break the canonical loop form. + if (!isLoadPRESplitBackedgeEnabled()) + if (DT->dominates(LoadBB, Pred)) { + LLVM_DEBUG( + dbgs() + << "COULD NOT PRE LOAD BECAUSE OF A BACKEDGE CRITICAL EDGE '" + << Pred->getName() << "': " << *LI << '\n'); + return false; + } + CriticalEdgePred.push_back(Pred); } else { // Only add the predecessors that will not be split for now. @@ -1170,6 +1257,17 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, if (NumUnavailablePreds != 1) return false; + // Now we know where we will insert load. We must ensure that it is safe + // to speculatively execute the load at that points. + if (MustEnsureSafetyOfSpeculativeExecution) { + if (CriticalEdgePred.size()) + if (!isSafeToSpeculativelyExecute(LI, LoadBB->getFirstNonPHI(), DT)) + return false; + for (auto &PL : PredLoads) + if (!isSafeToSpeculativelyExecute(LI, PL.first->getTerminator(), DT)) + return false; + } + // Split critical edges, and update the unavailable predecessors accordingly. for (BasicBlock *OrigPred : CriticalEdgePred) { BasicBlock *NewPred = splitCriticalEdges(OrigPred, LoadBB); @@ -1251,8 +1349,7 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, // Instructions that have been inserted in predecessor(s) to materialize // the load address do not retain their original debug locations. Doing // so could lead to confusing (but correct) source attributions. - if (const DebugLoc &DL = I->getDebugLoc()) - I->setDebugLoc(DebugLoc::get(0, 0, DL.getScope(), DL.getInlinedAt())); + I->updateLocationAfterHoist(); // FIXME: We really _ought_ to insert these value numbers into their // parent's availability map. However, in doing so, we risk getting into @@ -1270,6 +1367,22 @@ bool GVN::PerformLoadPRE(LoadInst *LI, AvailValInBlkVect &ValuesPerBlock, LI->getAlign(), LI->getOrdering(), LI->getSyncScopeID(), UnavailablePred->getTerminator()); NewLoad->setDebugLoc(LI->getDebugLoc()); + if (MSSAU) { + auto *MSSA = MSSAU->getMemorySSA(); + // Get the defining access of the original load or use the load if it is a + // MemoryDef (e.g. because it is volatile). The inserted loads are + // guaranteed to load from the same definition. + auto *LIAcc = MSSA->getMemoryAccess(LI); + auto *DefiningAcc = + isa(LIAcc) ? LIAcc : LIAcc->getDefiningAccess(); + auto *NewAccess = MSSAU->createMemoryAccessInBB( + NewLoad, DefiningAcc, NewLoad->getParent(), + MemorySSA::BeforeTerminator); + if (auto *NewDef = dyn_cast(NewAccess)) + MSSAU->insertDef(NewDef, /*RenameUses=*/true); + else + MSSAU->insertUse(cast(NewAccess), /*RenameUses=*/true); + } // Transfer the old load's AA tags to the new load. AAMDNodes Tags; @@ -1357,13 +1470,14 @@ bool GVN::processNonLocalLoad(LoadInst *LI) { return false; } + bool Changed = false; // If this load follows a GEP, see if we can PRE the indices before analyzing. if (GetElementPtrInst *GEP = dyn_cast(LI->getOperand(0))) { for (GetElementPtrInst::op_iterator OI = GEP->idx_begin(), OE = GEP->idx_end(); OI != OE; ++OI) if (Instruction *I = dyn_cast(OI->get())) - performScalarPRE(I); + Changed |= performScalarPRE(I); } // Step 2: Analyze the availability of the load @@ -1374,7 +1488,7 @@ bool GVN::processNonLocalLoad(LoadInst *LI) { // If we have no predecessors that produce a known value for this load, exit // early. if (ValuesPerBlock.empty()) - return false; + return Changed; // Step 3: Eliminate fully redundancy. // @@ -1406,12 +1520,12 @@ bool GVN::processNonLocalLoad(LoadInst *LI) { // Step 4: Eliminate partial redundancy. if (!isPREEnabled() || !isLoadPREEnabled()) - return false; + return Changed; if (!isLoadInLoopPREEnabled() && this->LI && this->LI->getLoopFor(LI->getParent())) - return false; + return Changed; - return PerformLoadPRE(LI, ValuesPerBlock, UnavailableBlocks); + return Changed || PerformLoadPRE(LI, ValuesPerBlock, UnavailableBlocks); } static bool impliesEquivalanceIfTrue(CmpInst* Cmp) { @@ -1486,9 +1600,40 @@ bool GVN::processAssumeIntrinsic(IntrinsicInst *IntrinsicI) { // Insert a new store to null instruction before the load to indicate that // this code is not reachable. FIXME: We could insert unreachable // instruction directly because we can modify the CFG. - new StoreInst(UndefValue::get(Int8Ty), - Constant::getNullValue(Int8Ty->getPointerTo()), - IntrinsicI); + auto *NewS = new StoreInst(UndefValue::get(Int8Ty), + Constant::getNullValue(Int8Ty->getPointerTo()), + IntrinsicI); + if (MSSAU) { + const MemoryUseOrDef *FirstNonDom = nullptr; + const auto *AL = + MSSAU->getMemorySSA()->getBlockAccesses(IntrinsicI->getParent()); + + // If there are accesses in the current basic block, find the first one + // that does not come before NewS. The new memory access is inserted + // after the found access or before the terminator if no such access is + // found. + if (AL) { + for (auto &Acc : *AL) { + if (auto *Current = dyn_cast(&Acc)) + if (!Current->getMemoryInst()->comesBefore(NewS)) { + FirstNonDom = Current; + break; + } + } + } + + // This added store is to null, so it will never executed and we can + // just use the LiveOnEntry def as defining access. + auto *NewDef = + FirstNonDom ? MSSAU->createMemoryAccessBefore( + NewS, MSSAU->getMemorySSA()->getLiveOnEntryDef(), + const_cast(FirstNonDom)) + : MSSAU->createMemoryAccessInBB( + NewS, MSSAU->getMemorySSA()->getLiveOnEntryDef(), + NewS->getParent(), MemorySSA::BeforeTerminator); + + MSSAU->insertDef(cast(NewDef), /*RenameUses=*/false); + } } if (isAssumeWithEmptyBundle(*IntrinsicI)) markInstructionForDeletion(IntrinsicI); @@ -1516,6 +1661,11 @@ bool GVN::processAssumeIntrinsic(IntrinsicInst *IntrinsicI) { // br i1 %cmp, label %bb1, label %bb2 ; will change %cmp to true ReplaceOperandsWithMap[V] = True; + // Similarly, after assume(!NotV) we know that NotV == false. + Value *NotV; + if (match(V, m_Not(m_Value(NotV)))) + ReplaceOperandsWithMap[NotV] = ConstantInt::getFalse(V->getContext()); + // If we find an equality fact, canonicalize all dominated uses in this block // to one of the two values. We heuristically choice the "oldest" of the // two where age is determined by value number. (Note that propagateEquality @@ -1622,6 +1772,8 @@ bool GVN::processLoad(LoadInst *L) { // Replace the load! patchAndReplaceAllUsesWith(L, AvailableValue); markInstructionForDeletion(L); + if (MSSAU) + MSSAU->removeMemoryAccess(L); ++NumGVNLoad; reportLoadElim(L, AvailableValue, ORE); // Tell MDA to rexamine the reused pointer since we might have more @@ -1743,7 +1895,7 @@ uint32_t GVN::ValueTable::phiTranslateImpl(const BasicBlock *Pred, } if (Exp.commutative) { - assert(Exp.varargs.size() == 2 && "Unsupported commutative expression!"); + assert(Exp.varargs.size() >= 2 && "Unsupported commutative instruction!"); if (Exp.varargs[0] > Exp.varargs[1]) { std::swap(Exp.varargs[0], Exp.varargs[1]); uint32_t Opcode = Exp.opcode >> 8; @@ -1766,11 +1918,8 @@ uint32_t GVN::ValueTable::phiTranslateImpl(const BasicBlock *Pred, /// again. void GVN::ValueTable::eraseTranslateCacheEntry(uint32_t Num, const BasicBlock &CurrBlock) { - for (const BasicBlock *Pred : predecessors(&CurrBlock)) { - auto FindRes = PhiTranslateTable.find({Num, Pred}); - if (FindRes != PhiTranslateTable.end()) - PhiTranslateTable.erase(FindRes); - } + for (const BasicBlock *Pred : predecessors(&CurrBlock)) + PhiTranslateTable.erase({Num, Pred}); } // In order to find a leader for a given value number at a @@ -1934,8 +2083,8 @@ bool GVN::propagateEquality(Value *LHS, Value *RHS, const BasicBlockEdge &Root, // If "A && B" is known true then both A and B are known true. If "A || B" // is known false then both A and B are known false. Value *A, *B; - if ((isKnownTrue && match(LHS, m_And(m_Value(A), m_Value(B)))) || - (isKnownFalse && match(LHS, m_Or(m_Value(A), m_Value(B))))) { + if ((isKnownTrue && match(LHS, m_LogicalAnd(m_Value(A), m_Value(B)))) || + (isKnownFalse && match(LHS, m_LogicalOr(m_Value(A), m_Value(B))))) { Worklist.push_back(std::make_pair(A, RHS)); Worklist.push_back(std::make_pair(B, RHS)); continue; @@ -2137,7 +2286,7 @@ bool GVN::processInstruction(Instruction *I) { bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, const TargetLibraryInfo &RunTLI, AAResults &RunAA, MemoryDependenceResults *RunMD, LoopInfo *LI, - OptimizationRemarkEmitter *RunORE) { + OptimizationRemarkEmitter *RunORE, MemorySSA *MSSA) { AC = &RunAC; DT = &RunDT; VN.setDomTree(DT); @@ -2150,6 +2299,8 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, VN.setMemDep(MD); ORE = RunORE; InvalidBlockRPONumbers = true; + MemorySSAUpdater Updater(MSSA); + MSSAU = MSSA ? &Updater : nullptr; bool Changed = false; bool ShouldContinue = true; @@ -2160,7 +2311,7 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ) { BasicBlock *BB = &*FI++; - bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, nullptr, MD); + bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, MSSAU, MD); if (removedBlock) ++NumGVNBlocks; @@ -2196,6 +2347,9 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT, // iteration. DeadBlocks.clear(); + if (MSSA && VerifyMemorySSA) + MSSA->verifyMemorySSA(); + return Changed; } @@ -2236,6 +2390,8 @@ bool GVN::processBlock(BasicBlock *BB) { salvageKnowledge(I, AC); salvageDebugInfo(*I); if (MD) MD->removeInstruction(I); + if (MSSAU) + MSSAU->removeMemoryAccess(I); LLVM_DEBUG(verifyRemoved(I)); ICF->removeInstruction(I); I->eraseFromParent(); @@ -2323,10 +2479,14 @@ bool GVN::performScalarPRE(Instruction *CurInst) { if (isa(CurInst)) return false; - // We don't currently value number ANY inline asm calls. - if (auto *CallB = dyn_cast(CurInst)) + if (auto *CallB = dyn_cast(CurInst)) { + // We don't currently value number ANY inline asm calls. if (CallB->isInlineAsm()) return false; + // Don't do PRE on convergent calls. + if (CallB->isConvergent()) + return false; + } uint32_t ValNo = VN.lookup(CurInst); @@ -2466,6 +2626,8 @@ bool GVN::performScalarPRE(Instruction *CurInst) { LLVM_DEBUG(dbgs() << "GVN PRE removed: " << *CurInst << '\n'); if (MD) MD->removeInstruction(CurInst); + if (MSSAU) + MSSAU->removeMemoryAccess(CurInst); LLVM_DEBUG(verifyRemoved(CurInst)); // FIXME: Intended to be markInstructionForDeletion(CurInst), but it causes // some assertion failures. @@ -2510,10 +2672,12 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) { // possible. BasicBlock *BB = SplitCriticalEdge( Pred, Succ, - CriticalEdgeSplittingOptions(DT, LI).unsetPreserveLoopSimplify()); - if (MD) - MD->invalidateCachedPredecessors(); - InvalidBlockRPONumbers = true; + CriticalEdgeSplittingOptions(DT, LI, MSSAU).unsetPreserveLoopSimplify()); + if (BB) { + if (MD) + MD->invalidateCachedPredecessors(); + InvalidBlockRPONumbers = true; + } return BB; } @@ -2522,14 +2686,20 @@ BasicBlock *GVN::splitCriticalEdges(BasicBlock *Pred, BasicBlock *Succ) { bool GVN::splitCriticalEdges() { if (toSplit.empty()) return false; + + bool Changed = false; do { std::pair Edge = toSplit.pop_back_val(); - SplitCriticalEdge(Edge.first, Edge.second, - CriticalEdgeSplittingOptions(DT, LI)); + Changed |= SplitCriticalEdge(Edge.first, Edge.second, + CriticalEdgeSplittingOptions(DT, LI, MSSAU)) != + nullptr; } while (!toSplit.empty()); - if (MD) MD->invalidateCachedPredecessors(); - InvalidBlockRPONumbers = true; - return true; + if (Changed) { + if (MD) + MD->invalidateCachedPredecessors(); + InvalidBlockRPONumbers = true; + } + return Changed; } /// Executes one iteration of GVN @@ -2633,13 +2803,12 @@ void GVN::addDeadBlock(BasicBlock *BB) { // First, split the critical edges. This might also create additional blocks // to preserve LoopSimplify form and adjust edges accordingly. - SmallVector Preds(pred_begin(B), pred_end(B)); + SmallVector Preds(predecessors(B)); for (BasicBlock *P : Preds) { if (!DeadBlocks.count(P)) continue; - if (llvm::any_of(successors(P), - [B](BasicBlock *Succ) { return Succ == B; }) && + if (llvm::is_contained(successors(P), B) && isCriticalEdge(P->getTerminator(), B)) { if (BasicBlock *S = splitCriticalEdges(P, B)) DeadBlocks.insert(P = S); @@ -2724,6 +2893,7 @@ public: auto *LIWP = getAnalysisIfAvailable(); + auto *MSSAWP = getAnalysisIfAvailable(); return Impl.runImpl( F, getAnalysis().getAssumptionCache(F), getAnalysis().getDomTree(), @@ -2733,7 +2903,8 @@ public: ? &getAnalysis().getMemDep() : nullptr, LIWP ? &LIWP->getLoopInfo() : nullptr, - &getAnalysis().getORE()); + &getAnalysis().getORE(), + MSSAWP ? &MSSAWP->getMSSA() : nullptr); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -2744,12 +2915,12 @@ public: if (Impl.isMemDepEnabled()) AU.addRequired(); AU.addRequired(); - AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addPreserved(); AU.addRequired(); + AU.addPreserved(); } private: diff --git a/llvm/lib/Transforms/Scalar/GVNHoist.cpp b/llvm/lib/Transforms/Scalar/GVNHoist.cpp index 9c4cdf2feb56..8d0bd5674964 100644 --- a/llvm/lib/Transforms/Scalar/GVNHoist.cpp +++ b/llvm/lib/Transforms/Scalar/GVNHoist.cpp @@ -149,8 +149,8 @@ struct CHIArg { // The instruction (VN) which uses the values flowing out of CHI. Instruction *I; - bool operator==(const CHIArg &A) { return VN == A.VN; } - bool operator!=(const CHIArg &A) { return !(*this == A); } + bool operator==(const CHIArg &A) const { return VN == A.VN; } + bool operator!=(const CHIArg &A) const { return !(*this == A); } }; using CHIIt = SmallVectorImpl::iterator; @@ -242,11 +242,14 @@ public: }; static void combineKnownMetadata(Instruction *ReplInst, Instruction *I) { - static const unsigned KnownIDs[] = { - LLVMContext::MD_tbaa, LLVMContext::MD_alias_scope, - LLVMContext::MD_noalias, LLVMContext::MD_range, - LLVMContext::MD_fpmath, LLVMContext::MD_invariant_load, - LLVMContext::MD_invariant_group, LLVMContext::MD_access_group}; + static const unsigned KnownIDs[] = {LLVMContext::MD_tbaa, + LLVMContext::MD_alias_scope, + LLVMContext::MD_noalias, + LLVMContext::MD_range, + LLVMContext::MD_fpmath, + LLVMContext::MD_invariant_load, + LLVMContext::MD_invariant_group, + LLVMContext::MD_access_group}; combineMetadata(ReplInst, I, KnownIDs, true); } @@ -260,43 +263,7 @@ public: : DT(DT), PDT(PDT), AA(AA), MD(MD), MSSA(MSSA), MSSAUpdater(std::make_unique(MSSA)) {} - bool run(Function &F) { - NumFuncArgs = F.arg_size(); - VN.setDomTree(DT); - VN.setAliasAnalysis(AA); - VN.setMemDep(MD); - bool Res = false; - // Perform DFS Numbering of instructions. - unsigned BBI = 0; - for (const BasicBlock *BB : depth_first(&F.getEntryBlock())) { - DFSNumber[BB] = ++BBI; - unsigned I = 0; - for (auto &Inst : *BB) - DFSNumber[&Inst] = ++I; - } - - int ChainLength = 0; - - // FIXME: use lazy evaluation of VN to avoid the fix-point computation. - while (true) { - if (MaxChainLength != -1 && ++ChainLength >= MaxChainLength) - return Res; - - auto HoistStat = hoistExpressions(F); - if (HoistStat.first + HoistStat.second == 0) - return Res; - - if (HoistStat.second > 0) - // To address a limitation of the current GVN, we need to rerun the - // hoisting after we hoisted loads or stores in order to be able to - // hoist all scalars dependent on the hoisted ld/st. - VN.clear(); - - Res = true; - } - - return Res; - } + bool run(Function &F); // Copied from NewGVN.cpp // This function provides global ranking of operations so that we can place @@ -304,27 +271,7 @@ public: // for a complete ordering, as constants all have the same rank. However, // generally, we will simplify an operation with all constants so that it // doesn't matter what order they appear in. - unsigned int rank(const Value *V) const { - // Prefer constants to undef to anything else - // Undef is a constant, have to check it first. - // Prefer smaller constants to constantexprs - if (isa(V)) - return 2; - if (isa(V)) - return 1; - if (isa(V)) - return 0; - else if (auto *A = dyn_cast(V)) - return 3 + A->getArgNo(); - - // Need to shift the instruction DFS by number of arguments + 3 to account - // for the constant and argument ranking above. - auto Result = DFSNumber.lookup(V); - if (Result > 0) - return 4 + NumFuncArgs + Result; - // Unreachable or something else, just return a really large number. - return ~0; - } + unsigned int rank(const Value *V) const; private: GVN::ValueTable VN; @@ -344,33 +291,7 @@ private: enum InsKind { Unknown, Scalar, Load, Store }; // Return true when there are exception handling in BB. - bool hasEH(const BasicBlock *BB) { - auto It = BBSideEffects.find(BB); - if (It != BBSideEffects.end()) - return It->second; - - if (BB->isEHPad() || BB->hasAddressTaken()) { - BBSideEffects[BB] = true; - return true; - } - - if (BB->getTerminator()->mayThrow()) { - BBSideEffects[BB] = true; - return true; - } - - BBSideEffects[BB] = false; - return false; - } - - // Return true when a successor of BB dominates A. - bool successorDominate(const BasicBlock *BB, const BasicBlock *A) { - for (const BasicBlock *Succ : successors(BB)) - if (DT->dominates(Succ, A)) - return true; - - return false; - } + bool hasEH(const BasicBlock *BB); // Return true when I1 appears before I2 in the instructions of BB. bool firstInBB(const Instruction *I1, const Instruction *I2) { @@ -383,57 +304,10 @@ private: // Return true when there are memory uses of Def in BB. bool hasMemoryUse(const Instruction *NewPt, MemoryDef *Def, - const BasicBlock *BB) { - const MemorySSA::AccessList *Acc = MSSA->getBlockAccesses(BB); - if (!Acc) - return false; - - Instruction *OldPt = Def->getMemoryInst(); - const BasicBlock *OldBB = OldPt->getParent(); - const BasicBlock *NewBB = NewPt->getParent(); - bool ReachedNewPt = false; - - for (const MemoryAccess &MA : *Acc) - if (const MemoryUse *MU = dyn_cast(&MA)) { - Instruction *Insn = MU->getMemoryInst(); - - // Do not check whether MU aliases Def when MU occurs after OldPt. - if (BB == OldBB && firstInBB(OldPt, Insn)) - break; - - // Do not check whether MU aliases Def when MU occurs before NewPt. - if (BB == NewBB) { - if (!ReachedNewPt) { - if (firstInBB(Insn, NewPt)) - continue; - ReachedNewPt = true; - } - } - if (MemorySSAUtil::defClobbersUseOrDef(Def, MU, *AA)) - return true; - } - - return false; - } + const BasicBlock *BB); bool hasEHhelper(const BasicBlock *BB, const BasicBlock *SrcBB, - int &NBBsOnAllPaths) { - // Stop walk once the limit is reached. - if (NBBsOnAllPaths == 0) - return true; - - // Impossible to hoist with exceptions on the path. - if (hasEH(BB)) - return true; - - // No such instruction after HoistBarrier in a basic block was - // selected for hoisting so instructions selected within basic block with - // a hoist barrier can be hoisted. - if ((BB != SrcBB) && HoistBarrier.count(BB)) - return true; - - return false; - } + int &NBBsOnAllPaths); // Return true when there are exception handling or loads of memory Def // between Def and NewPt. This function is only called for stores: Def is @@ -443,118 +317,19 @@ private: // return true when the counter NBBsOnAllPaths reaces 0, except when it is // initialized to -1 which is unlimited. bool hasEHOrLoadsOnPath(const Instruction *NewPt, MemoryDef *Def, - int &NBBsOnAllPaths) { - const BasicBlock *NewBB = NewPt->getParent(); - const BasicBlock *OldBB = Def->getBlock(); - assert(DT->dominates(NewBB, OldBB) && "invalid path"); - assert(DT->dominates(Def->getDefiningAccess()->getBlock(), NewBB) && - "def does not dominate new hoisting point"); - - // Walk all basic blocks reachable in depth-first iteration on the inverse - // CFG from OldBB to NewBB. These blocks are all the blocks that may be - // executed between the execution of NewBB and OldBB. Hoisting an expression - // from OldBB into NewBB has to be safe on all execution paths. - for (auto I = idf_begin(OldBB), E = idf_end(OldBB); I != E;) { - const BasicBlock *BB = *I; - if (BB == NewBB) { - // Stop traversal when reaching HoistPt. - I.skipChildren(); - continue; - } - - if (hasEHhelper(BB, OldBB, NBBsOnAllPaths)) - return true; - - // Check that we do not move a store past loads. - if (hasMemoryUse(NewPt, Def, BB)) - return true; - - // -1 is unlimited number of blocks on all paths. - if (NBBsOnAllPaths != -1) - --NBBsOnAllPaths; - - ++I; - } - - return false; - } + int &NBBsOnAllPaths); // Return true when there are exception handling between HoistPt and BB. // Decrement by 1 NBBsOnAllPaths for each block between HoistPt and BB, and // return true when the counter NBBsOnAllPaths reaches 0, except when it is // initialized to -1 which is unlimited. bool hasEHOnPath(const BasicBlock *HoistPt, const BasicBlock *SrcBB, - int &NBBsOnAllPaths) { - assert(DT->dominates(HoistPt, SrcBB) && "Invalid path"); - - // Walk all basic blocks reachable in depth-first iteration on - // the inverse CFG from BBInsn to NewHoistPt. These blocks are all the - // blocks that may be executed between the execution of NewHoistPt and - // BBInsn. Hoisting an expression from BBInsn into NewHoistPt has to be safe - // on all execution paths. - for (auto I = idf_begin(SrcBB), E = idf_end(SrcBB); I != E;) { - const BasicBlock *BB = *I; - if (BB == HoistPt) { - // Stop traversal when reaching NewHoistPt. - I.skipChildren(); - continue; - } - - if (hasEHhelper(BB, SrcBB, NBBsOnAllPaths)) - return true; - - // -1 is unlimited number of blocks on all paths. - if (NBBsOnAllPaths != -1) - --NBBsOnAllPaths; - - ++I; - } - - return false; - } + int &NBBsOnAllPaths); // Return true when it is safe to hoist a memory load or store U from OldPt // to NewPt. bool safeToHoistLdSt(const Instruction *NewPt, const Instruction *OldPt, - MemoryUseOrDef *U, InsKind K, int &NBBsOnAllPaths) { - // In place hoisting is safe. - if (NewPt == OldPt) - return true; - - const BasicBlock *NewBB = NewPt->getParent(); - const BasicBlock *OldBB = OldPt->getParent(); - const BasicBlock *UBB = U->getBlock(); - - // Check for dependences on the Memory SSA. - MemoryAccess *D = U->getDefiningAccess(); - BasicBlock *DBB = D->getBlock(); - if (DT->properlyDominates(NewBB, DBB)) - // Cannot move the load or store to NewBB above its definition in DBB. - return false; - - if (NewBB == DBB && !MSSA->isLiveOnEntryDef(D)) - if (auto *UD = dyn_cast(D)) - if (!firstInBB(UD->getMemoryInst(), NewPt)) - // Cannot move the load or store to NewPt above its definition in D. - return false; - - // Check for unsafe hoistings due to side effects. - if (K == InsKind::Store) { - if (hasEHOrLoadsOnPath(NewPt, cast(U), NBBsOnAllPaths)) - return false; - } else if (hasEHOnPath(NewBB, OldBB, NBBsOnAllPaths)) - return false; - - if (UBB == NewBB) { - if (DT->properlyDominates(DBB, NewBB)) - return true; - assert(UBB == DBB); - assert(MSSA->locallyDominates(D, U)); - } - - // No side effects: it is safe to hoist. - return true; - } + MemoryUseOrDef *U, InsKind K, int &NBBsOnAllPaths); // Return true when it is safe to hoist scalar instructions from all blocks in // WL to HoistBB. @@ -577,92 +352,21 @@ private: // Returns the edge via which an instruction in BB will get the values from. // Returns true when the values are flowing out to each edge. - bool valueAnticipable(CHIArgs C, Instruction *TI) const { - if (TI->getNumSuccessors() > (unsigned)size(C)) - return false; // Not enough args in this CHI. - - for (auto CHI : C) { - BasicBlock *Dest = CHI.Dest; - // Find if all the edges have values flowing out of BB. - bool Found = llvm::any_of( - successors(TI), [Dest](const BasicBlock *BB) { return BB == Dest; }); - if (!Found) - return false; - } - return true; - } + bool valueAnticipable(CHIArgs C, Instruction *TI) const; // Check if it is safe to hoist values tracked by CHI in the range // [Begin, End) and accumulate them in Safe. void checkSafety(CHIArgs C, BasicBlock *BB, InsKind K, - SmallVectorImpl &Safe) { - int NumBBsOnAllPaths = MaxNumberOfBBSInPath; - for (auto CHI : C) { - Instruction *Insn = CHI.I; - if (!Insn) // No instruction was inserted in this CHI. - continue; - if (K == InsKind::Scalar) { - if (safeToHoistScalar(BB, Insn->getParent(), NumBBsOnAllPaths)) - Safe.push_back(CHI); - } else { - MemoryUseOrDef *UD = MSSA->getMemoryAccess(Insn); - if (safeToHoistLdSt(BB->getTerminator(), Insn, UD, K, NumBBsOnAllPaths)) - Safe.push_back(CHI); - } - } - } + SmallVectorImpl &Safe); using RenameStackType = DenseMap>; // Push all the VNs corresponding to BB into RenameStack. void fillRenameStack(BasicBlock *BB, InValuesType &ValueBBs, - RenameStackType &RenameStack) { - auto it1 = ValueBBs.find(BB); - if (it1 != ValueBBs.end()) { - // Iterate in reverse order to keep lower ranked values on the top. - for (std::pair &VI : reverse(it1->second)) { - // Get the value of instruction I - LLVM_DEBUG(dbgs() << "\nPushing on stack: " << *VI.second); - RenameStack[VI.first].push_back(VI.second); - } - } - } + RenameStackType &RenameStack); void fillChiArgs(BasicBlock *BB, OutValuesType &CHIBBs, - RenameStackType &RenameStack) { - // For each *predecessor* (because Post-DOM) of BB check if it has a CHI - for (auto Pred : predecessors(BB)) { - auto P = CHIBBs.find(Pred); - if (P == CHIBBs.end()) { - continue; - } - LLVM_DEBUG(dbgs() << "\nLooking at CHIs in: " << Pred->getName();); - // A CHI is found (BB -> Pred is an edge in the CFG) - // Pop the stack until Top(V) = Ve. - auto &VCHI = P->second; - for (auto It = VCHI.begin(), E = VCHI.end(); It != E;) { - CHIArg &C = *It; - if (!C.Dest) { - auto si = RenameStack.find(C.VN); - // The Basic Block where CHI is must dominate the value we want to - // track in a CHI. In the PDom walk, there can be values in the - // stack which are not control dependent e.g., nested loop. - if (si != RenameStack.end() && si->second.size() && - DT->properlyDominates(Pred, si->second.back()->getParent())) { - C.Dest = BB; // Assign the edge - C.I = si->second.pop_back_val(); // Assign the argument - LLVM_DEBUG(dbgs() - << "\nCHI Inserted in BB: " << C.Dest->getName() << *C.I - << ", VN: " << C.VN.first << ", " << C.VN.second); - } - // Move to next CHI of a different value - It = std::find_if(It, VCHI.end(), - [It](CHIArg &A) { return A != *It; }); - } else - ++It; - } - } - } + RenameStackType &RenameStack); // Walk the post-dominator tree top-down and use a stack for each value to // store the last value you see. When you hit a CHI from a given edge, the @@ -692,48 +396,7 @@ private: // they form a list of anticipable values. OutValues contains CHIs // corresponding to each basic block. void findHoistableCandidates(OutValuesType &CHIBBs, InsKind K, - HoistingPointList &HPL) { - auto cmpVN = [](const CHIArg &A, const CHIArg &B) { return A.VN < B.VN; }; - - // CHIArgs now have the outgoing values, so check for anticipability and - // accumulate hoistable candidates in HPL. - for (std::pair> &A : CHIBBs) { - BasicBlock *BB = A.first; - SmallVectorImpl &CHIs = A.second; - // Vector of PHIs contains PHIs for different instructions. - // Sort the args according to their VNs, such that identical - // instructions are together. - llvm::stable_sort(CHIs, cmpVN); - auto TI = BB->getTerminator(); - auto B = CHIs.begin(); - // [PreIt, PHIIt) form a range of CHIs which have identical VNs. - auto PHIIt = std::find_if(CHIs.begin(), CHIs.end(), - [B](CHIArg &A) { return A != *B; }); - auto PrevIt = CHIs.begin(); - while (PrevIt != PHIIt) { - // Collect values which satisfy safety checks. - SmallVector Safe; - // We check for safety first because there might be multiple values in - // the same path, some of which are not safe to be hoisted, but overall - // each edge has at least one value which can be hoisted, making the - // value anticipable along that path. - checkSafety(make_range(PrevIt, PHIIt), BB, K, Safe); - - // List of safe values should be anticipable at TI. - if (valueAnticipable(make_range(Safe.begin(), Safe.end()), TI)) { - HPL.push_back({BB, SmallVecInsn()}); - SmallVecInsn &V = HPL.back().second; - for (auto B : Safe) - V.push_back(B.I); - } - - // Check other VNs - PrevIt = PHIIt; - PHIIt = std::find_if(PrevIt, CHIs.end(), - [PrevIt](CHIArg &A) { return A != *PrevIt; }); - } - } - } + HoistingPointList &HPL); // Compute insertion points for each values which can be fully anticipated at // a dominator. HPL contains all such values. @@ -791,14 +454,14 @@ private: } // Insert empty CHI node for this VN. This is used to factor out // basic blocks where the ANTIC can potentially change. - for (auto IDFB : IDFBlocks) { + CHIArg EmptyChi = {VN, nullptr, nullptr}; + for (auto *IDFBB : IDFBlocks) { for (unsigned i = 0; i < V.size(); ++i) { - CHIArg C = {VN, nullptr, nullptr}; - // Ignore spurious PDFs. - if (DT->properlyDominates(IDFB, V[i]->getParent())) { - OutValue[IDFB].push_back(C); - LLVM_DEBUG(dbgs() << "\nInsertion a CHI for BB: " << IDFB->getName() - << ", for Insn: " << *V[i]); + // Ignore spurious PDFs. + if (DT->properlyDominates(IDFBB, V[i]->getParent())) { + OutValue[IDFBB].push_back(EmptyChi); + LLVM_DEBUG(dbgs() << "\nInserting a CHI for BB: " + << IDFBB->getName() << ", for Insn: " << *V[i]); } } } @@ -816,364 +479,754 @@ private: // a load without hoisting its access function. So before hoisting any // expression, make sure that all its operands are available at insert point. bool allOperandsAvailable(const Instruction *I, - const BasicBlock *HoistPt) const { - for (const Use &Op : I->operands()) - if (const auto *Inst = dyn_cast(&Op)) - if (!DT->dominates(Inst->getParent(), HoistPt)) - return false; - - return true; - } + const BasicBlock *HoistPt) const; // Same as allOperandsAvailable with recursive check for GEP operands. bool allGepOperandsAvailable(const Instruction *I, - const BasicBlock *HoistPt) const { - for (const Use &Op : I->operands()) - if (const auto *Inst = dyn_cast(&Op)) - if (!DT->dominates(Inst->getParent(), HoistPt)) { - if (const GetElementPtrInst *GepOp = - dyn_cast(Inst)) { - if (!allGepOperandsAvailable(GepOp, HoistPt)) - return false; - // Gep is available if all operands of GepOp are available. - } else { - // Gep is not available if it has operands other than GEPs that are - // defined in blocks not dominating HoistPt. - return false; - } - } - return true; - } + const BasicBlock *HoistPt) const; // Make all operands of the GEP available. void makeGepsAvailable(Instruction *Repl, BasicBlock *HoistPt, const SmallVecInsn &InstructionsToHoist, - Instruction *Gep) const { - assert(allGepOperandsAvailable(Gep, HoistPt) && - "GEP operands not available"); - - Instruction *ClonedGep = Gep->clone(); - for (unsigned i = 0, e = Gep->getNumOperands(); i != e; ++i) - if (Instruction *Op = dyn_cast(Gep->getOperand(i))) { - // Check whether the operand is already available. - if (DT->dominates(Op->getParent(), HoistPt)) - continue; + Instruction *Gep) const; + + void updateAlignment(Instruction *I, Instruction *Repl); + + // Remove all the instructions in Candidates and replace their usage with + // Repl. Returns the number of instructions removed. + unsigned rauw(const SmallVecInsn &Candidates, Instruction *Repl, + MemoryUseOrDef *NewMemAcc); + + // Replace all Memory PHI usage with NewMemAcc. + void raMPHIuw(MemoryUseOrDef *NewMemAcc); + + // Remove all other instructions and replace them with Repl. + unsigned removeAndReplace(const SmallVecInsn &Candidates, Instruction *Repl, + BasicBlock *DestBB, bool MoveAccess); + + // In the case Repl is a load or a store, we make all their GEPs + // available: GEPs are not hoisted by default to avoid the address + // computations to be hoisted without the associated load or store. + bool makeGepOperandsAvailable(Instruction *Repl, BasicBlock *HoistPt, + const SmallVecInsn &InstructionsToHoist) const; + + std::pair hoist(HoistingPointList &HPL); + + // Hoist all expressions. Returns Number of scalars hoisted + // and number of non-scalars hoisted. + std::pair hoistExpressions(Function &F); +}; + +class GVNHoistLegacyPass : public FunctionPass { +public: + static char ID; + + GVNHoistLegacyPass() : FunctionPass(ID) { + initializeGVNHoistLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + if (skipFunction(F)) + return false; + auto &DT = getAnalysis().getDomTree(); + auto &PDT = getAnalysis().getPostDomTree(); + auto &AA = getAnalysis().getAAResults(); + auto &MD = getAnalysis().getMemDep(); + auto &MSSA = getAnalysis().getMSSA(); + + GVNHoist G(&DT, &PDT, &AA, &MD, &MSSA); + return G.run(F); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + AU.addPreserved(); + AU.addPreserved(); + AU.addPreserved(); + } +}; + +bool GVNHoist::run(Function &F) { + NumFuncArgs = F.arg_size(); + VN.setDomTree(DT); + VN.setAliasAnalysis(AA); + VN.setMemDep(MD); + bool Res = false; + // Perform DFS Numbering of instructions. + unsigned BBI = 0; + for (const BasicBlock *BB : depth_first(&F.getEntryBlock())) { + DFSNumber[BB] = ++BBI; + unsigned I = 0; + for (auto &Inst : *BB) + DFSNumber[&Inst] = ++I; + } + + int ChainLength = 0; + + // FIXME: use lazy evaluation of VN to avoid the fix-point computation. + while (true) { + if (MaxChainLength != -1 && ++ChainLength >= MaxChainLength) + return Res; + + auto HoistStat = hoistExpressions(F); + if (HoistStat.first + HoistStat.second == 0) + return Res; + + if (HoistStat.second > 0) + // To address a limitation of the current GVN, we need to rerun the + // hoisting after we hoisted loads or stores in order to be able to + // hoist all scalars dependent on the hoisted ld/st. + VN.clear(); + + Res = true; + } + + return Res; +} + +unsigned int GVNHoist::rank(const Value *V) const { + // Prefer constants to undef to anything else + // Undef is a constant, have to check it first. + // Prefer smaller constants to constantexprs + if (isa(V)) + return 2; + if (isa(V)) + return 1; + if (isa(V)) + return 0; + else if (auto *A = dyn_cast(V)) + return 3 + A->getArgNo(); + + // Need to shift the instruction DFS by number of arguments + 3 to account + // for the constant and argument ranking above. + auto Result = DFSNumber.lookup(V); + if (Result > 0) + return 4 + NumFuncArgs + Result; + // Unreachable or something else, just return a really large number. + return ~0; +} + +bool GVNHoist::hasEH(const BasicBlock *BB) { + auto It = BBSideEffects.find(BB); + if (It != BBSideEffects.end()) + return It->second; + + if (BB->isEHPad() || BB->hasAddressTaken()) { + BBSideEffects[BB] = true; + return true; + } + + if (BB->getTerminator()->mayThrow()) { + BBSideEffects[BB] = true; + return true; + } + + BBSideEffects[BB] = false; + return false; +} + +bool GVNHoist::hasMemoryUse(const Instruction *NewPt, MemoryDef *Def, + const BasicBlock *BB) { + const MemorySSA::AccessList *Acc = MSSA->getBlockAccesses(BB); + if (!Acc) + return false; + + Instruction *OldPt = Def->getMemoryInst(); + const BasicBlock *OldBB = OldPt->getParent(); + const BasicBlock *NewBB = NewPt->getParent(); + bool ReachedNewPt = false; - // As a GEP can refer to other GEPs, recursively make all the operands - // of this GEP available at HoistPt. - if (GetElementPtrInst *GepOp = dyn_cast(Op)) - makeGepsAvailable(ClonedGep, HoistPt, InstructionsToHoist, GepOp); + for (const MemoryAccess &MA : *Acc) + if (const MemoryUse *MU = dyn_cast(&MA)) { + Instruction *Insn = MU->getMemoryInst(); + + // Do not check whether MU aliases Def when MU occurs after OldPt. + if (BB == OldBB && firstInBB(OldPt, Insn)) + break; + + // Do not check whether MU aliases Def when MU occurs before NewPt. + if (BB == NewBB) { + if (!ReachedNewPt) { + if (firstInBB(Insn, NewPt)) + continue; + ReachedNewPt = true; + } } + if (MemorySSAUtil::defClobbersUseOrDef(Def, MU, *AA)) + return true; + } + + return false; +} + +bool GVNHoist::hasEHhelper(const BasicBlock *BB, const BasicBlock *SrcBB, + int &NBBsOnAllPaths) { + // Stop walk once the limit is reached. + if (NBBsOnAllPaths == 0) + return true; + + // Impossible to hoist with exceptions on the path. + if (hasEH(BB)) + return true; + + // No such instruction after HoistBarrier in a basic block was + // selected for hoisting so instructions selected within basic block with + // a hoist barrier can be hoisted. + if ((BB != SrcBB) && HoistBarrier.count(BB)) + return true; + + return false; +} - // Copy Gep and replace its uses in Repl with ClonedGep. - ClonedGep->insertBefore(HoistPt->getTerminator()); - - // Conservatively discard any optimization hints, they may differ on the - // other paths. - ClonedGep->dropUnknownNonDebugMetadata(); - - // If we have optimization hints which agree with each other along different - // paths, preserve them. - for (const Instruction *OtherInst : InstructionsToHoist) { - const GetElementPtrInst *OtherGep; - if (auto *OtherLd = dyn_cast(OtherInst)) - OtherGep = cast(OtherLd->getPointerOperand()); - else - OtherGep = cast( - cast(OtherInst)->getPointerOperand()); - ClonedGep->andIRFlags(OtherGep); +bool GVNHoist::hasEHOrLoadsOnPath(const Instruction *NewPt, MemoryDef *Def, + int &NBBsOnAllPaths) { + const BasicBlock *NewBB = NewPt->getParent(); + const BasicBlock *OldBB = Def->getBlock(); + assert(DT->dominates(NewBB, OldBB) && "invalid path"); + assert(DT->dominates(Def->getDefiningAccess()->getBlock(), NewBB) && + "def does not dominate new hoisting point"); + + // Walk all basic blocks reachable in depth-first iteration on the inverse + // CFG from OldBB to NewBB. These blocks are all the blocks that may be + // executed between the execution of NewBB and OldBB. Hoisting an expression + // from OldBB into NewBB has to be safe on all execution paths. + for (auto I = idf_begin(OldBB), E = idf_end(OldBB); I != E;) { + const BasicBlock *BB = *I; + if (BB == NewBB) { + // Stop traversal when reaching HoistPt. + I.skipChildren(); + continue; } - // Replace uses of Gep with ClonedGep in Repl. - Repl->replaceUsesOfWith(Gep, ClonedGep); + if (hasEHhelper(BB, OldBB, NBBsOnAllPaths)) + return true; + + // Check that we do not move a store past loads. + if (hasMemoryUse(NewPt, Def, BB)) + return true; + + // -1 is unlimited number of blocks on all paths. + if (NBBsOnAllPaths != -1) + --NBBsOnAllPaths; + + ++I; } - void updateAlignment(Instruction *I, Instruction *Repl) { - if (auto *ReplacementLoad = dyn_cast(Repl)) { - ReplacementLoad->setAlignment( - std::min(ReplacementLoad->getAlign(), cast(I)->getAlign())); - ++NumLoadsRemoved; - } else if (auto *ReplacementStore = dyn_cast(Repl)) { - ReplacementStore->setAlignment(std::min(ReplacementStore->getAlign(), - cast(I)->getAlign())); - ++NumStoresRemoved; - } else if (auto *ReplacementAlloca = dyn_cast(Repl)) { - ReplacementAlloca->setAlignment(std::max( - ReplacementAlloca->getAlign(), cast(I)->getAlign())); - } else if (isa(Repl)) { - ++NumCallsRemoved; + return false; +} + +bool GVNHoist::hasEHOnPath(const BasicBlock *HoistPt, const BasicBlock *SrcBB, + int &NBBsOnAllPaths) { + assert(DT->dominates(HoistPt, SrcBB) && "Invalid path"); + + // Walk all basic blocks reachable in depth-first iteration on + // the inverse CFG from BBInsn to NewHoistPt. These blocks are all the + // blocks that may be executed between the execution of NewHoistPt and + // BBInsn. Hoisting an expression from BBInsn into NewHoistPt has to be safe + // on all execution paths. + for (auto I = idf_begin(SrcBB), E = idf_end(SrcBB); I != E;) { + const BasicBlock *BB = *I; + if (BB == HoistPt) { + // Stop traversal when reaching NewHoistPt. + I.skipChildren(); + continue; } + + if (hasEHhelper(BB, SrcBB, NBBsOnAllPaths)) + return true; + + // -1 is unlimited number of blocks on all paths. + if (NBBsOnAllPaths != -1) + --NBBsOnAllPaths; + + ++I; } - // Remove all the instructions in Candidates and replace their usage with Repl. - // Returns the number of instructions removed. - unsigned rauw(const SmallVecInsn &Candidates, Instruction *Repl, - MemoryUseOrDef *NewMemAcc) { - unsigned NR = 0; - for (Instruction *I : Candidates) { - if (I != Repl) { - ++NR; - updateAlignment(I, Repl); - if (NewMemAcc) { - // Update the uses of the old MSSA access with NewMemAcc. - MemoryAccess *OldMA = MSSA->getMemoryAccess(I); - OldMA->replaceAllUsesWith(NewMemAcc); - MSSAUpdater->removeMemoryAccess(OldMA); - } + return false; +} - Repl->andIRFlags(I); - combineKnownMetadata(Repl, I); - I->replaceAllUsesWith(Repl); - // Also invalidate the Alias Analysis cache. - MD->removeInstruction(I); - I->eraseFromParent(); - } +bool GVNHoist::safeToHoistLdSt(const Instruction *NewPt, + const Instruction *OldPt, MemoryUseOrDef *U, + GVNHoist::InsKind K, int &NBBsOnAllPaths) { + // In place hoisting is safe. + if (NewPt == OldPt) + return true; + + const BasicBlock *NewBB = NewPt->getParent(); + const BasicBlock *OldBB = OldPt->getParent(); + const BasicBlock *UBB = U->getBlock(); + + // Check for dependences on the Memory SSA. + MemoryAccess *D = U->getDefiningAccess(); + BasicBlock *DBB = D->getBlock(); + if (DT->properlyDominates(NewBB, DBB)) + // Cannot move the load or store to NewBB above its definition in DBB. + return false; + + if (NewBB == DBB && !MSSA->isLiveOnEntryDef(D)) + if (auto *UD = dyn_cast(D)) + if (!firstInBB(UD->getMemoryInst(), NewPt)) + // Cannot move the load or store to NewPt above its definition in D. + return false; + + // Check for unsafe hoistings due to side effects. + if (K == InsKind::Store) { + if (hasEHOrLoadsOnPath(NewPt, cast(U), NBBsOnAllPaths)) + return false; + } else if (hasEHOnPath(NewBB, OldBB, NBBsOnAllPaths)) + return false; + + if (UBB == NewBB) { + if (DT->properlyDominates(DBB, NewBB)) + return true; + assert(UBB == DBB); + assert(MSSA->locallyDominates(D, U)); + } + + // No side effects: it is safe to hoist. + return true; +} + +bool GVNHoist::valueAnticipable(CHIArgs C, Instruction *TI) const { + if (TI->getNumSuccessors() > (unsigned)size(C)) + return false; // Not enough args in this CHI. + + for (auto CHI : C) { + // Find if all the edges have values flowing out of BB. + if (!llvm::is_contained(successors(TI), CHI.Dest)) + return false; + } + return true; +} + +void GVNHoist::checkSafety(CHIArgs C, BasicBlock *BB, GVNHoist::InsKind K, + SmallVectorImpl &Safe) { + int NumBBsOnAllPaths = MaxNumberOfBBSInPath; + for (auto CHI : C) { + Instruction *Insn = CHI.I; + if (!Insn) // No instruction was inserted in this CHI. + continue; + if (K == InsKind::Scalar) { + if (safeToHoistScalar(BB, Insn->getParent(), NumBBsOnAllPaths)) + Safe.push_back(CHI); + } else { + auto *T = BB->getTerminator(); + if (MemoryUseOrDef *UD = MSSA->getMemoryAccess(Insn)) + if (safeToHoistLdSt(T, Insn, UD, K, NumBBsOnAllPaths)) + Safe.push_back(CHI); } - return NR; } +} - // Replace all Memory PHI usage with NewMemAcc. - void raMPHIuw(MemoryUseOrDef *NewMemAcc) { - SmallPtrSet UsePhis; - for (User *U : NewMemAcc->users()) - if (MemoryPhi *Phi = dyn_cast(U)) - UsePhis.insert(Phi); - - for (MemoryPhi *Phi : UsePhis) { - auto In = Phi->incoming_values(); - if (llvm::all_of(In, [&](Use &U) { return U == NewMemAcc; })) { - Phi->replaceAllUsesWith(NewMemAcc); - MSSAUpdater->removeMemoryAccess(Phi); - } +void GVNHoist::fillRenameStack(BasicBlock *BB, InValuesType &ValueBBs, + GVNHoist::RenameStackType &RenameStack) { + auto it1 = ValueBBs.find(BB); + if (it1 != ValueBBs.end()) { + // Iterate in reverse order to keep lower ranked values on the top. + for (std::pair &VI : reverse(it1->second)) { + // Get the value of instruction I + LLVM_DEBUG(dbgs() << "\nPushing on stack: " << *VI.second); + RenameStack[VI.first].push_back(VI.second); } } +} - // Remove all other instructions and replace them with Repl. - unsigned removeAndReplace(const SmallVecInsn &Candidates, Instruction *Repl, - BasicBlock *DestBB, bool MoveAccess) { - MemoryUseOrDef *NewMemAcc = MSSA->getMemoryAccess(Repl); - if (MoveAccess && NewMemAcc) { - // The definition of this ld/st will not change: ld/st hoisting is - // legal when the ld/st is not moved past its current definition. - MSSAUpdater->moveToPlace(NewMemAcc, DestBB, - MemorySSA::BeforeTerminator); +void GVNHoist::fillChiArgs(BasicBlock *BB, OutValuesType &CHIBBs, + GVNHoist::RenameStackType &RenameStack) { + // For each *predecessor* (because Post-DOM) of BB check if it has a CHI + for (auto Pred : predecessors(BB)) { + auto P = CHIBBs.find(Pred); + if (P == CHIBBs.end()) { + continue; } + LLVM_DEBUG(dbgs() << "\nLooking at CHIs in: " << Pred->getName();); + // A CHI is found (BB -> Pred is an edge in the CFG) + // Pop the stack until Top(V) = Ve. + auto &VCHI = P->second; + for (auto It = VCHI.begin(), E = VCHI.end(); It != E;) { + CHIArg &C = *It; + if (!C.Dest) { + auto si = RenameStack.find(C.VN); + // The Basic Block where CHI is must dominate the value we want to + // track in a CHI. In the PDom walk, there can be values in the + // stack which are not control dependent e.g., nested loop. + if (si != RenameStack.end() && si->second.size() && + DT->properlyDominates(Pred, si->second.back()->getParent())) { + C.Dest = BB; // Assign the edge + C.I = si->second.pop_back_val(); // Assign the argument + LLVM_DEBUG(dbgs() + << "\nCHI Inserted in BB: " << C.Dest->getName() << *C.I + << ", VN: " << C.VN.first << ", " << C.VN.second); + } + // Move to next CHI of a different value + It = std::find_if(It, VCHI.end(), [It](CHIArg &A) { return A != *It; }); + } else + ++It; + } + } +} - // Replace all other instructions with Repl with memory access NewMemAcc. - unsigned NR = rauw(Candidates, Repl, NewMemAcc); +void GVNHoist::findHoistableCandidates(OutValuesType &CHIBBs, + GVNHoist::InsKind K, + HoistingPointList &HPL) { + auto cmpVN = [](const CHIArg &A, const CHIArg &B) { return A.VN < B.VN; }; + + // CHIArgs now have the outgoing values, so check for anticipability and + // accumulate hoistable candidates in HPL. + for (std::pair> &A : CHIBBs) { + BasicBlock *BB = A.first; + SmallVectorImpl &CHIs = A.second; + // Vector of PHIs contains PHIs for different instructions. + // Sort the args according to their VNs, such that identical + // instructions are together. + llvm::stable_sort(CHIs, cmpVN); + auto TI = BB->getTerminator(); + auto B = CHIs.begin(); + // [PreIt, PHIIt) form a range of CHIs which have identical VNs. + auto PHIIt = llvm::find_if(CHIs, [B](CHIArg &A) { return A != *B; }); + auto PrevIt = CHIs.begin(); + while (PrevIt != PHIIt) { + // Collect values which satisfy safety checks. + SmallVector Safe; + // We check for safety first because there might be multiple values in + // the same path, some of which are not safe to be hoisted, but overall + // each edge has at least one value which can be hoisted, making the + // value anticipable along that path. + checkSafety(make_range(PrevIt, PHIIt), BB, K, Safe); + + // List of safe values should be anticipable at TI. + if (valueAnticipable(make_range(Safe.begin(), Safe.end()), TI)) { + HPL.push_back({BB, SmallVecInsn()}); + SmallVecInsn &V = HPL.back().second; + for (auto B : Safe) + V.push_back(B.I); + } - // Remove MemorySSA phi nodes with the same arguments. - if (NewMemAcc) - raMPHIuw(NewMemAcc); - return NR; + // Check other VNs + PrevIt = PHIIt; + PHIIt = std::find_if(PrevIt, CHIs.end(), + [PrevIt](CHIArg &A) { return A != *PrevIt; }); + } } +} - // In the case Repl is a load or a store, we make all their GEPs - // available: GEPs are not hoisted by default to avoid the address - // computations to be hoisted without the associated load or store. - bool makeGepOperandsAvailable(Instruction *Repl, BasicBlock *HoistPt, - const SmallVecInsn &InstructionsToHoist) const { - // Check whether the GEP of a ld/st can be synthesized at HoistPt. - GetElementPtrInst *Gep = nullptr; - Instruction *Val = nullptr; - if (auto *Ld = dyn_cast(Repl)) { - Gep = dyn_cast(Ld->getPointerOperand()); - } else if (auto *St = dyn_cast(Repl)) { - Gep = dyn_cast(St->getPointerOperand()); - Val = dyn_cast(St->getValueOperand()); - // Check that the stored value is available. - if (Val) { - if (isa(Val)) { - // Check whether we can compute the GEP at HoistPt. - if (!allGepOperandsAvailable(Val, HoistPt)) +bool GVNHoist::allOperandsAvailable(const Instruction *I, + const BasicBlock *HoistPt) const { + for (const Use &Op : I->operands()) + if (const auto *Inst = dyn_cast(&Op)) + if (!DT->dominates(Inst->getParent(), HoistPt)) + return false; + + return true; +} + +bool GVNHoist::allGepOperandsAvailable(const Instruction *I, + const BasicBlock *HoistPt) const { + for (const Use &Op : I->operands()) + if (const auto *Inst = dyn_cast(&Op)) + if (!DT->dominates(Inst->getParent(), HoistPt)) { + if (const GetElementPtrInst *GepOp = + dyn_cast(Inst)) { + if (!allGepOperandsAvailable(GepOp, HoistPt)) return false; - } else if (!DT->dominates(Val->getParent(), HoistPt)) + // Gep is available if all operands of GepOp are available. + } else { + // Gep is not available if it has operands other than GEPs that are + // defined in blocks not dominating HoistPt. return false; + } } - } + return true; +} - // Check whether we can compute the Gep at HoistPt. - if (!Gep || !allGepOperandsAvailable(Gep, HoistPt)) - return false; +void GVNHoist::makeGepsAvailable(Instruction *Repl, BasicBlock *HoistPt, + const SmallVecInsn &InstructionsToHoist, + Instruction *Gep) const { + assert(allGepOperandsAvailable(Gep, HoistPt) && "GEP operands not available"); - makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Gep); + Instruction *ClonedGep = Gep->clone(); + for (unsigned i = 0, e = Gep->getNumOperands(); i != e; ++i) + if (Instruction *Op = dyn_cast(Gep->getOperand(i))) { + // Check whether the operand is already available. + if (DT->dominates(Op->getParent(), HoistPt)) + continue; - if (Val && isa(Val)) - makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Val); + // As a GEP can refer to other GEPs, recursively make all the operands + // of this GEP available at HoistPt. + if (GetElementPtrInst *GepOp = dyn_cast(Op)) + makeGepsAvailable(ClonedGep, HoistPt, InstructionsToHoist, GepOp); + } - return true; - } + // Copy Gep and replace its uses in Repl with ClonedGep. + ClonedGep->insertBefore(HoistPt->getTerminator()); - std::pair hoist(HoistingPointList &HPL) { - unsigned NI = 0, NL = 0, NS = 0, NC = 0, NR = 0; - for (const HoistingPointInfo &HP : HPL) { - // Find out whether we already have one of the instructions in HoistPt, - // in which case we do not have to move it. - BasicBlock *DestBB = HP.first; - const SmallVecInsn &InstructionsToHoist = HP.second; - Instruction *Repl = nullptr; - for (Instruction *I : InstructionsToHoist) - if (I->getParent() == DestBB) - // If there are two instructions in HoistPt to be hoisted in place: - // update Repl to be the first one, such that we can rename the uses - // of the second based on the first. - if (!Repl || firstInBB(I, Repl)) - Repl = I; - - // Keep track of whether we moved the instruction so we know whether we - // should move the MemoryAccess. - bool MoveAccess = true; - if (Repl) { - // Repl is already in HoistPt: it remains in place. - assert(allOperandsAvailable(Repl, DestBB) && - "instruction depends on operands that are not available"); - MoveAccess = false; - } else { - // When we do not find Repl in HoistPt, select the first in the list - // and move it to HoistPt. - Repl = InstructionsToHoist.front(); - - // We can move Repl in HoistPt only when all operands are available. - // The order in which hoistings are done may influence the availability - // of operands. - if (!allOperandsAvailable(Repl, DestBB)) { - // When HoistingGeps there is nothing more we can do to make the - // operands available: just continue. - if (HoistingGeps) - continue; + // Conservatively discard any optimization hints, they may differ on the + // other paths. + ClonedGep->dropUnknownNonDebugMetadata(); - // When not HoistingGeps we need to copy the GEPs. - if (!makeGepOperandsAvailable(Repl, DestBB, InstructionsToHoist)) - continue; - } + // If we have optimization hints which agree with each other along different + // paths, preserve them. + for (const Instruction *OtherInst : InstructionsToHoist) { + const GetElementPtrInst *OtherGep; + if (auto *OtherLd = dyn_cast(OtherInst)) + OtherGep = cast(OtherLd->getPointerOperand()); + else + OtherGep = cast( + cast(OtherInst)->getPointerOperand()); + ClonedGep->andIRFlags(OtherGep); + } - // Move the instruction at the end of HoistPt. - Instruction *Last = DestBB->getTerminator(); - MD->removeInstruction(Repl); - Repl->moveBefore(Last); + // Replace uses of Gep with ClonedGep in Repl. + Repl->replaceUsesOfWith(Gep, ClonedGep); +} - DFSNumber[Repl] = DFSNumber[Last]++; +void GVNHoist::updateAlignment(Instruction *I, Instruction *Repl) { + if (auto *ReplacementLoad = dyn_cast(Repl)) { + ReplacementLoad->setAlignment( + std::min(ReplacementLoad->getAlign(), cast(I)->getAlign())); + ++NumLoadsRemoved; + } else if (auto *ReplacementStore = dyn_cast(Repl)) { + ReplacementStore->setAlignment( + std::min(ReplacementStore->getAlign(), cast(I)->getAlign())); + ++NumStoresRemoved; + } else if (auto *ReplacementAlloca = dyn_cast(Repl)) { + ReplacementAlloca->setAlignment(std::max(ReplacementAlloca->getAlign(), + cast(I)->getAlign())); + } else if (isa(Repl)) { + ++NumCallsRemoved; + } +} + +unsigned GVNHoist::rauw(const SmallVecInsn &Candidates, Instruction *Repl, + MemoryUseOrDef *NewMemAcc) { + unsigned NR = 0; + for (Instruction *I : Candidates) { + if (I != Repl) { + ++NR; + updateAlignment(I, Repl); + if (NewMemAcc) { + // Update the uses of the old MSSA access with NewMemAcc. + MemoryAccess *OldMA = MSSA->getMemoryAccess(I); + OldMA->replaceAllUsesWith(NewMemAcc); + MSSAUpdater->removeMemoryAccess(OldMA); } - NR += removeAndReplace(InstructionsToHoist, Repl, DestBB, MoveAccess); + Repl->andIRFlags(I); + combineKnownMetadata(Repl, I); + I->replaceAllUsesWith(Repl); + // Also invalidate the Alias Analysis cache. + MD->removeInstruction(I); + I->eraseFromParent(); + } + } + return NR; +} - if (isa(Repl)) - ++NL; - else if (isa(Repl)) - ++NS; - else if (isa(Repl)) - ++NC; - else // Scalar - ++NI; +void GVNHoist::raMPHIuw(MemoryUseOrDef *NewMemAcc) { + SmallPtrSet UsePhis; + for (User *U : NewMemAcc->users()) + if (MemoryPhi *Phi = dyn_cast(U)) + UsePhis.insert(Phi); + + for (MemoryPhi *Phi : UsePhis) { + auto In = Phi->incoming_values(); + if (llvm::all_of(In, [&](Use &U) { return U == NewMemAcc; })) { + Phi->replaceAllUsesWith(NewMemAcc); + MSSAUpdater->removeMemoryAccess(Phi); } + } +} + +unsigned GVNHoist::removeAndReplace(const SmallVecInsn &Candidates, + Instruction *Repl, BasicBlock *DestBB, + bool MoveAccess) { + MemoryUseOrDef *NewMemAcc = MSSA->getMemoryAccess(Repl); + if (MoveAccess && NewMemAcc) { + // The definition of this ld/st will not change: ld/st hoisting is + // legal when the ld/st is not moved past its current definition. + MSSAUpdater->moveToPlace(NewMemAcc, DestBB, MemorySSA::BeforeTerminator); + } - if (MSSA && VerifyMemorySSA) - MSSA->verifyMemorySSA(); + // Replace all other instructions with Repl with memory access NewMemAcc. + unsigned NR = rauw(Candidates, Repl, NewMemAcc); - NumHoisted += NL + NS + NC + NI; - NumRemoved += NR; - NumLoadsHoisted += NL; - NumStoresHoisted += NS; - NumCallsHoisted += NC; - return {NI, NL + NC + NS}; + // Remove MemorySSA phi nodes with the same arguments. + if (NewMemAcc) + raMPHIuw(NewMemAcc); + return NR; +} + +bool GVNHoist::makeGepOperandsAvailable( + Instruction *Repl, BasicBlock *HoistPt, + const SmallVecInsn &InstructionsToHoist) const { + // Check whether the GEP of a ld/st can be synthesized at HoistPt. + GetElementPtrInst *Gep = nullptr; + Instruction *Val = nullptr; + if (auto *Ld = dyn_cast(Repl)) { + Gep = dyn_cast(Ld->getPointerOperand()); + } else if (auto *St = dyn_cast(Repl)) { + Gep = dyn_cast(St->getPointerOperand()); + Val = dyn_cast(St->getValueOperand()); + // Check that the stored value is available. + if (Val) { + if (isa(Val)) { + // Check whether we can compute the GEP at HoistPt. + if (!allGepOperandsAvailable(Val, HoistPt)) + return false; + } else if (!DT->dominates(Val->getParent(), HoistPt)) + return false; + } } - // Hoist all expressions. Returns Number of scalars hoisted - // and number of non-scalars hoisted. - std::pair hoistExpressions(Function &F) { - InsnInfo II; - LoadInfo LI; - StoreInfo SI; - CallInfo CI; - for (BasicBlock *BB : depth_first(&F.getEntryBlock())) { - int InstructionNb = 0; - for (Instruction &I1 : *BB) { - // If I1 cannot guarantee progress, subsequent instructions - // in BB cannot be hoisted anyways. - if (!isGuaranteedToTransferExecutionToSuccessor(&I1)) { - HoistBarrier.insert(BB); - break; - } - // Only hoist the first instructions in BB up to MaxDepthInBB. Hoisting - // deeper may increase the register pressure and compilation time. - if (MaxDepthInBB != -1 && InstructionNb++ >= MaxDepthInBB) - break; + // Check whether we can compute the Gep at HoistPt. + if (!Gep || !allGepOperandsAvailable(Gep, HoistPt)) + return false; - // Do not value number terminator instructions. - if (I1.isTerminator()) - break; + makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Gep); - if (auto *Load = dyn_cast(&I1)) - LI.insert(Load, VN); - else if (auto *Store = dyn_cast(&I1)) - SI.insert(Store, VN); - else if (auto *Call = dyn_cast(&I1)) { - if (auto *Intr = dyn_cast(Call)) { - if (isa(Intr) || - Intr->getIntrinsicID() == Intrinsic::assume || - Intr->getIntrinsicID() == Intrinsic::sideeffect) - continue; - } - if (Call->mayHaveSideEffects()) - break; - - if (Call->isConvergent()) - break; - - CI.insert(Call, VN); - } else if (HoistingGeps || !isa(&I1)) - // Do not hoist scalars past calls that may write to memory because - // that could result in spills later. geps are handled separately. - // TODO: We can relax this for targets like AArch64 as they have more - // registers than X86. - II.insert(&I1, VN); + if (Val && isa(Val)) + makeGepsAvailable(Repl, HoistPt, InstructionsToHoist, Val); + + return true; +} + +std::pair GVNHoist::hoist(HoistingPointList &HPL) { + unsigned NI = 0, NL = 0, NS = 0, NC = 0, NR = 0; + for (const HoistingPointInfo &HP : HPL) { + // Find out whether we already have one of the instructions in HoistPt, + // in which case we do not have to move it. + BasicBlock *DestBB = HP.first; + const SmallVecInsn &InstructionsToHoist = HP.second; + Instruction *Repl = nullptr; + for (Instruction *I : InstructionsToHoist) + if (I->getParent() == DestBB) + // If there are two instructions in HoistPt to be hoisted in place: + // update Repl to be the first one, such that we can rename the uses + // of the second based on the first. + if (!Repl || firstInBB(I, Repl)) + Repl = I; + + // Keep track of whether we moved the instruction so we know whether we + // should move the MemoryAccess. + bool MoveAccess = true; + if (Repl) { + // Repl is already in HoistPt: it remains in place. + assert(allOperandsAvailable(Repl, DestBB) && + "instruction depends on operands that are not available"); + MoveAccess = false; + } else { + // When we do not find Repl in HoistPt, select the first in the list + // and move it to HoistPt. + Repl = InstructionsToHoist.front(); + + // We can move Repl in HoistPt only when all operands are available. + // The order in which hoistings are done may influence the availability + // of operands. + if (!allOperandsAvailable(Repl, DestBB)) { + // When HoistingGeps there is nothing more we can do to make the + // operands available: just continue. + if (HoistingGeps) + continue; + + // When not HoistingGeps we need to copy the GEPs. + if (!makeGepOperandsAvailable(Repl, DestBB, InstructionsToHoist)) + continue; } + + // Move the instruction at the end of HoistPt. + Instruction *Last = DestBB->getTerminator(); + MD->removeInstruction(Repl); + Repl->moveBefore(Last); + + DFSNumber[Repl] = DFSNumber[Last]++; } - HoistingPointList HPL; - computeInsertionPoints(II.getVNTable(), HPL, InsKind::Scalar); - computeInsertionPoints(LI.getVNTable(), HPL, InsKind::Load); - computeInsertionPoints(SI.getVNTable(), HPL, InsKind::Store); - computeInsertionPoints(CI.getScalarVNTable(), HPL, InsKind::Scalar); - computeInsertionPoints(CI.getLoadVNTable(), HPL, InsKind::Load); - computeInsertionPoints(CI.getStoreVNTable(), HPL, InsKind::Store); - return hoist(HPL); + NR += removeAndReplace(InstructionsToHoist, Repl, DestBB, MoveAccess); + + if (isa(Repl)) + ++NL; + else if (isa(Repl)) + ++NS; + else if (isa(Repl)) + ++NC; + else // Scalar + ++NI; } -}; -class GVNHoistLegacyPass : public FunctionPass { -public: - static char ID; + if (MSSA && VerifyMemorySSA) + MSSA->verifyMemorySSA(); - GVNHoistLegacyPass() : FunctionPass(ID) { - initializeGVNHoistLegacyPassPass(*PassRegistry::getPassRegistry()); - } + NumHoisted += NL + NS + NC + NI; + NumRemoved += NR; + NumLoadsHoisted += NL; + NumStoresHoisted += NS; + NumCallsHoisted += NC; + return {NI, NL + NC + NS}; +} - bool runOnFunction(Function &F) override { - if (skipFunction(F)) - return false; - auto &DT = getAnalysis().getDomTree(); - auto &PDT = getAnalysis().getPostDomTree(); - auto &AA = getAnalysis().getAAResults(); - auto &MD = getAnalysis().getMemDep(); - auto &MSSA = getAnalysis().getMSSA(); +std::pair GVNHoist::hoistExpressions(Function &F) { + InsnInfo II; + LoadInfo LI; + StoreInfo SI; + CallInfo CI; + for (BasicBlock *BB : depth_first(&F.getEntryBlock())) { + int InstructionNb = 0; + for (Instruction &I1 : *BB) { + // If I1 cannot guarantee progress, subsequent instructions + // in BB cannot be hoisted anyways. + if (!isGuaranteedToTransferExecutionToSuccessor(&I1)) { + HoistBarrier.insert(BB); + break; + } + // Only hoist the first instructions in BB up to MaxDepthInBB. Hoisting + // deeper may increase the register pressure and compilation time. + if (MaxDepthInBB != -1 && InstructionNb++ >= MaxDepthInBB) + break; + + // Do not value number terminator instructions. + if (I1.isTerminator()) + break; + + if (auto *Load = dyn_cast(&I1)) + LI.insert(Load, VN); + else if (auto *Store = dyn_cast(&I1)) + SI.insert(Store, VN); + else if (auto *Call = dyn_cast(&I1)) { + if (auto *Intr = dyn_cast(Call)) { + if (isa(Intr) || + Intr->getIntrinsicID() == Intrinsic::assume || + Intr->getIntrinsicID() == Intrinsic::sideeffect) + continue; + } + if (Call->mayHaveSideEffects()) + break; - GVNHoist G(&DT, &PDT, &AA, &MD, &MSSA); - return G.run(F); - } + if (Call->isConvergent()) + break; - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - AU.addPreserved(); - AU.addPreserved(); - AU.addPreserved(); - AU.addPreserved(); + CI.insert(Call, VN); + } else if (HoistingGeps || !isa(&I1)) + // Do not hoist scalars past calls that may write to memory because + // that could result in spills later. geps are handled separately. + // TODO: We can relax this for targets like AArch64 as they have more + // registers than X86. + II.insert(&I1, VN); + } } -}; + + HoistingPointList HPL; + computeInsertionPoints(II.getVNTable(), HPL, InsKind::Scalar); + computeInsertionPoints(LI.getVNTable(), HPL, InsKind::Load); + computeInsertionPoints(SI.getVNTable(), HPL, InsKind::Store); + computeInsertionPoints(CI.getScalarVNTable(), HPL, InsKind::Scalar); + computeInsertionPoints(CI.getLoadVNTable(), HPL, InsKind::Load); + computeInsertionPoints(CI.getStoreVNTable(), HPL, InsKind::Store); + return hoist(HPL); +} } // end namespace llvm diff --git a/llvm/lib/Transforms/Scalar/GVNSink.cpp b/llvm/lib/Transforms/Scalar/GVNSink.cpp index dfb4b7e038ba..aef927ab6558 100644 --- a/llvm/lib/Transforms/Scalar/GVNSink.cpp +++ b/llvm/lib/Transforms/Scalar/GVNSink.cpp @@ -158,8 +158,7 @@ public: void restrictToBlocks(SmallSetVector &Blocks) { for (auto II = Insts.begin(); II != Insts.end();) { - if (std::find(Blocks.begin(), Blocks.end(), (*II)->getParent()) == - Blocks.end()) { + if (!llvm::is_contained(Blocks, (*II)->getParent())) { ActiveBlocks.remove((*II)->getParent()); II = Insts.erase(II); } else { @@ -277,8 +276,7 @@ public: auto VI = Values.begin(); while (BI != Blocks.end()) { assert(VI != Values.end()); - if (std::find(NewBlocks.begin(), NewBlocks.end(), *BI) == - NewBlocks.end()) { + if (!llvm::is_contained(NewBlocks, *BI)) { BI = Blocks.erase(BI); VI = Values.erase(VI); } else { @@ -694,10 +692,8 @@ Optional GVNSink::analyzeInstructionForSinking( ModelledPHI NewPHI(NewInsts, ActivePreds); // Does sinking this instruction render previous PHIs redundant? - if (NeededPHIs.find(NewPHI) != NeededPHIs.end()) { - NeededPHIs.erase(NewPHI); + if (NeededPHIs.erase(NewPHI)) RecomputePHIContents = true; - } if (RecomputePHIContents) { // The needed PHIs have changed, so recompute the set of all needed @@ -758,8 +754,7 @@ Optional GVNSink::analyzeInstructionForSinking( Cand.NumMemoryInsts = MemoryInstNum; Cand.NumBlocks = ActivePreds.size(); Cand.NumPHIs = NeededPHIs.size(); - for (auto *C : ActivePreds) - Cand.Blocks.push_back(C); + append_range(Cand.Blocks, ActivePreds); return Cand; } diff --git a/llvm/lib/Transforms/Scalar/GuardWidening.cpp b/llvm/lib/Transforms/Scalar/GuardWidening.cpp index a3eba27a4d90..61eb4ce0ed46 100644 --- a/llvm/lib/Transforms/Scalar/GuardWidening.cpp +++ b/llvm/lib/Transforms/Scalar/GuardWidening.cpp @@ -347,9 +347,8 @@ bool GuardWideningImpl::eliminateInstrViaWidening( const auto &GuardsInCurBB = GuardsInBlock.find(CurBB)->second; auto I = GuardsInCurBB.begin(); - auto E = Instr->getParent() == CurBB - ? std::find(GuardsInCurBB.begin(), GuardsInCurBB.end(), Instr) - : GuardsInCurBB.end(); + auto E = Instr->getParent() == CurBB ? find(GuardsInCurBB, Instr) + : GuardsInCurBB.end(); #ifndef NDEBUG { @@ -666,13 +665,12 @@ bool GuardWideningImpl::combineRangeChecks( }; copy_if(Checks, std::back_inserter(CurrentChecks), IsCurrentCheck); - Checks.erase(remove_if(Checks, IsCurrentCheck), Checks.end()); + erase_if(Checks, IsCurrentCheck); assert(CurrentChecks.size() != 0 && "We know we have at least one!"); if (CurrentChecks.size() < 3) { - RangeChecksOut.insert(RangeChecksOut.end(), CurrentChecks.begin(), - CurrentChecks.end()); + llvm::append_range(RangeChecksOut, CurrentChecks); continue; } @@ -700,9 +698,7 @@ bool GuardWideningImpl::combineRangeChecks( return (HighOffset - RC.getOffsetValue()).ult(MaxDiff); }; - if (MaxDiff.isMinValue() || - !std::all_of(std::next(CurrentChecks.begin()), CurrentChecks.end(), - OffsetOK)) + if (MaxDiff.isMinValue() || !all_of(drop_begin(CurrentChecks), OffsetOK)) return false; // We have a series of f+1 checks as: diff --git a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp index 0f36c3f772e6..ae1fff0fa844 100644 --- a/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp +++ b/llvm/lib/Transforms/Scalar/IndVarSimplify.cpp @@ -131,6 +131,10 @@ static cl::opt LoopPredication("indvars-predicate-loops", cl::Hidden, cl::init(true), cl::desc("Predicate conditions in read only loops")); +static cl::opt +AllowIVWidening("indvars-widen-indvars", cl::Hidden, cl::init(true), + cl::desc("Allow widening of indvars to eliminate s/zext")); + namespace { struct RewritePhi; @@ -145,6 +149,7 @@ class IndVarSimplify { std::unique_ptr MSSAU; SmallVector DeadInsts; + bool WidenIndVars; bool handleFloatingPointIV(Loop *L, PHINode *PH); bool rewriteNonIntegerIVs(Loop *L); @@ -167,8 +172,9 @@ class IndVarSimplify { public: IndVarSimplify(LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, const DataLayout &DL, TargetLibraryInfo *TLI, - TargetTransformInfo *TTI, MemorySSA *MSSA) - : LI(LI), SE(SE), DT(DT), DL(DL), TLI(TLI), TTI(TTI) { + TargetTransformInfo *TTI, MemorySSA *MSSA, bool WidenIndVars) + : LI(LI), SE(SE), DT(DT), DL(DL), TLI(TLI), TTI(TTI), + WidenIndVars(WidenIndVars) { if (MSSA) MSSAU = std::make_unique(MSSA); } @@ -178,57 +184,6 @@ public: } // end anonymous namespace -/// Determine the insertion point for this user. By default, insert immediately -/// before the user. SCEVExpander or LICM will hoist loop invariants out of the -/// loop. For PHI nodes, there may be multiple uses, so compute the nearest -/// common dominator for the incoming blocks. A nullptr can be returned if no -/// viable location is found: it may happen if User is a PHI and Def only comes -/// to this PHI from unreachable blocks. -static Instruction *getInsertPointForUses(Instruction *User, Value *Def, - DominatorTree *DT, LoopInfo *LI) { - PHINode *PHI = dyn_cast(User); - if (!PHI) - return User; - - Instruction *InsertPt = nullptr; - for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) { - if (PHI->getIncomingValue(i) != Def) - continue; - - BasicBlock *InsertBB = PHI->getIncomingBlock(i); - - if (!DT->isReachableFromEntry(InsertBB)) - continue; - - if (!InsertPt) { - InsertPt = InsertBB->getTerminator(); - continue; - } - InsertBB = DT->findNearestCommonDominator(InsertPt->getParent(), InsertBB); - InsertPt = InsertBB->getTerminator(); - } - - // If we have skipped all inputs, it means that Def only comes to Phi from - // unreachable blocks. - if (!InsertPt) - return nullptr; - - auto *DefI = dyn_cast(Def); - if (!DefI) - return InsertPt; - - assert(DT->dominates(DefI, InsertPt) && "def does not dominate all uses"); - - auto *L = LI->getLoopFor(DefI->getParent()); - assert(!L || L->contains(LI->getLoopFor(InsertPt->getParent()))); - - for (auto *DTN = (*DT)[InsertPt->getParent()]; DTN; DTN = DTN->getIDom()) - if (LI->getLoopFor(DTN->getBlock()) == L) - return DTN->getBlock()->getTerminator(); - - llvm_unreachable("DefI dominates InsertPt!"); -} - //===----------------------------------------------------------------------===// // rewriteNonIntegerIVs and helpers. Prefer integer IVs. //===----------------------------------------------------------------------===// @@ -550,27 +505,11 @@ bool IndVarSimplify::rewriteFirstIterationLoopExitValues(Loop *L) { // IV Widening - Extend the width of an IV to cover its widest uses. //===----------------------------------------------------------------------===// -namespace { - -// Collect information about induction variables that are used by sign/zero -// extend operations. This information is recorded by CollectExtend and provides -// the input to WidenIV. -struct WideIVInfo { - PHINode *NarrowIV = nullptr; - - // Widest integer type created [sz]ext - Type *WidestNativeType = nullptr; - - // Was a sext user seen before a zext? - bool IsSigned = false; -}; - -} // end anonymous namespace - /// Update information about the induction variable that is extended by this /// sign or zero extend operation. This is used to determine the final width of /// the IV before actually widening it. -static void visitIVCast(CastInst *Cast, WideIVInfo &WI, ScalarEvolution *SE, +static void visitIVCast(CastInst *Cast, WideIVInfo &WI, + ScalarEvolution *SE, const TargetTransformInfo *TTI) { bool IsSigned = Cast->getOpcode() == Instruction::SExt; if (!IsSigned && Cast->getOpcode() != Instruction::ZExt) @@ -616,982 +555,6 @@ static void visitIVCast(CastInst *Cast, WideIVInfo &WI, ScalarEvolution *SE, WI.WidestNativeType = SE->getEffectiveSCEVType(Ty); } -namespace { - -/// Record a link in the Narrow IV def-use chain along with the WideIV that -/// computes the same value as the Narrow IV def. This avoids caching Use* -/// pointers. -struct NarrowIVDefUse { - Instruction *NarrowDef = nullptr; - Instruction *NarrowUse = nullptr; - Instruction *WideDef = nullptr; - - // True if the narrow def is never negative. Tracking this information lets - // us use a sign extension instead of a zero extension or vice versa, when - // profitable and legal. - bool NeverNegative = false; - - NarrowIVDefUse(Instruction *ND, Instruction *NU, Instruction *WD, - bool NeverNegative) - : NarrowDef(ND), NarrowUse(NU), WideDef(WD), - NeverNegative(NeverNegative) {} -}; - -/// The goal of this transform is to remove sign and zero extends without -/// creating any new induction variables. To do this, it creates a new phi of -/// the wider type and redirects all users, either removing extends or inserting -/// truncs whenever we stop propagating the type. -class WidenIV { - // Parameters - PHINode *OrigPhi; - Type *WideType; - - // Context - LoopInfo *LI; - Loop *L; - ScalarEvolution *SE; - DominatorTree *DT; - - // Does the module have any calls to the llvm.experimental.guard intrinsic - // at all? If not we can avoid scanning instructions looking for guards. - bool HasGuards; - - // Result - PHINode *WidePhi = nullptr; - Instruction *WideInc = nullptr; - const SCEV *WideIncExpr = nullptr; - SmallVectorImpl &DeadInsts; - - SmallPtrSet Widened; - SmallVector NarrowIVUsers; - - enum ExtendKind { ZeroExtended, SignExtended, Unknown }; - - // A map tracking the kind of extension used to widen each narrow IV - // and narrow IV user. - // Key: pointer to a narrow IV or IV user. - // Value: the kind of extension used to widen this Instruction. - DenseMap, ExtendKind> ExtendKindMap; - - using DefUserPair = std::pair, AssertingVH>; - - // A map with control-dependent ranges for post increment IV uses. The key is - // a pair of IV def and a use of this def denoting the context. The value is - // a ConstantRange representing possible values of the def at the given - // context. - DenseMap PostIncRangeInfos; - - Optional getPostIncRangeInfo(Value *Def, - Instruction *UseI) { - DefUserPair Key(Def, UseI); - auto It = PostIncRangeInfos.find(Key); - return It == PostIncRangeInfos.end() - ? Optional(None) - : Optional(It->second); - } - - void calculatePostIncRanges(PHINode *OrigPhi); - void calculatePostIncRange(Instruction *NarrowDef, Instruction *NarrowUser); - - void updatePostIncRangeInfo(Value *Def, Instruction *UseI, ConstantRange R) { - DefUserPair Key(Def, UseI); - auto It = PostIncRangeInfos.find(Key); - if (It == PostIncRangeInfos.end()) - PostIncRangeInfos.insert({Key, R}); - else - It->second = R.intersectWith(It->second); - } - -public: - WidenIV(const WideIVInfo &WI, LoopInfo *LInfo, ScalarEvolution *SEv, - DominatorTree *DTree, SmallVectorImpl &DI, - bool HasGuards) - : OrigPhi(WI.NarrowIV), WideType(WI.WidestNativeType), LI(LInfo), - L(LI->getLoopFor(OrigPhi->getParent())), SE(SEv), DT(DTree), - HasGuards(HasGuards), DeadInsts(DI) { - assert(L->getHeader() == OrigPhi->getParent() && "Phi must be an IV"); - ExtendKindMap[OrigPhi] = WI.IsSigned ? SignExtended : ZeroExtended; - } - - PHINode *createWideIV(SCEVExpander &Rewriter); - -protected: - Value *createExtendInst(Value *NarrowOper, Type *WideType, bool IsSigned, - Instruction *Use); - - Instruction *cloneIVUser(NarrowIVDefUse DU, const SCEVAddRecExpr *WideAR); - Instruction *cloneArithmeticIVUser(NarrowIVDefUse DU, - const SCEVAddRecExpr *WideAR); - Instruction *cloneBitwiseIVUser(NarrowIVDefUse DU); - - ExtendKind getExtendKind(Instruction *I); - - using WidenedRecTy = std::pair; - - WidenedRecTy getWideRecurrence(NarrowIVDefUse DU); - - WidenedRecTy getExtendedOperandRecurrence(NarrowIVDefUse DU); - - const SCEV *getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS, - unsigned OpCode) const; - - Instruction *widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter); - - bool widenLoopCompare(NarrowIVDefUse DU); - bool widenWithVariantUse(NarrowIVDefUse DU); - void widenWithVariantUseCodegen(NarrowIVDefUse DU); - - void pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef); -}; - -} // end anonymous namespace - -Value *WidenIV::createExtendInst(Value *NarrowOper, Type *WideType, - bool IsSigned, Instruction *Use) { - // Set the debug location and conservative insertion point. - IRBuilder<> Builder(Use); - // Hoist the insertion point into loop preheaders as far as possible. - for (const Loop *L = LI->getLoopFor(Use->getParent()); - L && L->getLoopPreheader() && L->isLoopInvariant(NarrowOper); - L = L->getParentLoop()) - Builder.SetInsertPoint(L->getLoopPreheader()->getTerminator()); - - return IsSigned ? Builder.CreateSExt(NarrowOper, WideType) : - Builder.CreateZExt(NarrowOper, WideType); -} - -/// Instantiate a wide operation to replace a narrow operation. This only needs -/// to handle operations that can evaluation to SCEVAddRec. It can safely return -/// 0 for any operation we decide not to clone. -Instruction *WidenIV::cloneIVUser(NarrowIVDefUse DU, - const SCEVAddRecExpr *WideAR) { - unsigned Opcode = DU.NarrowUse->getOpcode(); - switch (Opcode) { - default: - return nullptr; - case Instruction::Add: - case Instruction::Mul: - case Instruction::UDiv: - case Instruction::Sub: - return cloneArithmeticIVUser(DU, WideAR); - - case Instruction::And: - case Instruction::Or: - case Instruction::Xor: - case Instruction::Shl: - case Instruction::LShr: - case Instruction::AShr: - return cloneBitwiseIVUser(DU); - } -} - -Instruction *WidenIV::cloneBitwiseIVUser(NarrowIVDefUse DU) { - Instruction *NarrowUse = DU.NarrowUse; - Instruction *NarrowDef = DU.NarrowDef; - Instruction *WideDef = DU.WideDef; - - LLVM_DEBUG(dbgs() << "Cloning bitwise IVUser: " << *NarrowUse << "\n"); - - // Replace NarrowDef operands with WideDef. Otherwise, we don't know anything - // about the narrow operand yet so must insert a [sz]ext. It is probably loop - // invariant and will be folded or hoisted. If it actually comes from a - // widened IV, it should be removed during a future call to widenIVUse. - bool IsSigned = getExtendKind(NarrowDef) == SignExtended; - Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(0), WideType, - IsSigned, NarrowUse); - Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(1), WideType, - IsSigned, NarrowUse); - - auto *NarrowBO = cast(NarrowUse); - auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, - NarrowBO->getName()); - IRBuilder<> Builder(NarrowUse); - Builder.Insert(WideBO); - WideBO->copyIRFlags(NarrowBO); - return WideBO; -} - -Instruction *WidenIV::cloneArithmeticIVUser(NarrowIVDefUse DU, - const SCEVAddRecExpr *WideAR) { - Instruction *NarrowUse = DU.NarrowUse; - Instruction *NarrowDef = DU.NarrowDef; - Instruction *WideDef = DU.WideDef; - - LLVM_DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *NarrowUse << "\n"); - - unsigned IVOpIdx = (NarrowUse->getOperand(0) == NarrowDef) ? 0 : 1; - - // We're trying to find X such that - // - // Widen(NarrowDef `op` NonIVNarrowDef) == WideAR == WideDef `op.wide` X - // - // We guess two solutions to X, sext(NonIVNarrowDef) and zext(NonIVNarrowDef), - // and check using SCEV if any of them are correct. - - // Returns true if extending NonIVNarrowDef according to `SignExt` is a - // correct solution to X. - auto GuessNonIVOperand = [&](bool SignExt) { - const SCEV *WideLHS; - const SCEV *WideRHS; - - auto GetExtend = [this, SignExt](const SCEV *S, Type *Ty) { - if (SignExt) - return SE->getSignExtendExpr(S, Ty); - return SE->getZeroExtendExpr(S, Ty); - }; - - if (IVOpIdx == 0) { - WideLHS = SE->getSCEV(WideDef); - const SCEV *NarrowRHS = SE->getSCEV(NarrowUse->getOperand(1)); - WideRHS = GetExtend(NarrowRHS, WideType); - } else { - const SCEV *NarrowLHS = SE->getSCEV(NarrowUse->getOperand(0)); - WideLHS = GetExtend(NarrowLHS, WideType); - WideRHS = SE->getSCEV(WideDef); - } - - // WideUse is "WideDef `op.wide` X" as described in the comment. - const SCEV *WideUse = nullptr; - - switch (NarrowUse->getOpcode()) { - default: - llvm_unreachable("No other possibility!"); - - case Instruction::Add: - WideUse = SE->getAddExpr(WideLHS, WideRHS); - break; - - case Instruction::Mul: - WideUse = SE->getMulExpr(WideLHS, WideRHS); - break; - - case Instruction::UDiv: - WideUse = SE->getUDivExpr(WideLHS, WideRHS); - break; - - case Instruction::Sub: - WideUse = SE->getMinusSCEV(WideLHS, WideRHS); - break; - } - - return WideUse == WideAR; - }; - - bool SignExtend = getExtendKind(NarrowDef) == SignExtended; - if (!GuessNonIVOperand(SignExtend)) { - SignExtend = !SignExtend; - if (!GuessNonIVOperand(SignExtend)) - return nullptr; - } - - Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(0), WideType, - SignExtend, NarrowUse); - Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(1), WideType, - SignExtend, NarrowUse); - - auto *NarrowBO = cast(NarrowUse); - auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, - NarrowBO->getName()); - - IRBuilder<> Builder(NarrowUse); - Builder.Insert(WideBO); - WideBO->copyIRFlags(NarrowBO); - return WideBO; -} - -WidenIV::ExtendKind WidenIV::getExtendKind(Instruction *I) { - auto It = ExtendKindMap.find(I); - assert(It != ExtendKindMap.end() && "Instruction not yet extended!"); - return It->second; -} - -const SCEV *WidenIV::getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS, - unsigned OpCode) const { - if (OpCode == Instruction::Add) - return SE->getAddExpr(LHS, RHS); - if (OpCode == Instruction::Sub) - return SE->getMinusSCEV(LHS, RHS); - if (OpCode == Instruction::Mul) - return SE->getMulExpr(LHS, RHS); - - llvm_unreachable("Unsupported opcode."); -} - -/// No-wrap operations can transfer sign extension of their result to their -/// operands. Generate the SCEV value for the widened operation without -/// actually modifying the IR yet. If the expression after extending the -/// operands is an AddRec for this loop, return the AddRec and the kind of -/// extension used. -WidenIV::WidenedRecTy WidenIV::getExtendedOperandRecurrence(NarrowIVDefUse DU) { - // Handle the common case of add - const unsigned OpCode = DU.NarrowUse->getOpcode(); - // Only Add/Sub/Mul instructions supported yet. - if (OpCode != Instruction::Add && OpCode != Instruction::Sub && - OpCode != Instruction::Mul) - return {nullptr, Unknown}; - - // One operand (NarrowDef) has already been extended to WideDef. Now determine - // if extending the other will lead to a recurrence. - const unsigned ExtendOperIdx = - DU.NarrowUse->getOperand(0) == DU.NarrowDef ? 1 : 0; - assert(DU.NarrowUse->getOperand(1-ExtendOperIdx) == DU.NarrowDef && "bad DU"); - - const SCEV *ExtendOperExpr = nullptr; - const OverflowingBinaryOperator *OBO = - cast(DU.NarrowUse); - ExtendKind ExtKind = getExtendKind(DU.NarrowDef); - if (ExtKind == SignExtended && OBO->hasNoSignedWrap()) - ExtendOperExpr = SE->getSignExtendExpr( - SE->getSCEV(DU.NarrowUse->getOperand(ExtendOperIdx)), WideType); - else if(ExtKind == ZeroExtended && OBO->hasNoUnsignedWrap()) - ExtendOperExpr = SE->getZeroExtendExpr( - SE->getSCEV(DU.NarrowUse->getOperand(ExtendOperIdx)), WideType); - else - return {nullptr, Unknown}; - - // When creating this SCEV expr, don't apply the current operations NSW or NUW - // flags. This instruction may be guarded by control flow that the no-wrap - // behavior depends on. Non-control-equivalent instructions can be mapped to - // the same SCEV expression, and it would be incorrect to transfer NSW/NUW - // semantics to those operations. - const SCEV *lhs = SE->getSCEV(DU.WideDef); - const SCEV *rhs = ExtendOperExpr; - - // Let's swap operands to the initial order for the case of non-commutative - // operations, like SUB. See PR21014. - if (ExtendOperIdx == 0) - std::swap(lhs, rhs); - const SCEVAddRecExpr *AddRec = - dyn_cast(getSCEVByOpCode(lhs, rhs, OpCode)); - - if (!AddRec || AddRec->getLoop() != L) - return {nullptr, Unknown}; - - return {AddRec, ExtKind}; -} - -/// Is this instruction potentially interesting for further simplification after -/// widening it's type? In other words, can the extend be safely hoisted out of -/// the loop with SCEV reducing the value to a recurrence on the same loop. If -/// so, return the extended recurrence and the kind of extension used. Otherwise -/// return {nullptr, Unknown}. -WidenIV::WidenedRecTy WidenIV::getWideRecurrence(NarrowIVDefUse DU) { - if (!SE->isSCEVable(DU.NarrowUse->getType())) - return {nullptr, Unknown}; - - const SCEV *NarrowExpr = SE->getSCEV(DU.NarrowUse); - if (SE->getTypeSizeInBits(NarrowExpr->getType()) >= - SE->getTypeSizeInBits(WideType)) { - // NarrowUse implicitly widens its operand. e.g. a gep with a narrow - // index. So don't follow this use. - return {nullptr, Unknown}; - } - - const SCEV *WideExpr; - ExtendKind ExtKind; - if (DU.NeverNegative) { - WideExpr = SE->getSignExtendExpr(NarrowExpr, WideType); - if (isa(WideExpr)) - ExtKind = SignExtended; - else { - WideExpr = SE->getZeroExtendExpr(NarrowExpr, WideType); - ExtKind = ZeroExtended; - } - } else if (getExtendKind(DU.NarrowDef) == SignExtended) { - WideExpr = SE->getSignExtendExpr(NarrowExpr, WideType); - ExtKind = SignExtended; - } else { - WideExpr = SE->getZeroExtendExpr(NarrowExpr, WideType); - ExtKind = ZeroExtended; - } - const SCEVAddRecExpr *AddRec = dyn_cast(WideExpr); - if (!AddRec || AddRec->getLoop() != L) - return {nullptr, Unknown}; - return {AddRec, ExtKind}; -} - -/// This IV user cannot be widened. Replace this use of the original narrow IV -/// with a truncation of the new wide IV to isolate and eliminate the narrow IV. -static void truncateIVUse(NarrowIVDefUse DU, DominatorTree *DT, LoopInfo *LI) { - auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI); - if (!InsertPt) - return; - LLVM_DEBUG(dbgs() << "INDVARS: Truncate IV " << *DU.WideDef << " for user " - << *DU.NarrowUse << "\n"); - IRBuilder<> Builder(InsertPt); - Value *Trunc = Builder.CreateTrunc(DU.WideDef, DU.NarrowDef->getType()); - DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, Trunc); -} - -/// If the narrow use is a compare instruction, then widen the compare -// (and possibly the other operand). The extend operation is hoisted into the -// loop preheader as far as possible. -bool WidenIV::widenLoopCompare(NarrowIVDefUse DU) { - ICmpInst *Cmp = dyn_cast(DU.NarrowUse); - if (!Cmp) - return false; - - // We can legally widen the comparison in the following two cases: - // - // - The signedness of the IV extension and comparison match - // - // - The narrow IV is always positive (and thus its sign extension is equal - // to its zero extension). For instance, let's say we're zero extending - // %narrow for the following use - // - // icmp slt i32 %narrow, %val ... (A) - // - // and %narrow is always positive. Then - // - // (A) == icmp slt i32 sext(%narrow), sext(%val) - // == icmp slt i32 zext(%narrow), sext(%val) - bool IsSigned = getExtendKind(DU.NarrowDef) == SignExtended; - if (!(DU.NeverNegative || IsSigned == Cmp->isSigned())) - return false; - - Value *Op = Cmp->getOperand(Cmp->getOperand(0) == DU.NarrowDef ? 1 : 0); - unsigned CastWidth = SE->getTypeSizeInBits(Op->getType()); - unsigned IVWidth = SE->getTypeSizeInBits(WideType); - assert(CastWidth <= IVWidth && "Unexpected width while widening compare."); - - // Widen the compare instruction. - auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI); - if (!InsertPt) - return false; - IRBuilder<> Builder(InsertPt); - DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef); - - // Widen the other operand of the compare, if necessary. - if (CastWidth < IVWidth) { - Value *ExtOp = createExtendInst(Op, WideType, Cmp->isSigned(), Cmp); - DU.NarrowUse->replaceUsesOfWith(Op, ExtOp); - } - return true; -} - -// The widenIVUse avoids generating trunc by evaluating the use as AddRec, this -// will not work when: -// 1) SCEV traces back to an instruction inside the loop that SCEV can not -// expand, eg. add %indvar, (load %addr) -// 2) SCEV finds a loop variant, eg. add %indvar, %loopvariant -// While SCEV fails to avoid trunc, we can still try to use instruction -// combining approach to prove trunc is not required. This can be further -// extended with other instruction combining checks, but for now we handle the -// following case (sub can be "add" and "mul", "nsw + sext" can be "nus + zext") -// -// Src: -// %c = sub nsw %b, %indvar -// %d = sext %c to i64 -// Dst: -// %indvar.ext1 = sext %indvar to i64 -// %m = sext %b to i64 -// %d = sub nsw i64 %m, %indvar.ext1 -// Therefore, as long as the result of add/sub/mul is extended to wide type, no -// trunc is required regardless of how %b is generated. This pattern is common -// when calculating address in 64 bit architecture -bool WidenIV::widenWithVariantUse(NarrowIVDefUse DU) { - Instruction *NarrowUse = DU.NarrowUse; - Instruction *NarrowDef = DU.NarrowDef; - Instruction *WideDef = DU.WideDef; - - // Handle the common case of add - const unsigned OpCode = NarrowUse->getOpcode(); - // Only Add/Sub/Mul instructions are supported. - if (OpCode != Instruction::Add && OpCode != Instruction::Sub && - OpCode != Instruction::Mul) - return false; - - // The operand that is not defined by NarrowDef of DU. Let's call it the - // other operand. - unsigned ExtendOperIdx = DU.NarrowUse->getOperand(0) == NarrowDef ? 1 : 0; - assert(DU.NarrowUse->getOperand(1 - ExtendOperIdx) == DU.NarrowDef && - "bad DU"); - - const SCEV *ExtendOperExpr = nullptr; - const OverflowingBinaryOperator *OBO = - cast(NarrowUse); - ExtendKind ExtKind = getExtendKind(NarrowDef); - if (ExtKind == SignExtended && OBO->hasNoSignedWrap()) - ExtendOperExpr = SE->getSignExtendExpr( - SE->getSCEV(NarrowUse->getOperand(ExtendOperIdx)), WideType); - else if (ExtKind == ZeroExtended && OBO->hasNoUnsignedWrap()) - ExtendOperExpr = SE->getZeroExtendExpr( - SE->getSCEV(NarrowUse->getOperand(ExtendOperIdx)), WideType); - else - return false; - - // Verifying that Defining operand is an AddRec - const SCEV *Op1 = SE->getSCEV(WideDef); - const SCEVAddRecExpr *AddRecOp1 = dyn_cast(Op1); - if (!AddRecOp1 || AddRecOp1->getLoop() != L) - return false; - // Verifying that other operand is an Extend. - if (ExtKind == SignExtended) { - if (!isa(ExtendOperExpr)) - return false; - } else { - if (!isa(ExtendOperExpr)) - return false; - } - - if (ExtKind == SignExtended) { - for (Use &U : NarrowUse->uses()) { - SExtInst *User = dyn_cast(U.getUser()); - if (!User || User->getType() != WideType) - return false; - } - } else { // ExtKind == ZeroExtended - for (Use &U : NarrowUse->uses()) { - ZExtInst *User = dyn_cast(U.getUser()); - if (!User || User->getType() != WideType) - return false; - } - } - - return true; -} - -/// Special Case for widening with loop variant (see -/// WidenIV::widenWithVariant). This is the code generation part. -void WidenIV::widenWithVariantUseCodegen(NarrowIVDefUse DU) { - Instruction *NarrowUse = DU.NarrowUse; - Instruction *NarrowDef = DU.NarrowDef; - Instruction *WideDef = DU.WideDef; - - ExtendKind ExtKind = getExtendKind(NarrowDef); - - LLVM_DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *NarrowUse << "\n"); - - // Generating a widening use instruction. - Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(0), WideType, - ExtKind, NarrowUse); - Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) - ? WideDef - : createExtendInst(NarrowUse->getOperand(1), WideType, - ExtKind, NarrowUse); - - auto *NarrowBO = cast(NarrowUse); - auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, - NarrowBO->getName()); - IRBuilder<> Builder(NarrowUse); - Builder.Insert(WideBO); - WideBO->copyIRFlags(NarrowBO); - - assert(ExtKind != Unknown && "Unknown ExtKind not handled"); - - ExtendKindMap[NarrowUse] = ExtKind; - - for (Use &U : NarrowUse->uses()) { - Instruction *User = nullptr; - if (ExtKind == SignExtended) - User = dyn_cast(U.getUser()); - else - User = dyn_cast(U.getUser()); - if (User && User->getType() == WideType) { - LLVM_DEBUG(dbgs() << "INDVARS: eliminating " << *User << " replaced by " - << *WideBO << "\n"); - ++NumElimExt; - User->replaceAllUsesWith(WideBO); - DeadInsts.emplace_back(User); - } - } -} - -/// Determine whether an individual user of the narrow IV can be widened. If so, -/// return the wide clone of the user. -Instruction *WidenIV::widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter) { - assert(ExtendKindMap.count(DU.NarrowDef) && - "Should already know the kind of extension used to widen NarrowDef"); - - // Stop traversing the def-use chain at inner-loop phis or post-loop phis. - if (PHINode *UsePhi = dyn_cast(DU.NarrowUse)) { - if (LI->getLoopFor(UsePhi->getParent()) != L) { - // For LCSSA phis, sink the truncate outside the loop. - // After SimplifyCFG most loop exit targets have a single predecessor. - // Otherwise fall back to a truncate within the loop. - if (UsePhi->getNumOperands() != 1) - truncateIVUse(DU, DT, LI); - else { - // Widening the PHI requires us to insert a trunc. The logical place - // for this trunc is in the same BB as the PHI. This is not possible if - // the BB is terminated by a catchswitch. - if (isa(UsePhi->getParent()->getTerminator())) - return nullptr; - - PHINode *WidePhi = - PHINode::Create(DU.WideDef->getType(), 1, UsePhi->getName() + ".wide", - UsePhi); - WidePhi->addIncoming(DU.WideDef, UsePhi->getIncomingBlock(0)); - IRBuilder<> Builder(&*WidePhi->getParent()->getFirstInsertionPt()); - Value *Trunc = Builder.CreateTrunc(WidePhi, DU.NarrowDef->getType()); - UsePhi->replaceAllUsesWith(Trunc); - DeadInsts.emplace_back(UsePhi); - LLVM_DEBUG(dbgs() << "INDVARS: Widen lcssa phi " << *UsePhi << " to " - << *WidePhi << "\n"); - } - return nullptr; - } - } - - // This narrow use can be widened by a sext if it's non-negative or its narrow - // def was widended by a sext. Same for zext. - auto canWidenBySExt = [&]() { - return DU.NeverNegative || getExtendKind(DU.NarrowDef) == SignExtended; - }; - auto canWidenByZExt = [&]() { - return DU.NeverNegative || getExtendKind(DU.NarrowDef) == ZeroExtended; - }; - - // Our raison d'etre! Eliminate sign and zero extension. - if ((isa(DU.NarrowUse) && canWidenBySExt()) || - (isa(DU.NarrowUse) && canWidenByZExt())) { - Value *NewDef = DU.WideDef; - if (DU.NarrowUse->getType() != WideType) { - unsigned CastWidth = SE->getTypeSizeInBits(DU.NarrowUse->getType()); - unsigned IVWidth = SE->getTypeSizeInBits(WideType); - if (CastWidth < IVWidth) { - // The cast isn't as wide as the IV, so insert a Trunc. - IRBuilder<> Builder(DU.NarrowUse); - NewDef = Builder.CreateTrunc(DU.WideDef, DU.NarrowUse->getType()); - } - else { - // A wider extend was hidden behind a narrower one. This may induce - // another round of IV widening in which the intermediate IV becomes - // dead. It should be very rare. - LLVM_DEBUG(dbgs() << "INDVARS: New IV " << *WidePhi - << " not wide enough to subsume " << *DU.NarrowUse - << "\n"); - DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef); - NewDef = DU.NarrowUse; - } - } - if (NewDef != DU.NarrowUse) { - LLVM_DEBUG(dbgs() << "INDVARS: eliminating " << *DU.NarrowUse - << " replaced by " << *DU.WideDef << "\n"); - ++NumElimExt; - DU.NarrowUse->replaceAllUsesWith(NewDef); - DeadInsts.emplace_back(DU.NarrowUse); - } - // Now that the extend is gone, we want to expose it's uses for potential - // further simplification. We don't need to directly inform SimplifyIVUsers - // of the new users, because their parent IV will be processed later as a - // new loop phi. If we preserved IVUsers analysis, we would also want to - // push the uses of WideDef here. - - // No further widening is needed. The deceased [sz]ext had done it for us. - return nullptr; - } - - // Does this user itself evaluate to a recurrence after widening? - WidenedRecTy WideAddRec = getExtendedOperandRecurrence(DU); - if (!WideAddRec.first) - WideAddRec = getWideRecurrence(DU); - - assert((WideAddRec.first == nullptr) == (WideAddRec.second == Unknown)); - if (!WideAddRec.first) { - // If use is a loop condition, try to promote the condition instead of - // truncating the IV first. - if (widenLoopCompare(DU)) - return nullptr; - - // We are here about to generate a truncate instruction that may hurt - // performance because the scalar evolution expression computed earlier - // in WideAddRec.first does not indicate a polynomial induction expression. - // In that case, look at the operands of the use instruction to determine - // if we can still widen the use instead of truncating its operand. - if (widenWithVariantUse(DU)) { - widenWithVariantUseCodegen(DU); - return nullptr; - } - - // This user does not evaluate to a recurrence after widening, so don't - // follow it. Instead insert a Trunc to kill off the original use, - // eventually isolating the original narrow IV so it can be removed. - truncateIVUse(DU, DT, LI); - return nullptr; - } - // Assume block terminators cannot evaluate to a recurrence. We can't to - // insert a Trunc after a terminator if there happens to be a critical edge. - assert(DU.NarrowUse != DU.NarrowUse->getParent()->getTerminator() && - "SCEV is not expected to evaluate a block terminator"); - - // Reuse the IV increment that SCEVExpander created as long as it dominates - // NarrowUse. - Instruction *WideUse = nullptr; - if (WideAddRec.first == WideIncExpr && - Rewriter.hoistIVInc(WideInc, DU.NarrowUse)) - WideUse = WideInc; - else { - WideUse = cloneIVUser(DU, WideAddRec.first); - if (!WideUse) - return nullptr; - } - // Evaluation of WideAddRec ensured that the narrow expression could be - // extended outside the loop without overflow. This suggests that the wide use - // evaluates to the same expression as the extended narrow use, but doesn't - // absolutely guarantee it. Hence the following failsafe check. In rare cases - // where it fails, we simply throw away the newly created wide use. - if (WideAddRec.first != SE->getSCEV(WideUse)) { - LLVM_DEBUG(dbgs() << "Wide use expression mismatch: " << *WideUse << ": " - << *SE->getSCEV(WideUse) << " != " << *WideAddRec.first - << "\n"); - DeadInsts.emplace_back(WideUse); - return nullptr; - } - - // if we reached this point then we are going to replace - // DU.NarrowUse with WideUse. Reattach DbgValue then. - replaceAllDbgUsesWith(*DU.NarrowUse, *WideUse, *WideUse, *DT); - - ExtendKindMap[DU.NarrowUse] = WideAddRec.second; - // Returning WideUse pushes it on the worklist. - return WideUse; -} - -/// Add eligible users of NarrowDef to NarrowIVUsers. -void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) { - const SCEV *NarrowSCEV = SE->getSCEV(NarrowDef); - bool NonNegativeDef = - SE->isKnownPredicate(ICmpInst::ICMP_SGE, NarrowSCEV, - SE->getConstant(NarrowSCEV->getType(), 0)); - for (User *U : NarrowDef->users()) { - Instruction *NarrowUser = cast(U); - - // Handle data flow merges and bizarre phi cycles. - if (!Widened.insert(NarrowUser).second) - continue; - - bool NonNegativeUse = false; - if (!NonNegativeDef) { - // We might have a control-dependent range information for this context. - if (auto RangeInfo = getPostIncRangeInfo(NarrowDef, NarrowUser)) - NonNegativeUse = RangeInfo->getSignedMin().isNonNegative(); - } - - NarrowIVUsers.emplace_back(NarrowDef, NarrowUser, WideDef, - NonNegativeDef || NonNegativeUse); - } -} - -/// Process a single induction variable. First use the SCEVExpander to create a -/// wide induction variable that evaluates to the same recurrence as the -/// original narrow IV. Then use a worklist to forward traverse the narrow IV's -/// def-use chain. After widenIVUse has processed all interesting IV users, the -/// narrow IV will be isolated for removal by DeleteDeadPHIs. -/// -/// It would be simpler to delete uses as they are processed, but we must avoid -/// invalidating SCEV expressions. -PHINode *WidenIV::createWideIV(SCEVExpander &Rewriter) { - // Is this phi an induction variable? - const SCEVAddRecExpr *AddRec = dyn_cast(SE->getSCEV(OrigPhi)); - if (!AddRec) - return nullptr; - - // Widen the induction variable expression. - const SCEV *WideIVExpr = getExtendKind(OrigPhi) == SignExtended - ? SE->getSignExtendExpr(AddRec, WideType) - : SE->getZeroExtendExpr(AddRec, WideType); - - assert(SE->getEffectiveSCEVType(WideIVExpr->getType()) == WideType && - "Expect the new IV expression to preserve its type"); - - // Can the IV be extended outside the loop without overflow? - AddRec = dyn_cast(WideIVExpr); - if (!AddRec || AddRec->getLoop() != L) - return nullptr; - - // An AddRec must have loop-invariant operands. Since this AddRec is - // materialized by a loop header phi, the expression cannot have any post-loop - // operands, so they must dominate the loop header. - assert( - SE->properlyDominates(AddRec->getStart(), L->getHeader()) && - SE->properlyDominates(AddRec->getStepRecurrence(*SE), L->getHeader()) && - "Loop header phi recurrence inputs do not dominate the loop"); - - // Iterate over IV uses (including transitive ones) looking for IV increments - // of the form 'add nsw %iv, '. For each increment and each use of - // the increment calculate control-dependent range information basing on - // dominating conditions inside of the loop (e.g. a range check inside of the - // loop). Calculated ranges are stored in PostIncRangeInfos map. - // - // Control-dependent range information is later used to prove that a narrow - // definition is not negative (see pushNarrowIVUsers). It's difficult to do - // this on demand because when pushNarrowIVUsers needs this information some - // of the dominating conditions might be already widened. - if (UsePostIncrementRanges) - calculatePostIncRanges(OrigPhi); - - // The rewriter provides a value for the desired IV expression. This may - // either find an existing phi or materialize a new one. Either way, we - // expect a well-formed cyclic phi-with-increments. i.e. any operand not part - // of the phi-SCC dominates the loop entry. - Instruction *InsertPt = &L->getHeader()->front(); - WidePhi = cast(Rewriter.expandCodeFor(AddRec, WideType, InsertPt)); - - // Remembering the WideIV increment generated by SCEVExpander allows - // widenIVUse to reuse it when widening the narrow IV's increment. We don't - // employ a general reuse mechanism because the call above is the only call to - // SCEVExpander. Henceforth, we produce 1-to-1 narrow to wide uses. - if (BasicBlock *LatchBlock = L->getLoopLatch()) { - WideInc = - cast(WidePhi->getIncomingValueForBlock(LatchBlock)); - WideIncExpr = SE->getSCEV(WideInc); - // Propagate the debug location associated with the original loop increment - // to the new (widened) increment. - auto *OrigInc = - cast(OrigPhi->getIncomingValueForBlock(LatchBlock)); - WideInc->setDebugLoc(OrigInc->getDebugLoc()); - } - - LLVM_DEBUG(dbgs() << "Wide IV: " << *WidePhi << "\n"); - ++NumWidened; - - // Traverse the def-use chain using a worklist starting at the original IV. - assert(Widened.empty() && NarrowIVUsers.empty() && "expect initial state" ); - - Widened.insert(OrigPhi); - pushNarrowIVUsers(OrigPhi, WidePhi); - - while (!NarrowIVUsers.empty()) { - NarrowIVDefUse DU = NarrowIVUsers.pop_back_val(); - - // Process a def-use edge. This may replace the use, so don't hold a - // use_iterator across it. - Instruction *WideUse = widenIVUse(DU, Rewriter); - - // Follow all def-use edges from the previous narrow use. - if (WideUse) - pushNarrowIVUsers(DU.NarrowUse, WideUse); - - // widenIVUse may have removed the def-use edge. - if (DU.NarrowDef->use_empty()) - DeadInsts.emplace_back(DU.NarrowDef); - } - - // Attach any debug information to the new PHI. - replaceAllDbgUsesWith(*OrigPhi, *WidePhi, *WidePhi, *DT); - - return WidePhi; -} - -/// Calculates control-dependent range for the given def at the given context -/// by looking at dominating conditions inside of the loop -void WidenIV::calculatePostIncRange(Instruction *NarrowDef, - Instruction *NarrowUser) { - using namespace llvm::PatternMatch; - - Value *NarrowDefLHS; - const APInt *NarrowDefRHS; - if (!match(NarrowDef, m_NSWAdd(m_Value(NarrowDefLHS), - m_APInt(NarrowDefRHS))) || - !NarrowDefRHS->isNonNegative()) - return; - - auto UpdateRangeFromCondition = [&] (Value *Condition, - bool TrueDest) { - CmpInst::Predicate Pred; - Value *CmpRHS; - if (!match(Condition, m_ICmp(Pred, m_Specific(NarrowDefLHS), - m_Value(CmpRHS)))) - return; - - CmpInst::Predicate P = - TrueDest ? Pred : CmpInst::getInversePredicate(Pred); - - auto CmpRHSRange = SE->getSignedRange(SE->getSCEV(CmpRHS)); - auto CmpConstrainedLHSRange = - ConstantRange::makeAllowedICmpRegion(P, CmpRHSRange); - auto NarrowDefRange = CmpConstrainedLHSRange.addWithNoWrap( - *NarrowDefRHS, OverflowingBinaryOperator::NoSignedWrap); - - updatePostIncRangeInfo(NarrowDef, NarrowUser, NarrowDefRange); - }; - - auto UpdateRangeFromGuards = [&](Instruction *Ctx) { - if (!HasGuards) - return; - - for (Instruction &I : make_range(Ctx->getIterator().getReverse(), - Ctx->getParent()->rend())) { - Value *C = nullptr; - if (match(&I, m_Intrinsic(m_Value(C)))) - UpdateRangeFromCondition(C, /*TrueDest=*/true); - } - }; - - UpdateRangeFromGuards(NarrowUser); - - BasicBlock *NarrowUserBB = NarrowUser->getParent(); - // If NarrowUserBB is statically unreachable asking dominator queries may - // yield surprising results. (e.g. the block may not have a dom tree node) - if (!DT->isReachableFromEntry(NarrowUserBB)) - return; - - for (auto *DTB = (*DT)[NarrowUserBB]->getIDom(); - L->contains(DTB->getBlock()); - DTB = DTB->getIDom()) { - auto *BB = DTB->getBlock(); - auto *TI = BB->getTerminator(); - UpdateRangeFromGuards(TI); - - auto *BI = dyn_cast(TI); - if (!BI || !BI->isConditional()) - continue; - - auto *TrueSuccessor = BI->getSuccessor(0); - auto *FalseSuccessor = BI->getSuccessor(1); - - auto DominatesNarrowUser = [this, NarrowUser] (BasicBlockEdge BBE) { - return BBE.isSingleEdge() && - DT->dominates(BBE, NarrowUser->getParent()); - }; - - if (DominatesNarrowUser(BasicBlockEdge(BB, TrueSuccessor))) - UpdateRangeFromCondition(BI->getCondition(), /*TrueDest=*/true); - - if (DominatesNarrowUser(BasicBlockEdge(BB, FalseSuccessor))) - UpdateRangeFromCondition(BI->getCondition(), /*TrueDest=*/false); - } -} - -/// Calculates PostIncRangeInfos map for the given IV -void WidenIV::calculatePostIncRanges(PHINode *OrigPhi) { - SmallPtrSet Visited; - SmallVector Worklist; - Worklist.push_back(OrigPhi); - Visited.insert(OrigPhi); - - while (!Worklist.empty()) { - Instruction *NarrowDef = Worklist.pop_back_val(); - - for (Use &U : NarrowDef->uses()) { - auto *NarrowUser = cast(U.getUser()); - - // Don't go looking outside the current loop. - auto *NarrowUserLoop = (*LI)[NarrowUser->getParent()]; - if (!NarrowUserLoop || !L->contains(NarrowUserLoop)) - continue; - - if (!Visited.insert(NarrowUser).second) - continue; - - Worklist.push_back(NarrowUser); - - calculatePostIncRange(NarrowDef, NarrowUser); - } - } -} - //===----------------------------------------------------------------------===// // Live IV Reduction - Minimize IVs live across the loop. //===----------------------------------------------------------------------===// @@ -1668,9 +631,18 @@ bool IndVarSimplify::simplifyAndExtend(Loop *L, } } while(!LoopPhis.empty()); + // Continue if we disallowed widening. + if (!WidenIndVars) + continue; + for (; !WideIVs.empty(); WideIVs.pop_back()) { - WidenIV Widener(WideIVs.back(), LI, SE, DT, DeadInsts, HasGuards); - if (PHINode *WidePhi = Widener.createWideIV(Rewriter)) { + unsigned ElimExt; + unsigned Widened; + if (PHINode *WidePhi = createWideIV(WideIVs.back(), LI, SE, Rewriter, + DT, DeadInsts, ElimExt, Widened, + HasGuards, UsePostIncrementRanges)) { + NumElimExt += ElimExt; + NumWidened += Widened; Changed = true; LoopPhis.push_back(WidePhi); } @@ -1813,7 +785,7 @@ static bool mustExecuteUBIfPoisonOnPathTo(Instruction *Root, // If we can't analyze propagation through this instruction, just skip it // and transitive users. Safe as false is a conservative result. - if (!propagatesPoison(I) && I != Root) + if (!propagatesPoison(cast(I)) && I != Root) continue; if (KnownPoison.insert(I).second) @@ -2318,42 +1290,116 @@ bool IndVarSimplify::sinkUnusedInvariants(Loop *L) { return MadeAnyChanges; } -/// Return a symbolic upper bound for the backedge taken count of the loop. -/// This is more general than getConstantMaxBackedgeTakenCount as it returns -/// an arbitrary expression as opposed to only constants. -/// TODO: Move into the ScalarEvolution class. -static const SCEV* getMaxBackedgeTakenCount(ScalarEvolution &SE, - DominatorTree &DT, Loop *L) { - SmallVector ExitingBlocks; - L->getExitingBlocks(ExitingBlocks); +static void replaceExitCond(BranchInst *BI, Value *NewCond, + SmallVectorImpl &DeadInsts) { + auto *OldCond = BI->getCondition(); + BI->setCondition(NewCond); + if (OldCond->use_empty()) + DeadInsts.emplace_back(OldCond); +} - // Form an expression for the maximum exit count possible for this loop. We - // merge the max and exact information to approximate a version of - // getConstantMaxBackedgeTakenCount which isn't restricted to just constants. - SmallVector ExitCounts; - for (BasicBlock *ExitingBB : ExitingBlocks) { - const SCEV *ExitCount = SE.getExitCount(L, ExitingBB); - if (isa(ExitCount)) - ExitCount = SE.getExitCount(L, ExitingBB, - ScalarEvolution::ConstantMaximum); - if (!isa(ExitCount)) { - assert(DT.dominates(ExitingBB, L->getLoopLatch()) && - "We should only have known counts for exiting blocks that " - "dominate latch!"); - ExitCounts.push_back(ExitCount); - } +static void foldExit(const Loop *L, BasicBlock *ExitingBB, bool IsTaken, + SmallVectorImpl &DeadInsts) { + BranchInst *BI = cast(ExitingBB->getTerminator()); + bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB)); + auto *OldCond = BI->getCondition(); + auto *NewCond = + ConstantInt::get(OldCond->getType(), IsTaken ? ExitIfTrue : !ExitIfTrue); + replaceExitCond(BI, NewCond, DeadInsts); +} + +static void replaceWithInvariantCond( + const Loop *L, BasicBlock *ExitingBB, ICmpInst::Predicate InvariantPred, + const SCEV *InvariantLHS, const SCEV *InvariantRHS, SCEVExpander &Rewriter, + SmallVectorImpl &DeadInsts) { + BranchInst *BI = cast(ExitingBB->getTerminator()); + Rewriter.setInsertPoint(BI); + auto *LHSV = Rewriter.expandCodeFor(InvariantLHS); + auto *RHSV = Rewriter.expandCodeFor(InvariantRHS); + bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB)); + if (ExitIfTrue) + InvariantPred = ICmpInst::getInversePredicate(InvariantPred); + IRBuilder<> Builder(BI); + auto *NewCond = Builder.CreateICmp(InvariantPred, LHSV, RHSV, + BI->getCondition()->getName()); + replaceExitCond(BI, NewCond, DeadInsts); +} + +static bool optimizeLoopExitWithUnknownExitCount( + const Loop *L, BranchInst *BI, BasicBlock *ExitingBB, + const SCEV *MaxIter, bool Inverted, bool SkipLastIter, + ScalarEvolution *SE, SCEVExpander &Rewriter, + SmallVectorImpl &DeadInsts) { + ICmpInst::Predicate Pred; + Value *LHS, *RHS; + using namespace PatternMatch; + BasicBlock *TrueSucc, *FalseSucc; + if (!match(BI, m_Br(m_ICmp(Pred, m_Value(LHS), m_Value(RHS)), + m_BasicBlock(TrueSucc), m_BasicBlock(FalseSucc)))) + return false; + + assert((L->contains(TrueSucc) != L->contains(FalseSucc)) && + "Not a loop exit!"); + + // 'LHS pred RHS' should now mean that we stay in loop. + if (L->contains(FalseSucc)) + Pred = CmpInst::getInversePredicate(Pred); + + // If we are proving loop exit, invert the predicate. + if (Inverted) + Pred = CmpInst::getInversePredicate(Pred); + + const SCEV *LHSS = SE->getSCEVAtScope(LHS, L); + const SCEV *RHSS = SE->getSCEVAtScope(RHS, L); + // Can we prove it to be trivially true? + if (SE->isKnownPredicateAt(Pred, LHSS, RHSS, BI)) { + foldExit(L, ExitingBB, Inverted, DeadInsts); + return true; + } + // Further logic works for non-inverted condition only. + if (Inverted) + return false; + + auto *ARTy = LHSS->getType(); + auto *MaxIterTy = MaxIter->getType(); + // If possible, adjust types. + if (SE->getTypeSizeInBits(ARTy) > SE->getTypeSizeInBits(MaxIterTy)) + MaxIter = SE->getZeroExtendExpr(MaxIter, ARTy); + else if (SE->getTypeSizeInBits(ARTy) < SE->getTypeSizeInBits(MaxIterTy)) { + const SCEV *MinusOne = SE->getMinusOne(ARTy); + auto *MaxAllowedIter = SE->getZeroExtendExpr(MinusOne, MaxIterTy); + if (SE->isKnownPredicateAt(ICmpInst::ICMP_ULE, MaxIter, MaxAllowedIter, BI)) + MaxIter = SE->getTruncateExpr(MaxIter, ARTy); + } + + if (SkipLastIter) { + const SCEV *One = SE->getOne(MaxIter->getType()); + MaxIter = SE->getMinusSCEV(MaxIter, One); } - if (ExitCounts.empty()) - return SE.getCouldNotCompute(); - return SE.getUMinFromMismatchedTypes(ExitCounts); + + // Check if there is a loop-invariant predicate equivalent to our check. + auto LIP = SE->getLoopInvariantExitCondDuringFirstIterations(Pred, LHSS, RHSS, + L, BI, MaxIter); + if (!LIP) + return false; + + // Can we prove it to be trivially true? + if (SE->isKnownPredicateAt(LIP->Pred, LIP->LHS, LIP->RHS, BI)) + foldExit(L, ExitingBB, Inverted, DeadInsts); + else + replaceWithInvariantCond(L, ExitingBB, LIP->Pred, LIP->LHS, LIP->RHS, + Rewriter, DeadInsts); + + return true; } bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); - // Remove all exits which aren't both rewriteable and analyzeable. - auto NewEnd = llvm::remove_if(ExitingBlocks, [&](BasicBlock *ExitingBB) { + // Remove all exits which aren't both rewriteable and execute on every + // iteration. + llvm::erase_if(ExitingBlocks, [&](BasicBlock *ExitingBB) { // If our exitting block exits multiple loops, we can only rewrite the // innermost one. Otherwise, we're changing how many times the innermost // loop runs before it exits. @@ -2369,56 +1415,85 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { if (isa(BI->getCondition())) return true; - const SCEV *ExitCount = SE->getExitCount(L, ExitingBB); - if (isa(ExitCount)) + // Likewise, the loop latch must be dominated by the exiting BB. + if (!DT->dominates(ExitingBB, L->getLoopLatch())) return true; + return false; }); - ExitingBlocks.erase(NewEnd, ExitingBlocks.end()); if (ExitingBlocks.empty()) return false; // Get a symbolic upper bound on the loop backedge taken count. - const SCEV *MaxExitCount = getMaxBackedgeTakenCount(*SE, *DT, L); + const SCEV *MaxExitCount = SE->getSymbolicMaxBackedgeTakenCount(L); if (isa(MaxExitCount)) return false; - // Visit our exit blocks in order of dominance. We know from the fact that - // all exits (left) are analyzeable that the must be a total dominance order - // between them as each must dominate the latch. The visit order only - // matters for the provably equal case. - llvm::sort(ExitingBlocks, - [&](BasicBlock *A, BasicBlock *B) { + // Visit our exit blocks in order of dominance. We know from the fact that + // all exits must dominate the latch, so there is a total dominance order + // between them. + llvm::sort(ExitingBlocks, [&](BasicBlock *A, BasicBlock *B) { // std::sort sorts in ascending order, so we want the inverse of // the normal dominance relation. if (A == B) return false; - if (DT->properlyDominates(A, B)) return true; - if (DT->properlyDominates(B, A)) return false; - llvm_unreachable("expected total dominance order!"); - }); + if (DT->properlyDominates(A, B)) + return true; + else { + assert(DT->properlyDominates(B, A) && + "expected total dominance order!"); + return false; + } + }); #ifdef ASSERT for (unsigned i = 1; i < ExitingBlocks.size(); i++) { assert(DT->dominates(ExitingBlocks[i-1], ExitingBlocks[i])); } #endif - auto FoldExit = [&](BasicBlock *ExitingBB, bool IsTaken) { - BranchInst *BI = cast(ExitingBB->getTerminator()); - bool ExitIfTrue = !L->contains(*succ_begin(ExitingBB)); - auto *OldCond = BI->getCondition(); - auto *NewCond = ConstantInt::get(OldCond->getType(), - IsTaken ? ExitIfTrue : !ExitIfTrue); - BI->setCondition(NewCond); - if (OldCond->use_empty()) - DeadInsts.emplace_back(OldCond); - }; - bool Changed = false; + bool SkipLastIter = false; SmallSet DominatingExitCounts; for (BasicBlock *ExitingBB : ExitingBlocks) { const SCEV *ExitCount = SE->getExitCount(L, ExitingBB); - assert(!isa(ExitCount) && "checked above"); + if (isa(ExitCount)) { + // Okay, we do not know the exit count here. Can we at least prove that it + // will remain the same within iteration space? + auto *BI = cast(ExitingBB->getTerminator()); + auto OptimizeCond = [&](bool Inverted, bool SkipLastIter) { + return optimizeLoopExitWithUnknownExitCount( + L, BI, ExitingBB, MaxExitCount, Inverted, SkipLastIter, SE, + Rewriter, DeadInsts); + }; + + // TODO: We might have proved that we can skip the last iteration for + // this check. In this case, we only want to check the condition on the + // pre-last iteration (MaxExitCount - 1). However, there is a nasty + // corner case: + // + // for (i = len; i != 0; i--) { ... check (i ult X) ... } + // + // If we could not prove that len != 0, then we also could not prove that + // (len - 1) is not a UINT_MAX. If we simply query (len - 1), then + // OptimizeCond will likely not prove anything for it, even if it could + // prove the same fact for len. + // + // As a temporary solution, we query both last and pre-last iterations in + // hope that we will be able to prove triviality for at least one of + // them. We can stop querying MaxExitCount for this case once SCEV + // understands that (MaxExitCount - 1) will not overflow here. + if (OptimizeCond(false, false) || OptimizeCond(true, false)) + Changed = true; + else if (SkipLastIter) + if (OptimizeCond(false, true) || OptimizeCond(true, true)) + Changed = true; + continue; + } + + if (MaxExitCount == ExitCount) + // If the loop has more than 1 iteration, all further checks will be + // executed 1 iteration less. + SkipLastIter = true; // If we know we'd exit on the first iteration, rewrite the exit to // reflect this. This does not imply the loop must exit through this @@ -2426,7 +1501,7 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { // TODO: Given we know the backedge can't be taken, we should go ahead // and break it. Or at least, kill all the header phis and simplify. if (ExitCount->isZero()) { - FoldExit(ExitingBB, true); + foldExit(L, ExitingBB, true, DeadInsts); Changed = true; continue; } @@ -2448,7 +1523,7 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { // one? if (SE->isLoopEntryGuardedByCond(L, CmpInst::ICMP_ULT, MaxExitCount, ExitCount)) { - FoldExit(ExitingBB, false); + foldExit(L, ExitingBB, false, DeadInsts); Changed = true; continue; } @@ -2458,7 +1533,7 @@ bool IndVarSimplify::optimizeLoopExits(Loop *L, SCEVExpander &Rewriter) { // exiting iteration, but (from the visit order) strictly follows another // which does the same and is thus dead. if (!DominatingExitCounts.insert(ExitCount).second) { - FoldExit(ExitingBB, false); + foldExit(L, ExitingBB, false, DeadInsts); Changed = true; continue; } @@ -2714,7 +1789,9 @@ bool IndVarSimplify::run(Loop *L) { if (optimizeLoopExits(L, Rewriter)) { Changed = true; // Given we've changed exit counts, notify SCEV - SE->forgetLoop(L); + // Some nested loops may share same folded exit basic block, + // thus we need to notify top most loop. + SE->forgetTopmostLoop(L); } // Try to form loop invariant tests for loop exits by changing how many @@ -2791,11 +1868,15 @@ bool IndVarSimplify::run(Loop *L) { // Now that we're done iterating through lists, clean up any instructions // which are now dead. - while (!DeadInsts.empty()) - if (Instruction *Inst = - dyn_cast_or_null(DeadInsts.pop_back_val())) + while (!DeadInsts.empty()) { + Value *V = DeadInsts.pop_back_val(); + + if (PHINode *PHI = dyn_cast_or_null(V)) + Changed |= RecursivelyDeleteDeadPHINode(PHI, TLI, MSSAU.get()); + else if (Instruction *Inst = dyn_cast_or_null(V)) Changed |= RecursivelyDeleteTriviallyDeadInstructions(Inst, TLI, MSSAU.get()); + } // The Rewriter may not be used from this point on. @@ -2845,7 +1926,8 @@ PreservedAnalyses IndVarSimplifyPass::run(Loop &L, LoopAnalysisManager &AM, Function *F = L.getHeader()->getParent(); const DataLayout &DL = F->getParent()->getDataLayout(); - IndVarSimplify IVS(&AR.LI, &AR.SE, &AR.DT, DL, &AR.TLI, &AR.TTI, AR.MSSA); + IndVarSimplify IVS(&AR.LI, &AR.SE, &AR.DT, DL, &AR.TLI, &AR.TTI, AR.MSSA, + WidenIndVars && AllowIVWidening); if (!IVS.run(&L)) return PreservedAnalyses::all(); @@ -2882,7 +1964,7 @@ struct IndVarSimplifyLegacyPass : public LoopPass { if (MSSAAnalysis) MSSA = &MSSAAnalysis->getMSSA(); - IndVarSimplify IVS(LI, SE, DT, DL, TLI, TTI, MSSA); + IndVarSimplify IVS(LI, SE, DT, DL, TLI, TTI, MSSA, AllowIVWidening); return IVS.run(L); } diff --git a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp index 30e4822b6769..6e09dec198c2 100644 --- a/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp +++ b/llvm/lib/Transforms/Scalar/InductiveRangeCheckElimination.cpp @@ -52,6 +52,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/LoopAnalysisManager.h" #include "llvm/Analysis/LoopInfo.h" @@ -109,12 +110,12 @@ static cl::opt PrintChangedLoops("irce-print-changed-loops", cl::Hidden, static cl::opt PrintRangeChecks("irce-print-range-checks", cl::Hidden, cl::init(false)); -static cl::opt MaxExitProbReciprocal("irce-max-exit-prob-reciprocal", - cl::Hidden, cl::init(10)); - static cl::opt SkipProfitabilityChecks("irce-skip-profitability-checks", cl::Hidden, cl::init(false)); +static cl::opt MinRuntimeIterations("irce-min-runtime-iterations", + cl::Hidden, cl::init(10)); + static cl::opt AllowUnsignedLatchCondition("irce-allow-unsigned-latch", cl::Hidden, cl::init(true)); @@ -145,7 +146,6 @@ class InductiveRangeCheck { const SCEV *Step = nullptr; const SCEV *End = nullptr; Use *CheckUse = nullptr; - bool IsSigned = true; static bool parseRangeCheckICmp(Loop *L, ICmpInst *ICI, ScalarEvolution &SE, Value *&Index, Value *&Length, @@ -160,7 +160,6 @@ public: const SCEV *getBegin() const { return Begin; } const SCEV *getStep() const { return Step; } const SCEV *getEnd() const { return End; } - bool isSigned() const { return IsSigned; } void print(raw_ostream &OS) const { OS << "InductiveRangeCheck:\n"; @@ -229,17 +228,27 @@ public: SmallVectorImpl &Checks); }; +struct LoopStructure; + class InductiveRangeCheckElimination { ScalarEvolution &SE; BranchProbabilityInfo *BPI; DominatorTree &DT; LoopInfo &LI; + using GetBFIFunc = + llvm::Optional >; + GetBFIFunc GetBFI; + + // Returns true if it is profitable to do a transform basing on estimation of + // number of iterations. + bool isProfitableToTransform(const Loop &L, LoopStructure &LS); + public: InductiveRangeCheckElimination(ScalarEvolution &SE, BranchProbabilityInfo *BPI, DominatorTree &DT, - LoopInfo &LI) - : SE(SE), BPI(BPI), DT(DT), LI(LI) {} + LoopInfo &LI, GetBFIFunc GetBFI = None) + : SE(SE), BPI(BPI), DT(DT), LI(LI), GetBFI(GetBFI) {} bool run(Loop *L, function_ref LPMAddNewLoop); }; @@ -394,7 +403,6 @@ void InductiveRangeCheck::extractRangeChecksFromCond( IRC.Begin = IndexAddRec->getStart(); IRC.Step = IndexAddRec->getStepRecurrence(SE); IRC.CheckUse = &ConditionUse; - IRC.IsSigned = IsSigned; Checks.push_back(IRC); } @@ -497,9 +505,8 @@ struct LoopStructure { return Result; } - static Optional parseLoopStructure(ScalarEvolution &, - BranchProbabilityInfo *BPI, - Loop &, const char *&); + static Optional parseLoopStructure(ScalarEvolution &, Loop &, + const char *&); }; /// This class is used to constrain loops to run within a given iteration space. @@ -743,8 +750,7 @@ static bool isSafeIncreasingBound(const SCEV *Start, } Optional -LoopStructure::parseLoopStructure(ScalarEvolution &SE, - BranchProbabilityInfo *BPI, Loop &L, +LoopStructure::parseLoopStructure(ScalarEvolution &SE, Loop &L, const char *&FailureReason) { if (!L.isLoopSimplifyForm()) { FailureReason = "loop not in LoopSimplify form"; @@ -779,16 +785,6 @@ LoopStructure::parseLoopStructure(ScalarEvolution &SE, unsigned LatchBrExitIdx = LatchBr->getSuccessor(0) == Header ? 1 : 0; - BranchProbability ExitProbability = - BPI ? BPI->getEdgeProbability(LatchBr->getParent(), LatchBrExitIdx) - : BranchProbability::getZero(); - - if (!SkipProfitabilityChecks && - ExitProbability > BranchProbability(1, MaxExitProbReciprocal)) { - FailureReason = "short running loop, not profitable"; - return None; - } - ICmpInst *ICI = dyn_cast(LatchBr->getCondition()); if (!ICI || !isa(ICI->getOperand(0)->getType())) { FailureReason = "latch terminator branch not conditional on integral icmp"; @@ -1772,14 +1768,25 @@ PreservedAnalyses IRCEPass::run(Function &F, FunctionAnalysisManager &AM) { auto &BPI = AM.getResult(F); LoopInfo &LI = AM.getResult(F); - InductiveRangeCheckElimination IRCE(SE, &BPI, DT, LI); + // Get BFI analysis result on demand. Please note that modification of + // CFG invalidates this analysis and we should handle it. + auto getBFI = [&F, &AM ]()->BlockFrequencyInfo & { + return AM.getResult(F); + }; + InductiveRangeCheckElimination IRCE(SE, &BPI, DT, LI, { getBFI }); bool Changed = false; + { + bool CFGChanged = false; + for (const auto &L : LI) { + CFGChanged |= simplifyLoop(L, &DT, &LI, &SE, nullptr, nullptr, + /*PreserveLCSSA=*/false); + Changed |= formLCSSARecursively(*L, DT, &LI, &SE); + } + Changed |= CFGChanged; - for (const auto &L : LI) { - Changed |= simplifyLoop(L, &DT, &LI, &SE, nullptr, nullptr, - /*PreserveLCSSA=*/false); - Changed |= formLCSSARecursively(*L, DT, &LI, &SE); + if (CFGChanged && !SkipProfitabilityChecks) + AM.invalidate(F); } SmallPriorityWorklist Worklist; @@ -1791,7 +1798,11 @@ PreservedAnalyses IRCEPass::run(Function &F, FunctionAnalysisManager &AM) { while (!Worklist.empty()) { Loop *L = Worklist.pop_back_val(); - Changed |= IRCE.run(L, LPMAddNewLoop); + if (IRCE.run(L, LPMAddNewLoop)) { + Changed = true; + if (!SkipProfitabilityChecks) + AM.invalidate(F); + } } if (!Changed) @@ -1832,6 +1843,37 @@ bool IRCELegacyPass::runOnFunction(Function &F) { return Changed; } +bool +InductiveRangeCheckElimination::isProfitableToTransform(const Loop &L, + LoopStructure &LS) { + if (SkipProfitabilityChecks) + return true; + if (GetBFI.hasValue()) { + BlockFrequencyInfo &BFI = (*GetBFI)(); + uint64_t hFreq = BFI.getBlockFreq(LS.Header).getFrequency(); + uint64_t phFreq = BFI.getBlockFreq(L.getLoopPreheader()).getFrequency(); + if (phFreq != 0 && hFreq != 0 && (hFreq / phFreq < MinRuntimeIterations)) { + LLVM_DEBUG(dbgs() << "irce: could not prove profitability: " + << "the estimated number of iterations basing on " + "frequency info is " << (hFreq / phFreq) << "\n";); + return false; + } + return true; + } + + if (!BPI) + return true; + BranchProbability ExitProbability = + BPI->getEdgeProbability(LS.Latch, LS.LatchBrExitIdx); + if (ExitProbability > BranchProbability(1, MinRuntimeIterations)) { + LLVM_DEBUG(dbgs() << "irce: could not prove profitability: " + << "the exit probability is too big " << ExitProbability + << "\n";); + return false; + } + return true; +} + bool InductiveRangeCheckElimination::run( Loop *L, function_ref LPMAddNewLoop) { if (L->getBlocks().size() >= LoopSizeCutoff) { @@ -1871,13 +1913,15 @@ bool InductiveRangeCheckElimination::run( const char *FailureReason = nullptr; Optional MaybeLoopStructure = - LoopStructure::parseLoopStructure(SE, BPI, *L, FailureReason); + LoopStructure::parseLoopStructure(SE, *L, FailureReason); if (!MaybeLoopStructure.hasValue()) { LLVM_DEBUG(dbgs() << "irce: could not parse loop structure: " << FailureReason << "\n";); return false; } LoopStructure LS = MaybeLoopStructure.getValue(); + if (!isProfitableToTransform(*L, LS)) + return false; const SCEVAddRecExpr *IndVar = cast(SE.getMinusSCEV(SE.getSCEV(LS.IndVarBase), SE.getSCEV(LS.IndVarStep))); diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp index db9cc58bbfc4..332eb10ac16b 100644 --- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp +++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp @@ -88,6 +88,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/InferAddressSpaces.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" @@ -108,6 +109,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Operator.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" #include "llvm/IR/User.h" @@ -146,13 +148,7 @@ namespace { using ValueToAddrSpaceMapTy = DenseMap; using PostorderStackTy = llvm::SmallVector, 4>; -/// InferAddressSpaces class InferAddressSpaces : public FunctionPass { - const TargetTransformInfo *TTI = nullptr; - const DataLayout *DL = nullptr; - - /// Target specific address space which uses of should be replaced if - /// possible. unsigned FlatAddrSpace = 0; public: @@ -168,8 +164,16 @@ public: } bool runOnFunction(Function &F) override; +}; + +class InferAddressSpacesImpl { + const TargetTransformInfo *TTI = nullptr; + const DataLayout *DL = nullptr; + + /// Target specific address space which uses of should be replaced if + /// possible. + unsigned FlatAddrSpace = 0; -private: // Returns the new address space of V if updated; otherwise, returns None. Optional updateAddressSpace(const Value &V, @@ -211,6 +215,11 @@ private: const ValueToValueMapTy &ValueWithNewAddrSpace, SmallVectorImpl *UndefUsesToFix) const; unsigned joinAddressSpaces(unsigned AS1, unsigned AS2) const; + +public: + InferAddressSpacesImpl(const TargetTransformInfo *TTI, unsigned FlatAddrSpace) + : TTI(TTI), FlatAddrSpace(FlatAddrSpace) {} + bool run(Function &F); }; } // end anonymous namespace @@ -286,7 +295,8 @@ static bool isAddressExpression(const Value &V, const DataLayout &DL, case Instruction::IntToPtr: return isNoopPtrIntCastPair(Op, DL, TTI); default: - return false; + // That value is an address expression if it has an assumed address space. + return TTI->getAssumedAddrSpace(&V) != UninitializedAddressSpace; } } @@ -325,9 +335,9 @@ getPointerOperands(const Value &V, const DataLayout &DL, } } -bool InferAddressSpaces::rewriteIntrinsicOperands(IntrinsicInst *II, - Value *OldV, - Value *NewV) const { +bool InferAddressSpacesImpl::rewriteIntrinsicOperands(IntrinsicInst *II, + Value *OldV, + Value *NewV) const { Module *M = II->getParent()->getParent()->getParent(); switch (II->getIntrinsicID()) { @@ -354,7 +364,7 @@ bool InferAddressSpaces::rewriteIntrinsicOperands(IntrinsicInst *II, } } -void InferAddressSpaces::collectRewritableIntrinsicOperands( +void InferAddressSpacesImpl::collectRewritableIntrinsicOperands( IntrinsicInst *II, PostorderStackTy &PostorderStack, DenseSet &Visited) const { auto IID = II->getIntrinsicID(); @@ -379,7 +389,7 @@ void InferAddressSpaces::collectRewritableIntrinsicOperands( // Returns all flat address expressions in function F. The elements are // If V is an unvisited flat address expression, appends V to PostorderStack // and marks it as visited. -void InferAddressSpaces::appendsFlatAddressExpressionToPostorderStack( +void InferAddressSpacesImpl::appendsFlatAddressExpressionToPostorderStack( Value *V, PostorderStackTy &PostorderStack, DenseSet &Visited) const { assert(V->getType()->isPointerTy()); @@ -394,8 +404,8 @@ void InferAddressSpaces::appendsFlatAddressExpressionToPostorderStack( return; } - if (isAddressExpression(*V, *DL, TTI) && - V->getType()->getPointerAddressSpace() == FlatAddrSpace) { + if (V->getType()->getPointerAddressSpace() == FlatAddrSpace && + isAddressExpression(*V, *DL, TTI)) { if (Visited.insert(V).second) { PostorderStack.emplace_back(V, false); @@ -413,7 +423,7 @@ void InferAddressSpaces::appendsFlatAddressExpressionToPostorderStack( // Returns all flat address expressions in function F. The elements are ordered // ordered in postorder. std::vector -InferAddressSpaces::collectFlatAddressExpressions(Function &F) const { +InferAddressSpacesImpl::collectFlatAddressExpressions(Function &F) const { // This function implements a non-recursive postorder traversal of a partial // use-def graph of function F. PostorderStackTy PostorderStack; @@ -478,9 +488,12 @@ InferAddressSpaces::collectFlatAddressExpressions(Function &F) const { } // Otherwise, adds its operands to the stack and explores them. PostorderStack.back().setInt(true); - for (Value *PtrOperand : getPointerOperands(*TopVal, *DL, TTI)) { - appendsFlatAddressExpressionToPostorderStack(PtrOperand, PostorderStack, - Visited); + // Skip values with an assumed address space. + if (TTI->getAssumedAddrSpace(TopVal) == UninitializedAddressSpace) { + for (Value *PtrOperand : getPointerOperands(*TopVal, *DL, TTI)) { + appendsFlatAddressExpressionToPostorderStack(PtrOperand, PostorderStack, + Visited); + } } } return Postorder; @@ -520,7 +533,7 @@ static Value *operandWithNewAddressSpaceOrCreateUndef( // // This may also return nullptr in the case the instruction could not be // rewritten. -Value *InferAddressSpaces::cloneInstructionWithNewAddressSpace( +Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace( Instruction *I, unsigned NewAddrSpace, const ValueToValueMapTy &ValueWithNewAddrSpace, SmallVectorImpl *UndefUsesToFix) const { @@ -555,6 +568,16 @@ Value *InferAddressSpaces::cloneInstructionWithNewAddressSpace( return nullptr; } + unsigned AS = TTI->getAssumedAddrSpace(I); + if (AS != UninitializedAddressSpace) { + // For the assumed address space, insert an `addrspacecast` to make that + // explicit. + auto *NewPtrTy = I->getType()->getPointerElementType()->getPointerTo(AS); + auto *NewI = new AddrSpaceCastInst(I, NewPtrTy); + NewI->insertAfter(I); + return NewI; + } + // Computes the converted pointer operands. SmallVector NewPointerOperands; for (const Use &OperandUse : I->operands()) { @@ -583,7 +606,7 @@ Value *InferAddressSpaces::cloneInstructionWithNewAddressSpace( GetElementPtrInst *GEP = cast(I); GetElementPtrInst *NewGEP = GetElementPtrInst::Create( GEP->getSourceElementType(), NewPointerOperands[0], - SmallVector(GEP->idx_begin(), GEP->idx_end())); + SmallVector(GEP->indices())); NewGEP->setIsInBounds(GEP->isInBounds()); return NewGEP; } @@ -695,13 +718,13 @@ static Value *cloneConstantExprWithNewAddressSpace( // expression whose address space needs to be modified, in postorder. // // See cloneInstructionWithNewAddressSpace for the meaning of UndefUsesToFix. -Value *InferAddressSpaces::cloneValueWithNewAddressSpace( - Value *V, unsigned NewAddrSpace, - const ValueToValueMapTy &ValueWithNewAddrSpace, - SmallVectorImpl *UndefUsesToFix) const { +Value *InferAddressSpacesImpl::cloneValueWithNewAddressSpace( + Value *V, unsigned NewAddrSpace, + const ValueToValueMapTy &ValueWithNewAddrSpace, + SmallVectorImpl *UndefUsesToFix) const { // All values in Postorder are flat address expressions. - assert(isAddressExpression(*V, *DL, TTI) && - V->getType()->getPointerAddressSpace() == FlatAddrSpace); + assert(V->getType()->getPointerAddressSpace() == FlatAddrSpace && + isAddressExpression(*V, *DL, TTI)); if (Instruction *I = dyn_cast(V)) { Value *NewV = cloneInstructionWithNewAddressSpace( @@ -721,8 +744,8 @@ Value *InferAddressSpaces::cloneValueWithNewAddressSpace( // Defines the join operation on the address space lattice (see the file header // comments). -unsigned InferAddressSpaces::joinAddressSpaces(unsigned AS1, - unsigned AS2) const { +unsigned InferAddressSpacesImpl::joinAddressSpaces(unsigned AS1, + unsigned AS2) const { if (AS1 == FlatAddrSpace || AS2 == FlatAddrSpace) return FlatAddrSpace; @@ -735,11 +758,7 @@ unsigned InferAddressSpaces::joinAddressSpaces(unsigned AS1, return (AS1 == AS2) ? AS1 : FlatAddrSpace; } -bool InferAddressSpaces::runOnFunction(Function &F) { - if (skipFunction(F)) - return false; - - TTI = &getAnalysis().getTTI(F); +bool InferAddressSpacesImpl::run(Function &F) { DL = &F.getParent()->getDataLayout(); if (AssumeDefaultIsFlatAddressSpace) @@ -766,7 +785,7 @@ bool InferAddressSpaces::runOnFunction(Function &F) { // Constants need to be tracked through RAUW to handle cases with nested // constant expressions, so wrap values in WeakTrackingVH. -void InferAddressSpaces::inferAddressSpaces( +void InferAddressSpacesImpl::inferAddressSpaces( ArrayRef Postorder, ValueToAddrSpaceMapTy *InferredAddrSpace) const { SetVector Worklist(Postorder.begin(), Postorder.end()); @@ -810,7 +829,7 @@ void InferAddressSpaces::inferAddressSpaces( } } -Optional InferAddressSpaces::updateAddressSpace( +Optional InferAddressSpacesImpl::updateAddressSpace( const Value &V, const ValueToAddrSpaceMapTy &InferredAddrSpace) const { assert(InferredAddrSpace.count(&V)); @@ -848,15 +867,24 @@ Optional InferAddressSpaces::updateAddressSpace( else NewAS = joinAddressSpaces(Src0AS, Src1AS); } else { - for (Value *PtrOperand : getPointerOperands(V, *DL, TTI)) { - auto I = InferredAddrSpace.find(PtrOperand); - unsigned OperandAS = I != InferredAddrSpace.end() ? - I->second : PtrOperand->getType()->getPointerAddressSpace(); - - // join(flat, *) = flat. So we can break if NewAS is already flat. - NewAS = joinAddressSpaces(NewAS, OperandAS); - if (NewAS == FlatAddrSpace) - break; + unsigned AS = TTI->getAssumedAddrSpace(&V); + if (AS != UninitializedAddressSpace) { + // Use the assumed address space directly. + NewAS = AS; + } else { + // Otherwise, infer the address space from its pointer operands. + for (Value *PtrOperand : getPointerOperands(V, *DL, TTI)) { + auto I = InferredAddrSpace.find(PtrOperand); + unsigned OperandAS = + I != InferredAddrSpace.end() + ? I->second + : PtrOperand->getType()->getPointerAddressSpace(); + + // join(flat, *) = flat. So we can break if NewAS is already flat. + NewAS = joinAddressSpaces(NewAS, OperandAS); + if (NewAS == FlatAddrSpace) + break; + } } } @@ -947,7 +975,8 @@ static bool handleMemIntrinsicPtrUse(MemIntrinsic *MI, Value *OldV, // \p returns true if it is OK to change the address space of constant \p C with // a ConstantExpr addrspacecast. -bool InferAddressSpaces::isSafeToCastConstAddrSpace(Constant *C, unsigned NewAS) const { +bool InferAddressSpacesImpl::isSafeToCastConstAddrSpace(Constant *C, + unsigned NewAS) const { assert(NewAS != UninitializedAddressSpace); unsigned SrcAS = C->getType()->getPointerAddressSpace(); @@ -986,7 +1015,7 @@ static Value::use_iterator skipToNextUser(Value::use_iterator I, return I; } -bool InferAddressSpaces::rewriteWithNewAddressSpaces( +bool InferAddressSpacesImpl::rewriteWithNewAddressSpaces( const TargetTransformInfo &TTI, ArrayRef Postorder, const ValueToAddrSpaceMapTy &InferredAddrSpace, Function *F) const { // For each address expression to be modified, creates a clone of it with its @@ -997,6 +1026,12 @@ bool InferAddressSpaces::rewriteWithNewAddressSpaces( SmallVector UndefUsesToFix; for (Value* V : Postorder) { unsigned NewAddrSpace = InferredAddrSpace.lookup(V); + + // In some degenerate cases (e.g. invalid IR in unreachable code), we may + // not even infer the value to have its original address space. + if (NewAddrSpace == UninitializedAddressSpace) + continue; + if (V->getType()->getPointerAddressSpace() != NewAddrSpace) { Value *New = cloneValueWithNewAddressSpace( V, NewAddrSpace, ValueWithNewAddrSpace, &UndefUsesToFix); @@ -1062,6 +1097,9 @@ bool InferAddressSpaces::rewriteWithNewAddressSpaces( } User *CurUser = U.getUser(); + // Skip if the current user is the new value itself. + if (CurUser == NewV) + continue; // Handle more complex cases like intrinsic that need to be remangled. if (auto *MI = dyn_cast(CurUser)) { if (!MI->isVolatile() && handleMemIntrinsicPtrUse(MI, V, NewV)) @@ -1148,6 +1186,34 @@ bool InferAddressSpaces::rewriteWithNewAddressSpaces( return true; } +bool InferAddressSpaces::runOnFunction(Function &F) { + if (skipFunction(F)) + return false; + + return InferAddressSpacesImpl( + &getAnalysis().getTTI(F), + FlatAddrSpace) + .run(F); +} + FunctionPass *llvm::createInferAddressSpacesPass(unsigned AddressSpace) { return new InferAddressSpaces(AddressSpace); } + +InferAddressSpacesPass::InferAddressSpacesPass() + : FlatAddrSpace(UninitializedAddressSpace) {} +InferAddressSpacesPass::InferAddressSpacesPass(unsigned AddressSpace) + : FlatAddrSpace(AddressSpace) {} + +PreservedAnalyses InferAddressSpacesPass::run(Function &F, + FunctionAnalysisManager &AM) { + bool Changed = + InferAddressSpacesImpl(&AM.getResult(F), FlatAddrSpace) + .run(F); + if (Changed) { + PreservedAnalyses PA; + PA.preserveSet(); + return PA; + } + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp b/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp index e87b622ab19f..c11d2e4c1d6b 100644 --- a/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp +++ b/llvm/lib/Transforms/Scalar/InstSimplifyPass.cpp @@ -20,8 +20,10 @@ #include "llvm/IR/Type.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" +#include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/Local.h" + using namespace llvm; #define DEBUG_TYPE "instsimplify" diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp index 9d0500419a7f..96aef90c1c1a 100644 --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -32,6 +32,7 @@ #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" @@ -104,6 +105,11 @@ static cl::opt PrintLVIAfterJumpThreading( cl::desc("Print the LazyValueInfo cache after JumpThreading"), cl::init(false), cl::Hidden); +static cl::opt JumpThreadingFreezeSelectCond( + "jump-threading-freeze-select-cond", + cl::desc("Freeze the condition when unfolding select"), cl::init(false), + cl::Hidden); + static cl::opt ThreadAcrossLoopHeaders( "jump-threading-across-loop-headers", cl::desc("Allow JumpThreading to thread across loop headers, for testing"), @@ -133,7 +139,8 @@ namespace { public: static char ID; // Pass identification - JumpThreading(int T = -1) : FunctionPass(ID), Impl(T) { + JumpThreading(bool InsertFreezeWhenUnfoldingSelect = false, int T = -1) + : FunctionPass(ID), Impl(InsertFreezeWhenUnfoldingSelect, T) { initializeJumpThreadingPass(*PassRegistry::getPassRegistry()); } @@ -147,6 +154,7 @@ namespace { AU.addPreserved(); AU.addPreserved(); AU.addRequired(); + AU.addRequired(); } void releaseMemory() override { Impl.releaseMemory(); } @@ -166,11 +174,12 @@ INITIALIZE_PASS_END(JumpThreading, "jump-threading", "Jump Threading", false, false) // Public interface to the Jump Threading pass -FunctionPass *llvm::createJumpThreadingPass(int Threshold) { - return new JumpThreading(Threshold); +FunctionPass *llvm::createJumpThreadingPass(bool InsertFr, int Threshold) { + return new JumpThreading(InsertFr, Threshold); } -JumpThreadingPass::JumpThreadingPass(int T) { +JumpThreadingPass::JumpThreadingPass(bool InsertFr, int T) { + InsertFreezeWhenUnfoldingSelect = JumpThreadingFreezeSelectCond | InsertFr; DefaultBBDupThreshold = (T == -1) ? BBDuplicateThreshold : unsigned(T); } @@ -304,6 +313,10 @@ static void updatePredecessorProfileMetadata(PHINode *PN, BasicBlock *BB) { bool JumpThreading::runOnFunction(Function &F) { if (skipFunction(F)) return false; + auto TTI = &getAnalysis().getTTI(F); + // Jump Threading has no sense for the targets with divergent CF + if (TTI->hasBranchDivergence()) + return false; auto TLI = &getAnalysis().getTLI(F); auto DT = &getAnalysis().getDomTree(); auto LVI = &getAnalysis().getLVI(); @@ -328,6 +341,10 @@ bool JumpThreading::runOnFunction(Function &F) { PreservedAnalyses JumpThreadingPass::run(Function &F, FunctionAnalysisManager &AM) { + auto &TTI = AM.getResult(F); + // Jump Threading has no sense for the targets with divergent CF + if (TTI.hasBranchDivergence()) + return PreservedAnalyses::all(); auto &TLI = AM.getResult(F); auto &DT = AM.getResult(F); auto &LVI = AM.getResult(F); @@ -345,6 +362,11 @@ PreservedAnalyses JumpThreadingPass::run(Function &F, bool Changed = runImpl(F, &TLI, &LVI, &AA, &DTU, F.hasProfileData(), std::move(BFI), std::move(BPI)); + if (PrintLVIAfterJumpThreading) { + dbgs() << "LVI for function '" << F.getName() << "':\n"; + LVI.printLVI(F, DTU.getDomTree(), dbgs()); + } + if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; @@ -397,7 +419,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, Unreachable.insert(&BB); if (!ThreadAcrossLoopHeaders) - FindLoopHeaders(F); + findLoopHeaders(F); bool EverChanged = false; bool Changed; @@ -406,7 +428,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, for (auto &BB : F) { if (Unreachable.count(&BB)) continue; - while (ProcessBlock(&BB)) // Thread all of the branches we can over BB. + while (processBlock(&BB)) // Thread all of the branches we can over BB. Changed = true; // Jump threading may have introduced redundant debug values into BB @@ -421,7 +443,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, continue; if (pred_empty(&BB)) { - // When ProcessBlock makes BB unreachable it doesn't bother to fix up + // When processBlock makes BB unreachable it doesn't bother to fix up // the instructions in it. We must remove BB to prevent invalid IR. LLVM_DEBUG(dbgs() << " JT: Deleting dead block '" << BB.getName() << "' with terminator: " << *BB.getTerminator() @@ -433,7 +455,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, continue; } - // ProcessBlock doesn't thread BBs with unconditional TIs. However, if BB + // processBlock doesn't thread BBs with unconditional TIs. However, if BB // is "almost empty", we attempt to merge BB with its sole successor. auto *BI = dyn_cast(BB.getTerminator()); if (BI && BI->isUnconditional()) { @@ -467,7 +489,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, // at the end of block. RAUW unconditionally replaces all uses // including the guards/assumes themselves and the uses before the // guard/assume. -static void ReplaceFoldableUses(Instruction *Cond, Value *ToVal) { +static void replaceFoldableUses(Instruction *Cond, Value *ToVal) { assert(Cond->getType() == ToVal->getType()); auto *BB = Cond->getParent(); // We can unconditionally replace all uses in non-local blocks (i.e. uses @@ -531,10 +553,18 @@ static unsigned getJumpThreadDuplicationCost(BasicBlock *BB, // Debugger intrinsics don't incur code size. if (isa(I)) continue; + // Pseudo-probes don't incur code size. + if (isa(I)) + continue; + // If this is a pointer->pointer bitcast, it is free. if (isa(I) && I->getType()->isPointerTy()) continue; + // Freeze instruction is free, too. + if (isa(I)) + continue; + // Bail out if this instruction gives back a token type, it is not possible // to duplicate it if it is used outside this BB. if (I->getType()->isTokenTy() && I->isUsedOutsideOfBlock(BB)) @@ -562,7 +592,7 @@ static unsigned getJumpThreadDuplicationCost(BasicBlock *BB, return Size > Bonus ? Size - Bonus : 0; } -/// FindLoopHeaders - We do not want jump threading to turn proper loop +/// findLoopHeaders - We do not want jump threading to turn proper loop /// structures into irreducible loops. Doing this breaks up the loop nesting /// hierarchy and pessimizes later transformations. To prevent this from /// happening, we first have to find the loop headers. Here we approximate this @@ -576,7 +606,7 @@ static unsigned getJumpThreadDuplicationCost(BasicBlock *BB, /// within the loop (forming a nested loop). This simple analysis is not rich /// enough to track all of these properties and keep it up-to-date as the CFG /// mutates, so we don't allow any of these transformations. -void JumpThreadingPass::FindLoopHeaders(Function &F) { +void JumpThreadingPass::findLoopHeaders(Function &F) { SmallVector, 32> Edges; FindFunctionBackedges(F, Edges); @@ -603,13 +633,13 @@ static Constant *getKnownConstant(Value *Val, ConstantPreference Preference) { return dyn_cast(Val); } -/// ComputeValueKnownInPredecessors - Given a basic block BB and a value V, see +/// computeValueKnownInPredecessors - Given a basic block BB and a value V, see /// if we can infer that the value is a known ConstantInt/BlockAddress or undef /// in any of our predecessors. If so, return the known list of value and pred /// BB in the result vector. /// /// This returns true if there were any known values. -bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( +bool JumpThreadingPass::computeValueKnownInPredecessorsImpl( Value *V, BasicBlock *BB, PredValueInfo &Result, ConstantPreference Preference, DenseSet &RecursionSet, Instruction *CxtI) { @@ -674,13 +704,10 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( return !Result.empty(); } - // Handle Cast instructions. Only see through Cast when the source operand is - // PHI or Cmp to save the compilation time. + // Handle Cast instructions. if (CastInst *CI = dyn_cast(I)) { Value *Source = CI->getOperand(0); - if (!isa(Source) && !isa(Source)) - return false; - ComputeValueKnownInPredecessorsImpl(Source, BB, Result, Preference, + computeValueKnownInPredecessorsImpl(Source, BB, Result, Preference, RecursionSet, CxtI); if (Result.empty()) return false; @@ -692,6 +719,18 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( return true; } + if (FreezeInst *FI = dyn_cast(I)) { + Value *Source = FI->getOperand(0); + computeValueKnownInPredecessorsImpl(Source, BB, Result, Preference, + RecursionSet, CxtI); + + erase_if(Result, [](auto &Pair) { + return !isGuaranteedNotToBeUndefOrPoison(Pair.first); + }); + + return !Result.empty(); + } + // Handle some boolean conditions. if (I->getType()->getPrimitiveSizeInBits() == 1) { assert(Preference == WantInteger && "One-bit non-integer type?"); @@ -701,9 +740,9 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( I->getOpcode() == Instruction::And) { PredValueInfoTy LHSVals, RHSVals; - ComputeValueKnownInPredecessorsImpl(I->getOperand(0), BB, LHSVals, + computeValueKnownInPredecessorsImpl(I->getOperand(0), BB, LHSVals, WantInteger, RecursionSet, CxtI); - ComputeValueKnownInPredecessorsImpl(I->getOperand(1), BB, RHSVals, + computeValueKnownInPredecessorsImpl(I->getOperand(1), BB, RHSVals, WantInteger, RecursionSet, CxtI); if (LHSVals.empty() && RHSVals.empty()) @@ -739,7 +778,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( if (I->getOpcode() == Instruction::Xor && isa(I->getOperand(1)) && cast(I->getOperand(1))->isOne()) { - ComputeValueKnownInPredecessorsImpl(I->getOperand(0), BB, Result, + computeValueKnownInPredecessorsImpl(I->getOperand(0), BB, Result, WantInteger, RecursionSet, CxtI); if (Result.empty()) return false; @@ -757,7 +796,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( && "A binary operator creating a block address?"); if (ConstantInt *CI = dyn_cast(BO->getOperand(1))) { PredValueInfoTy LHSVals; - ComputeValueKnownInPredecessorsImpl(BO->getOperand(0), BB, LHSVals, + computeValueKnownInPredecessorsImpl(BO->getOperand(0), BB, LHSVals, WantInteger, RecursionSet, CxtI); // Try to use constant folding to simplify the binary operator. @@ -891,7 +930,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( // Try to find a constant value for the LHS of a comparison, // and evaluate it statically if we can. PredValueInfoTy LHSVals; - ComputeValueKnownInPredecessorsImpl(I->getOperand(0), BB, LHSVals, + computeValueKnownInPredecessorsImpl(I->getOperand(0), BB, LHSVals, WantInteger, RecursionSet, CxtI); for (const auto &LHSVal : LHSVals) { @@ -912,7 +951,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( Constant *FalseVal = getKnownConstant(SI->getFalseValue(), Preference); PredValueInfoTy Conds; if ((TrueVal || FalseVal) && - ComputeValueKnownInPredecessorsImpl(SI->getCondition(), BB, Conds, + computeValueKnownInPredecessorsImpl(SI->getCondition(), BB, Conds, WantInteger, RecursionSet, CxtI)) { for (auto &C : Conds) { Constant *Cond = C.first; @@ -940,7 +979,8 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( } // If all else fails, see if LVI can figure out a constant value for us. - Constant *CI = LVI->getConstant(V, BB, CxtI); + assert(CxtI->getParent() == BB && "CxtI should be in BB"); + Constant *CI = LVI->getConstant(V, CxtI); if (Constant *KC = getKnownConstant(CI, Preference)) { for (BasicBlock *Pred : predecessors(BB)) Result.emplace_back(KC, Pred); @@ -954,7 +994,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessorsImpl( /// /// Since we can pick an arbitrary destination, we pick the successor with the /// fewest predecessors. This should reduce the in-degree of the others. -static unsigned GetBestDestForJumpOnUndef(BasicBlock *BB) { +static unsigned getBestDestForJumpOnUndef(BasicBlock *BB) { Instruction *BBTerm = BB->getTerminator(); unsigned MinSucc = 0; BasicBlock *TestBB = BBTerm->getSuccessor(MinSucc); @@ -982,9 +1022,9 @@ static bool hasAddressTakenAndUsed(BasicBlock *BB) { return !BA->use_empty(); } -/// ProcessBlock - If there are any predecessors whose control can be threaded +/// processBlock - If there are any predecessors whose control can be threaded /// through to a successor, transform them now. -bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { +bool JumpThreadingPass::processBlock(BasicBlock *BB) { // If the block is trivially dead, just return and let the caller nuke it. // This simplifies other transformations. if (DTU->isBBPendingDeletion(BB) || @@ -995,14 +1035,14 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // successor, merge the blocks. This encourages recursive jump threading // because now the condition in this block can be threaded through // predecessors of our predecessor block. - if (MaybeMergeBasicBlockIntoOnlyPred(BB)) + if (maybeMergeBasicBlockIntoOnlyPred(BB)) return true; - if (TryToUnfoldSelectInCurrBB(BB)) + if (tryToUnfoldSelectInCurrBB(BB)) return true; // Look if we can propagate guards to predecessors. - if (HasGuards && ProcessGuards(BB)) + if (HasGuards && processGuards(BB)) return true; // What kind of constant we're looking for. @@ -1027,6 +1067,9 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { return false; // Must be an invoke or callbr. } + // Keep track if we constant folded the condition in this invocation. + bool ConstantFolded = false; + // Run constant folding to see if we can reduce the condition to a simple // constant. if (Instruction *I = dyn_cast(Condition)) { @@ -1037,13 +1080,16 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { if (isInstructionTriviallyDead(I, TLI)) I->eraseFromParent(); Condition = SimpleVal; + ConstantFolded = true; } } - // If the terminator is branching on an undef, we can pick any of the - // successors to branch to. Let GetBestDestForJumpOnUndef decide. - if (isa(Condition)) { - unsigned BestSucc = GetBestDestForJumpOnUndef(BB); + // If the terminator is branching on an undef or freeze undef, we can pick any + // of the successors to branch to. Let getBestDestForJumpOnUndef decide. + auto *FI = dyn_cast(Condition); + if (isa(Condition) || + (FI && isa(FI->getOperand(0)) && FI->hasOneUse())) { + unsigned BestSucc = getBestDestForJumpOnUndef(BB); std::vector Updates; // Fold the branch/switch. @@ -1061,6 +1107,8 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm); BBTerm->eraseFromParent(); DTU->applyUpdatesPermissive(Updates); + if (FI) + FI->eraseFromParent(); return true; } @@ -1073,6 +1121,8 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { << '\n'); ++NumFolds; ConstantFoldTerminator(BB, true, nullptr, DTU); + if (HasProfileData) + BPI->eraseBlock(BB); return true; } @@ -1081,9 +1131,9 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // All the rest of our checks depend on the condition being an instruction. if (!CondInst) { // FIXME: Unify this with code below. - if (ProcessThreadableEdges(Condition, BB, Preference, Terminator)) + if (processThreadableEdges(Condition, BB, Preference, Terminator)) return true; - return false; + return ConstantFolded; } if (CmpInst *CondCmp = dyn_cast(CondInst)) { @@ -1124,22 +1174,24 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { auto *CI = Ret == LazyValueInfo::True ? ConstantInt::getTrue(CondCmp->getType()) : ConstantInt::getFalse(CondCmp->getType()); - ReplaceFoldableUses(CondCmp, CI); + replaceFoldableUses(CondCmp, CI); } DTU->applyUpdatesPermissive( {{DominatorTree::Delete, BB, ToRemoveSucc}}); + if (HasProfileData) + BPI->eraseBlock(BB); return true; } // We did not manage to simplify this branch, try to see whether // CondCmp depends on a known phi-select pattern. - if (TryToUnfoldSelect(CondCmp, BB)) + if (tryToUnfoldSelect(CondCmp, BB)) return true; } } if (SwitchInst *SI = dyn_cast(BB->getTerminator())) - if (TryToUnfoldSelect(SI, BB)) + if (tryToUnfoldSelect(SI, BB)) return true; // Check for some cases that are worth simplifying. Right now we want to look @@ -1147,6 +1199,11 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // we see one, check to see if it's partially redundant. If so, insert a PHI // which can then be used to thread the values. Value *SimplifyValue = CondInst; + + if (auto *FI = dyn_cast(SimplifyValue)) + // Look into freeze's operand + SimplifyValue = FI->getOperand(0); + if (CmpInst *CondCmp = dyn_cast(SimplifyValue)) if (isa(CondCmp->getOperand(1))) SimplifyValue = CondCmp->getOperand(0); @@ -1154,7 +1211,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // TODO: There are other places where load PRE would be profitable, such as // more complex comparisons. if (LoadInst *LoadI = dyn_cast(SimplifyValue)) - if (SimplifyPartiallyRedundantLoad(LoadI)) + if (simplifyPartiallyRedundantLoad(LoadI)) return true; // Before threading, try to propagate profile data backwards: @@ -1165,29 +1222,32 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // Handle a variety of cases where we are branching on something derived from // a PHI node in the current block. If we can prove that any predecessors // compute a predictable value based on a PHI node, thread those predecessors. - if (ProcessThreadableEdges(CondInst, BB, Preference, Terminator)) + if (processThreadableEdges(CondInst, BB, Preference, Terminator)) return true; - // If this is an otherwise-unfoldable branch on a phi node in the current - // block, see if we can simplify. - if (PHINode *PN = dyn_cast(CondInst)) - if (PN->getParent() == BB && isa(BB->getTerminator())) - return ProcessBranchOnPHI(PN); + // If this is an otherwise-unfoldable branch on a phi node or freeze(phi) in + // the current block, see if we can simplify. + PHINode *PN = dyn_cast( + isa(CondInst) ? cast(CondInst)->getOperand(0) + : CondInst); + + if (PN && PN->getParent() == BB && isa(BB->getTerminator())) + return processBranchOnPHI(PN); // If this is an otherwise-unfoldable branch on a XOR, see if we can simplify. if (CondInst->getOpcode() == Instruction::Xor && CondInst->getParent() == BB && isa(BB->getTerminator())) - return ProcessBranchOnXOR(cast(CondInst)); + return processBranchOnXOR(cast(CondInst)); // Search for a stronger dominating condition that can be used to simplify a // conditional branch leaving BB. - if (ProcessImpliedCondition(BB)) + if (processImpliedCondition(BB)) return true; return false; } -bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) { +bool JumpThreadingPass::processImpliedCondition(BasicBlock *BB) { auto *BI = dyn_cast(BB->getTerminator()); if (!BI || !BI->isConditional()) return false; @@ -1217,6 +1277,8 @@ bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) { UncondBI->setDebugLoc(BI->getDebugLoc()); BI->eraseFromParent(); DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, RemoveSucc}}); + if (HasProfileData) + BPI->eraseBlock(BB); return true; } CurrentBB = CurrentPred; @@ -1234,11 +1296,11 @@ static bool isOpDefinedInBlock(Value *Op, BasicBlock *BB) { return false; } -/// SimplifyPartiallyRedundantLoad - If LoadI is an obviously partially +/// simplifyPartiallyRedundantLoad - If LoadI is an obviously partially /// redundant load instruction, eliminate it by replacing it with a PHI node. /// This is an important optimization that encourages jump threading, and needs /// to be run interlaced with other jump threading tasks. -bool JumpThreadingPass::SimplifyPartiallyRedundantLoad(LoadInst *LoadI) { +bool JumpThreadingPass::simplifyPartiallyRedundantLoad(LoadInst *LoadI) { // Don't hack volatile and ordered loads. if (!LoadI->isUnordered()) return false; @@ -1408,7 +1470,7 @@ bool JumpThreadingPass::SimplifyPartiallyRedundantLoad(LoadInst *LoadI) { } // Split them out to their own block. - UnavailablePred = SplitBlockPreds(LoadBB, PredsToSplit, "thread-pre-split"); + UnavailablePred = splitBlockPreds(LoadBB, PredsToSplit, "thread-pre-split"); } // If the value isn't available in all predecessors, then there will be @@ -1472,11 +1534,11 @@ bool JumpThreadingPass::SimplifyPartiallyRedundantLoad(LoadInst *LoadI) { return true; } -/// FindMostPopularDest - The specified list contains multiple possible +/// findMostPopularDest - The specified list contains multiple possible /// threadable destinations. Pick the one that occurs the most frequently in /// the list. static BasicBlock * -FindMostPopularDest(BasicBlock *BB, +findMostPopularDest(BasicBlock *BB, const SmallVectorImpl> &PredToDestList) { assert(!PredToDestList.empty()); @@ -1511,7 +1573,7 @@ FindMostPopularDest(BasicBlock *BB, // Try to evaluate the value of V when the control flows from PredPredBB to // BB->getSinglePredecessor() and then on to BB. -Constant *JumpThreadingPass::EvaluateOnPredecessorEdge(BasicBlock *BB, +Constant *JumpThreadingPass::evaluateOnPredecessorEdge(BasicBlock *BB, BasicBlock *PredPredBB, Value *V) { BasicBlock *PredBB = BB->getSinglePredecessor(); @@ -1538,9 +1600,9 @@ Constant *JumpThreadingPass::EvaluateOnPredecessorEdge(BasicBlock *BB, if (CmpInst *CondCmp = dyn_cast(V)) { if (CondCmp->getParent() == BB) { Constant *Op0 = - EvaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(0)); + evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(0)); Constant *Op1 = - EvaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(1)); + evaluateOnPredecessorEdge(BB, PredPredBB, CondCmp->getOperand(1)); if (Op0 && Op1) { return ConstantExpr::getCompare(CondCmp->getPredicate(), Op0, Op1); } @@ -1551,7 +1613,7 @@ Constant *JumpThreadingPass::EvaluateOnPredecessorEdge(BasicBlock *BB, return nullptr; } -bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, +bool JumpThreadingPass::processThreadableEdges(Value *Cond, BasicBlock *BB, ConstantPreference Preference, Instruction *CxtI) { // If threading this would thread across a loop header, don't even try to @@ -1560,15 +1622,15 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, return false; PredValueInfoTy PredValues; - if (!ComputeValueKnownInPredecessors(Cond, BB, PredValues, Preference, + if (!computeValueKnownInPredecessors(Cond, BB, PredValues, Preference, CxtI)) { // We don't have known values in predecessors. See if we can thread through // BB and its sole predecessor. - return MaybeThreadThroughTwoBasicBlocks(BB, Cond); + return maybethreadThroughTwoBasicBlocks(BB, Cond); } assert(!PredValues.empty() && - "ComputeValueKnownInPredecessors returned true with no values"); + "computeValueKnownInPredecessors returned true with no values"); LLVM_DEBUG(dbgs() << "IN BB: " << *BB; for (const auto &PredValue : PredValues) { @@ -1660,6 +1722,8 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, BranchInst::Create(OnlyDest, Term); Term->eraseFromParent(); DTU->applyUpdatesPermissive(Updates); + if (HasProfileData) + BPI->eraseBlock(BB); // If the condition is now dead due to the removal of the old terminator, // erase it. @@ -1675,7 +1739,7 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, // guard/assume. else if (OnlyVal && OnlyVal != MultipleVal && CondInst->getParent() == BB) - ReplaceFoldableUses(CondInst, OnlyVal); + replaceFoldableUses(CondInst, OnlyVal); } return true; } @@ -1688,18 +1752,18 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, BasicBlock *MostPopularDest = OnlyDest; if (MostPopularDest == MultipleDestSentinel) { - // Remove any loop headers from the Dest list, ThreadEdge conservatively + // Remove any loop headers from the Dest list, threadEdge conservatively // won't process them, but we might have other destination that are eligible // and we still want to process. erase_if(PredToDestList, [&](const std::pair &PredToDest) { - return LoopHeaders.count(PredToDest.second) != 0; + return LoopHeaders.contains(PredToDest.second); }); if (PredToDestList.empty()) return false; - MostPopularDest = FindMostPopularDest(BB, PredToDestList); + MostPopularDest = findMostPopularDest(BB, PredToDestList); } // Now that we know what the most popular destination is, factor all @@ -1721,16 +1785,16 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, // the destination that these predecessors should get to. if (!MostPopularDest) MostPopularDest = BB->getTerminator()-> - getSuccessor(GetBestDestForJumpOnUndef(BB)); + getSuccessor(getBestDestForJumpOnUndef(BB)); // Ok, try to thread it! - return TryThreadEdge(BB, PredsToFactor, MostPopularDest); + return tryThreadEdge(BB, PredsToFactor, MostPopularDest); } -/// ProcessBranchOnPHI - We have an otherwise unthreadable conditional branch on -/// a PHI node in the current block. See if there are any simplifications we -/// can do based on inputs to the phi node. -bool JumpThreadingPass::ProcessBranchOnPHI(PHINode *PN) { +/// processBranchOnPHI - We have an otherwise unthreadable conditional branch on +/// a PHI node (or freeze PHI) in the current block. See if there are any +/// simplifications we can do based on inputs to the phi node. +bool JumpThreadingPass::processBranchOnPHI(PHINode *PN) { BasicBlock *BB = PN->getParent(); // TODO: We could make use of this to do it once for blocks with common PHI @@ -1742,13 +1806,16 @@ bool JumpThreadingPass::ProcessBranchOnPHI(PHINode *PN) { // *duplicate* the conditional branch into that block in order to further // encourage jump threading and to eliminate cases where we have branch on a // phi of an icmp (branch on icmp is much better). + // This is still beneficial when a frozen phi is used as the branch condition + // because it allows CodeGenPrepare to further canonicalize br(freeze(icmp)) + // to br(icmp(freeze ...)). for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { BasicBlock *PredBB = PN->getIncomingBlock(i); if (BranchInst *PredBr = dyn_cast(PredBB->getTerminator())) if (PredBr->isUnconditional()) { PredBBs[0] = PredBB; // Try to duplicate BB into PredBB. - if (DuplicateCondBranchOnPHIIntoPred(BB, PredBBs)) + if (duplicateCondBranchOnPHIIntoPred(BB, PredBBs)) return true; } } @@ -1756,10 +1823,10 @@ bool JumpThreadingPass::ProcessBranchOnPHI(PHINode *PN) { return false; } -/// ProcessBranchOnXOR - We have an otherwise unthreadable conditional branch on +/// processBranchOnXOR - We have an otherwise unthreadable conditional branch on /// a xor instruction in the current block. See if there are any /// simplifications we can do based on inputs to the xor. -bool JumpThreadingPass::ProcessBranchOnXOR(BinaryOperator *BO) { +bool JumpThreadingPass::processBranchOnXOR(BinaryOperator *BO) { BasicBlock *BB = BO->getParent(); // If either the LHS or RHS of the xor is a constant, don't do this @@ -1797,17 +1864,17 @@ bool JumpThreadingPass::ProcessBranchOnXOR(BinaryOperator *BO) { PredValueInfoTy XorOpValues; bool isLHS = true; - if (!ComputeValueKnownInPredecessors(BO->getOperand(0), BB, XorOpValues, + if (!computeValueKnownInPredecessors(BO->getOperand(0), BB, XorOpValues, WantInteger, BO)) { assert(XorOpValues.empty()); - if (!ComputeValueKnownInPredecessors(BO->getOperand(1), BB, XorOpValues, + if (!computeValueKnownInPredecessors(BO->getOperand(1), BB, XorOpValues, WantInteger, BO)) return false; isLHS = false; } assert(!XorOpValues.empty() && - "ComputeValueKnownInPredecessors returned true with no values"); + "computeValueKnownInPredecessors returned true with no values"); // Scan the information to see which is most popular: true or false. The // predecessors can be of the set true, false, or undef. @@ -1859,14 +1926,22 @@ bool JumpThreadingPass::ProcessBranchOnXOR(BinaryOperator *BO) { return true; } + // If any of predecessors end with an indirect goto, we can't change its + // destination. Same for CallBr. + if (any_of(BlocksToFoldInto, [](BasicBlock *Pred) { + return isa(Pred->getTerminator()) || + isa(Pred->getTerminator()); + })) + return false; + // Try to duplicate BB into PredBB. - return DuplicateCondBranchOnPHIIntoPred(BB, BlocksToFoldInto); + return duplicateCondBranchOnPHIIntoPred(BB, BlocksToFoldInto); } -/// AddPHINodeEntriesForMappedBlock - We're adding 'NewPred' as a new +/// addPHINodeEntriesForMappedBlock - We're adding 'NewPred' as a new /// predecessor to the PHIBB block. If it has PHI nodes, add entries for /// NewPred using the entries from OldPred (suitably mapped). -static void AddPHINodeEntriesForMappedBlock(BasicBlock *PHIBB, +static void addPHINodeEntriesForMappedBlock(BasicBlock *PHIBB, BasicBlock *OldPred, BasicBlock *NewPred, DenseMap &ValueMap) { @@ -1887,7 +1962,7 @@ static void AddPHINodeEntriesForMappedBlock(BasicBlock *PHIBB, } /// Merge basic block BB into its sole predecessor if possible. -bool JumpThreadingPass::MaybeMergeBasicBlockIntoOnlyPred(BasicBlock *BB) { +bool JumpThreadingPass::maybeMergeBasicBlockIntoOnlyPred(BasicBlock *BB) { BasicBlock *SinglePred = BB->getSinglePredecessor(); if (!SinglePred) return false; @@ -1938,7 +2013,7 @@ bool JumpThreadingPass::MaybeMergeBasicBlockIntoOnlyPred(BasicBlock *BB) { /// Update the SSA form. NewBB contains instructions that are copied from BB. /// ValueMapping maps old values in BB to new ones in NewBB. -void JumpThreadingPass::UpdateSSA( +void JumpThreadingPass::updateSSA( BasicBlock *BB, BasicBlock *NewBB, DenseMap &ValueMapping) { // If there were values defined in BB that are used outside the block, then we @@ -1984,7 +2059,7 @@ void JumpThreadingPass::UpdateSSA( /// arguments that come from PredBB. Return the map from the variables in the /// source basic block to the variables in the newly created basic block. DenseMap -JumpThreadingPass::CloneInstructions(BasicBlock::iterator BI, +JumpThreadingPass::cloneInstructions(BasicBlock::iterator BI, BasicBlock::iterator BE, BasicBlock *NewBB, BasicBlock *PredBB) { // We are going to have to map operands from the source basic block to the new @@ -2023,7 +2098,7 @@ JumpThreadingPass::CloneInstructions(BasicBlock::iterator BI, } /// Attempt to thread through two successive basic blocks. -bool JumpThreadingPass::MaybeThreadThroughTwoBasicBlocks(BasicBlock *BB, +bool JumpThreadingPass::maybethreadThroughTwoBasicBlocks(BasicBlock *BB, Value *Cond) { // Consider: // @@ -2092,7 +2167,7 @@ bool JumpThreadingPass::MaybeThreadThroughTwoBasicBlocks(BasicBlock *BB, BasicBlock *OnePred = nullptr; for (BasicBlock *P : predecessors(PredBB)) { if (ConstantInt *CI = dyn_cast_or_null( - EvaluateOnPredecessorEdge(BB, P, Cond))) { + evaluateOnPredecessorEdge(BB, P, Cond))) { if (CI->isZero()) { ZeroCount++; ZeroPred = P; @@ -2123,7 +2198,7 @@ bool JumpThreadingPass::MaybeThreadThroughTwoBasicBlocks(BasicBlock *BB, } // If threading this would thread across a loop header, don't thread the edge. - // See the comments above FindLoopHeaders for justifications and caveats. + // See the comments above findLoopHeaders for justifications and caveats. if (LoopHeaders.count(BB) || LoopHeaders.count(SuccBB)) { LLVM_DEBUG({ bool BBIsHeader = LoopHeaders.count(BB); @@ -2156,11 +2231,11 @@ bool JumpThreadingPass::MaybeThreadThroughTwoBasicBlocks(BasicBlock *BB, } // Now we are ready to duplicate PredBB. - ThreadThroughTwoBasicBlocks(PredPredBB, PredBB, BB, SuccBB); + threadThroughTwoBasicBlocks(PredPredBB, PredBB, BB, SuccBB); return true; } -void JumpThreadingPass::ThreadThroughTwoBasicBlocks(BasicBlock *PredPredBB, +void JumpThreadingPass::threadThroughTwoBasicBlocks(BasicBlock *PredPredBB, BasicBlock *PredBB, BasicBlock *BB, BasicBlock *SuccBB) { @@ -2186,7 +2261,11 @@ void JumpThreadingPass::ThreadThroughTwoBasicBlocks(BasicBlock *PredPredBB, // copy of the block 'NewBB'. If there are PHI nodes in PredBB, evaluate them // to account for entry from PredPredBB. DenseMap ValueMapping = - CloneInstructions(PredBB->begin(), PredBB->end(), NewBB, PredPredBB); + cloneInstructions(PredBB->begin(), PredBB->end(), NewBB, PredPredBB); + + // Copy the edge probabilities from PredBB to NewBB. + if (HasProfileData) + BPI->copyEdgeProbabilities(PredBB, NewBB); // Update the terminator of PredPredBB to jump to NewBB instead of PredBB. // This eliminates predecessors from PredPredBB, which requires us to simplify @@ -2198,9 +2277,9 @@ void JumpThreadingPass::ThreadThroughTwoBasicBlocks(BasicBlock *PredPredBB, PredPredTerm->setSuccessor(i, NewBB); } - AddPHINodeEntriesForMappedBlock(PredBBBranch->getSuccessor(0), PredBB, NewBB, + addPHINodeEntriesForMappedBlock(PredBBBranch->getSuccessor(0), PredBB, NewBB, ValueMapping); - AddPHINodeEntriesForMappedBlock(PredBBBranch->getSuccessor(1), PredBB, NewBB, + addPHINodeEntriesForMappedBlock(PredBBBranch->getSuccessor(1), PredBB, NewBB, ValueMapping); DTU->applyUpdatesPermissive( @@ -2209,7 +2288,7 @@ void JumpThreadingPass::ThreadThroughTwoBasicBlocks(BasicBlock *PredPredBB, {DominatorTree::Insert, PredPredBB, NewBB}, {DominatorTree::Delete, PredPredBB, PredBB}}); - UpdateSSA(PredBB, NewBB, ValueMapping); + updateSSA(PredBB, NewBB, ValueMapping); // Clean up things like PHI nodes with single operands, dead instructions, // etc. @@ -2218,11 +2297,11 @@ void JumpThreadingPass::ThreadThroughTwoBasicBlocks(BasicBlock *PredPredBB, SmallVector PredsToFactor; PredsToFactor.push_back(NewBB); - ThreadEdge(BB, PredsToFactor, SuccBB); + threadEdge(BB, PredsToFactor, SuccBB); } -/// TryThreadEdge - Thread an edge if it's safe and profitable to do so. -bool JumpThreadingPass::TryThreadEdge( +/// tryThreadEdge - Thread an edge if it's safe and profitable to do so. +bool JumpThreadingPass::tryThreadEdge( BasicBlock *BB, const SmallVectorImpl &PredBBs, BasicBlock *SuccBB) { // If threading to the same block as we come from, we would infinite loop. @@ -2233,7 +2312,7 @@ bool JumpThreadingPass::TryThreadEdge( } // If threading this would thread across a loop header, don't thread the edge. - // See the comments above FindLoopHeaders for justifications and caveats. + // See the comments above findLoopHeaders for justifications and caveats. if (LoopHeaders.count(BB) || LoopHeaders.count(SuccBB)) { LLVM_DEBUG({ bool BBIsHeader = LoopHeaders.count(BB); @@ -2254,14 +2333,14 @@ bool JumpThreadingPass::TryThreadEdge( return false; } - ThreadEdge(BB, PredBBs, SuccBB); + threadEdge(BB, PredBBs, SuccBB); return true; } -/// ThreadEdge - We have decided that it is safe and profitable to factor the +/// threadEdge - We have decided that it is safe and profitable to factor the /// blocks in PredBBs to one predecessor, then thread an edge from it to SuccBB /// across BB. Transform the IR to reflect this change. -void JumpThreadingPass::ThreadEdge(BasicBlock *BB, +void JumpThreadingPass::threadEdge(BasicBlock *BB, const SmallVectorImpl &PredBBs, BasicBlock *SuccBB) { assert(SuccBB != BB && "Don't create an infinite loop"); @@ -2276,7 +2355,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, else { LLVM_DEBUG(dbgs() << " Factoring out " << PredBBs.size() << " common predecessors.\n"); - PredBB = SplitBlockPreds(BB, PredBBs, ".thr_comm"); + PredBB = splitBlockPreds(BB, PredBBs, ".thr_comm"); } // And finally, do it! @@ -2300,7 +2379,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, // Copy all the instructions from BB to NewBB except the terminator. DenseMap ValueMapping = - CloneInstructions(BB->begin(), std::prev(BB->end()), NewBB, PredBB); + cloneInstructions(BB->begin(), std::prev(BB->end()), NewBB, PredBB); // We didn't copy the terminator from BB over to NewBB, because there is now // an unconditional jump to SuccBB. Insert the unconditional jump. @@ -2309,7 +2388,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, // Check to see if SuccBB has PHI nodes. If so, we need to add entries to the // PHI nodes for NewBB now. - AddPHINodeEntriesForMappedBlock(SuccBB, BB, NewBB, ValueMapping); + addPHINodeEntriesForMappedBlock(SuccBB, BB, NewBB, ValueMapping); // Update the terminator of PredBB to jump to NewBB instead of BB. This // eliminates predecessors from BB, which requires us to simplify any PHI @@ -2326,7 +2405,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, {DominatorTree::Insert, PredBB, NewBB}, {DominatorTree::Delete, PredBB, BB}}); - UpdateSSA(BB, NewBB, ValueMapping); + updateSSA(BB, NewBB, ValueMapping); // At this point, the IR is fully up to date and consistent. Do a quick scan // over the new instructions and zap any that are constants or dead. This @@ -2334,7 +2413,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, SimplifyInstructionsInBlock(NewBB, TLI); // Update the edge weight from BB to SuccBB, which should be less than before. - UpdateBlockFreqAndEdgeWeight(PredBB, BB, NewBB, SuccBB); + updateBlockFreqAndEdgeWeight(PredBB, BB, NewBB, SuccBB); // Threaded an edge! ++NumThreads; @@ -2343,7 +2422,7 @@ void JumpThreadingPass::ThreadEdge(BasicBlock *BB, /// Create a new basic block that will be the predecessor of BB and successor of /// all blocks in Preds. When profile data is available, update the frequency of /// this new block. -BasicBlock *JumpThreadingPass::SplitBlockPreds(BasicBlock *BB, +BasicBlock *JumpThreadingPass::splitBlockPreds(BasicBlock *BB, ArrayRef Preds, const char *Suffix) { SmallVector NewBBs; @@ -2404,7 +2483,7 @@ bool JumpThreadingPass::doesBlockHaveProfileData(BasicBlock *BB) { /// Update the block frequency of BB and branch weight and the metadata on the /// edge BB->SuccBB. This is done by scaling the weight of BB->SuccBB by 1 - /// Freq(PredBB->BB) / Freq(BB->SuccBB). -void JumpThreadingPass::UpdateBlockFreqAndEdgeWeight(BasicBlock *PredBB, +void JumpThreadingPass::updateBlockFreqAndEdgeWeight(BasicBlock *PredBB, BasicBlock *BB, BasicBlock *NewBB, BasicBlock *SuccBB) { @@ -2496,18 +2575,18 @@ void JumpThreadingPass::UpdateBlockFreqAndEdgeWeight(BasicBlock *PredBB, } } -/// DuplicateCondBranchOnPHIIntoPred - PredBB contains an unconditional branch +/// duplicateCondBranchOnPHIIntoPred - PredBB contains an unconditional branch /// to BB which contains an i1 PHI node and a conditional branch on that PHI. /// If we can duplicate the contents of BB up into PredBB do so now, this /// improves the odds that the branch will be on an analyzable instruction like /// a compare. -bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( +bool JumpThreadingPass::duplicateCondBranchOnPHIIntoPred( BasicBlock *BB, const SmallVectorImpl &PredBBs) { assert(!PredBBs.empty() && "Can't handle an empty set"); // If BB is a loop header, then duplicating this block outside the loop would // cause us to transform this into an irreducible loop, don't do this. - // See the comments above FindLoopHeaders for justifications and caveats. + // See the comments above findLoopHeaders for justifications and caveats. if (LoopHeaders.count(BB)) { LLVM_DEBUG(dbgs() << " Not duplicating loop header '" << BB->getName() << "' into predecessor block '" << PredBBs[0]->getName() @@ -2531,7 +2610,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( else { LLVM_DEBUG(dbgs() << " Factoring out " << PredBBs.size() << " common predecessors.\n"); - PredBB = SplitBlockPreds(BB, PredBBs, ".thr_comm"); + PredBB = splitBlockPreds(BB, PredBBs, ".thr_comm"); } Updates.push_back({DominatorTree::Delete, PredBB, BB}); @@ -2603,12 +2682,12 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( // Check to see if the targets of the branch had PHI nodes. If so, we need to // add entries to the PHI nodes for branch from PredBB now. BranchInst *BBBranch = cast(BB->getTerminator()); - AddPHINodeEntriesForMappedBlock(BBBranch->getSuccessor(0), BB, PredBB, + addPHINodeEntriesForMappedBlock(BBBranch->getSuccessor(0), BB, PredBB, ValueMapping); - AddPHINodeEntriesForMappedBlock(BBBranch->getSuccessor(1), BB, PredBB, + addPHINodeEntriesForMappedBlock(BBBranch->getSuccessor(1), BB, PredBB, ValueMapping); - UpdateSSA(BB, PredBB, ValueMapping); + updateSSA(BB, PredBB, ValueMapping); // PredBB no longer jumps to BB, remove entries in the PHI node for the edge // that we nuked. @@ -2616,6 +2695,8 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( // Remove the unconditional branch at the end of the PredBB block. OldPredBranch->eraseFromParent(); + if (HasProfileData) + BPI->copyEdgeProbabilities(BB, PredBB); DTU->applyUpdatesPermissive(Updates); ++NumDupes; @@ -2627,7 +2708,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( // a PHI node in BB. SI has no other use. // A new basic block, NewBB, is created and SI is converted to compare and // conditional branch. SI is erased from parent. -void JumpThreadingPass::UnfoldSelectInstr(BasicBlock *Pred, BasicBlock *BB, +void JumpThreadingPass::unfoldSelectInstr(BasicBlock *Pred, BasicBlock *BB, SelectInst *SI, PHINode *SIUse, unsigned Idx) { // Expand the select. @@ -2662,7 +2743,7 @@ void JumpThreadingPass::UnfoldSelectInstr(BasicBlock *Pred, BasicBlock *BB, Phi->addIncoming(Phi->getIncomingValueForBlock(Pred), NewBB); } -bool JumpThreadingPass::TryToUnfoldSelect(SwitchInst *SI, BasicBlock *BB) { +bool JumpThreadingPass::tryToUnfoldSelect(SwitchInst *SI, BasicBlock *BB) { PHINode *CondPHI = dyn_cast(SI->getCondition()); if (!CondPHI || CondPHI->getParent() != BB) @@ -2674,7 +2755,7 @@ bool JumpThreadingPass::TryToUnfoldSelect(SwitchInst *SI, BasicBlock *BB) { // The second and third condition can be potentially relaxed. Currently // the conditions help to simplify the code and allow us to reuse existing - // code, developed for TryToUnfoldSelect(CmpInst *, BasicBlock *) + // code, developed for tryToUnfoldSelect(CmpInst *, BasicBlock *) if (!PredSI || PredSI->getParent() != Pred || !PredSI->hasOneUse()) continue; @@ -2682,13 +2763,13 @@ bool JumpThreadingPass::TryToUnfoldSelect(SwitchInst *SI, BasicBlock *BB) { if (!PredTerm || !PredTerm->isUnconditional()) continue; - UnfoldSelectInstr(Pred, BB, PredSI, CondPHI, I); + unfoldSelectInstr(Pred, BB, PredSI, CondPHI, I); return true; } return false; } -/// TryToUnfoldSelect - Look for blocks of the form +/// tryToUnfoldSelect - Look for blocks of the form /// bb1: /// %a = select /// br bb2 @@ -2700,7 +2781,7 @@ bool JumpThreadingPass::TryToUnfoldSelect(SwitchInst *SI, BasicBlock *BB) { /// /// And expand the select into a branch structure if one of its arms allows %c /// to be folded. This later enables threading from bb1 over bb2. -bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) { +bool JumpThreadingPass::tryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) { BranchInst *CondBr = dyn_cast(BB->getTerminator()); PHINode *CondLHS = dyn_cast(CondCmp->getOperand(0)); Constant *CondRHS = cast(CondCmp->getOperand(1)); @@ -2734,14 +2815,14 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) { if ((LHSFolds != LazyValueInfo::Unknown || RHSFolds != LazyValueInfo::Unknown) && LHSFolds != RHSFolds) { - UnfoldSelectInstr(Pred, BB, SI, CondLHS, I); + unfoldSelectInstr(Pred, BB, SI, CondLHS, I); return true; } } return false; } -/// TryToUnfoldSelectInCurrBB - Look for PHI/Select or PHI/CMP/Select in the +/// tryToUnfoldSelectInCurrBB - Look for PHI/Select or PHI/CMP/Select in the /// same BB in the form /// bb: /// %p = phi [false, %bb1], [true, %bb2], [false, %bb3], [true, %bb4], ... @@ -2761,19 +2842,14 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) { /// select if the associated PHI has at least one constant. If the unfolded /// select is not jump-threaded, it will be folded again in the later /// optimizations. -bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) { - // This transform can introduce a UB (a conditional branch that depends on a - // poison value) that was not present in the original program. See - // @TryToUnfoldSelectInCurrBB test in test/Transforms/JumpThreading/select.ll. +bool JumpThreadingPass::tryToUnfoldSelectInCurrBB(BasicBlock *BB) { + // This transform would reduce the quality of msan diagnostics. // Disable this transform under MemorySanitizer. - // FIXME: either delete it or replace with a valid transform. This issue is - // not limited to MemorySanitizer (but has only been observed as an MSan false - // positive in practice so far). if (BB->getParent()->hasFnAttribute(Attribute::SanitizeMemory)) return false; // If threading this would thread across a loop header, don't thread the edge. - // See the comments above FindLoopHeaders for justifications and caveats. + // See the comments above findLoopHeaders for justifications and caveats. if (LoopHeaders.count(BB)) return false; @@ -2816,8 +2892,12 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) { if (!SI) continue; // Expand the select. - Instruction *Term = - SplitBlockAndInsertIfThen(SI->getCondition(), SI, false); + Value *Cond = SI->getCondition(); + if (InsertFreezeWhenUnfoldingSelect && + !isGuaranteedNotToBeUndefOrPoison(Cond, nullptr, SI, + &DTU->getDomTree())) + Cond = new FreezeInst(Cond, "cond.fr", SI); + Instruction *Term = SplitBlockAndInsertIfThen(Cond, SI, false); BasicBlock *SplitBB = SI->getParent(); BasicBlock *NewBB = Term->getParent(); PHINode *NewPN = PHINode::Create(SI->getType(), 2, "", SI); @@ -2861,7 +2941,7 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) { /// And cond either implies condGuard or !condGuard. In this case all the /// instructions before the guard can be duplicated in both branches, and the /// guard is then threaded to one of them. -bool JumpThreadingPass::ProcessGuards(BasicBlock *BB) { +bool JumpThreadingPass::processGuards(BasicBlock *BB) { using namespace PatternMatch; // We only want to deal with two predecessors. @@ -2886,7 +2966,7 @@ bool JumpThreadingPass::ProcessGuards(BasicBlock *BB) { if (auto *BI = dyn_cast(Parent->getTerminator())) for (auto &I : *BB) - if (isGuard(&I) && ThreadGuard(BB, cast(&I), BI)) + if (isGuard(&I) && threadGuard(BB, cast(&I), BI)) return true; return false; @@ -2895,7 +2975,7 @@ bool JumpThreadingPass::ProcessGuards(BasicBlock *BB) { /// Try to propagate the guard from BB which is the lower block of a diamond /// to one of its branches, in case if diamond's condition implies guard's /// condition. -bool JumpThreadingPass::ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard, +bool JumpThreadingPass::threadGuard(BasicBlock *BB, IntrinsicInst *Guard, BranchInst *BI) { assert(BI->getNumSuccessors() == 2 && "Wrong number of successors?"); assert(BI->isConditional() && "Unconditional branch has 2 successors?"); diff --git a/llvm/lib/Transforms/Scalar/LICM.cpp b/llvm/lib/Transforms/Scalar/LICM.cpp index 1a22edaf8726..d2b4ba296f41 100644 --- a/llvm/lib/Transforms/Scalar/LICM.cpp +++ b/llvm/lib/Transforms/Scalar/LICM.cpp @@ -12,6 +12,13 @@ // safe. This pass also promotes must-aliased memory locations in the loop to // live in registers, thus hoisting and sinking "invariant" loads and stores. // +// Hoisting operations out of loops is a canonicalization transform. It +// enables and simplifies subsequent optimizations in the middle-end. +// Rematerialization of hoisted instructions to reduce register pressure is the +// responsibility of the back-end, which has more accurate information about +// register pressure and also handles other optimizations than LICM that +// increase live-ranges. +// // This pass uses alias analysis for two purposes: // // 1. Moving loop invariant loads and calls out of loops. If we can determine @@ -35,10 +42,12 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasSetTracker.h" #include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/CaptureTracking.h" #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/GuardUtils.h" +#include "llvm/Analysis/LazyBlockFrequencyInfo.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopIterator.h" @@ -98,6 +107,11 @@ static cl::opt ControlFlowHoisting( "licm-control-flow-hoisting", cl::Hidden, cl::init(false), cl::desc("Enable control flow (and PHI) hoisting in LICM")); +static cl::opt HoistSinkColdnessThreshold( + "licm-coldness-threshold", cl::Hidden, cl::init(4), + cl::desc("Relative coldness Threshold of hoisting/sinking destination " + "block for LICM to be considered beneficial")); + static cl::opt MaxNumUsesTraversed( "licm-max-num-uses-traversed", cl::Hidden, cl::init(8), cl::desc("Max num uses visited for identifying load " @@ -143,8 +157,9 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop, MemorySSAUpdater *MSSAU, ScalarEvolution *SE, OptimizationRemarkEmitter *ORE); static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, - const Loop *CurLoop, ICFLoopSafetyInfo *SafetyInfo, - MemorySSAUpdater *MSSAU, OptimizationRemarkEmitter *ORE); + BlockFrequencyInfo *BFI, const Loop *CurLoop, + ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU, + OptimizationRemarkEmitter *ORE); static bool isSafeToExecuteUnconditionally(Instruction &Inst, const DominatorTree *DT, const Loop *CurLoop, @@ -155,8 +170,10 @@ static bool pointerInvalidatedByLoop(MemoryLocation MemLoc, AliasSetTracker *CurAST, Loop *CurLoop, AAResults *AA); static bool pointerInvalidatedByLoopWithMSSA(MemorySSA *MSSA, MemoryUse *MU, - Loop *CurLoop, + Loop *CurLoop, Instruction &I, SinkAndHoistLICMFlags &Flags); +static bool pointerInvalidatedByBlockWithMSSA(BasicBlock &BB, MemorySSA &MSSA, + MemoryUse &MU); static Instruction *cloneInstructionInExitBlock( Instruction &I, BasicBlock &ExitBlock, PHINode &PN, const LoopInfo *LI, const LoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU); @@ -171,8 +188,8 @@ static void moveInstructionBefore(Instruction &I, Instruction &Dest, namespace { struct LoopInvariantCodeMotion { bool runOnLoop(Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT, - TargetLibraryInfo *TLI, TargetTransformInfo *TTI, - ScalarEvolution *SE, MemorySSA *MSSA, + BlockFrequencyInfo *BFI, TargetLibraryInfo *TLI, + TargetTransformInfo *TTI, ScalarEvolution *SE, MemorySSA *MSSA, OptimizationRemarkEmitter *ORE); LoopInvariantCodeMotion(unsigned LicmMssaOptCap, @@ -204,23 +221,30 @@ struct LegacyLICMPass : public LoopPass { if (skipLoop(L)) return false; + LLVM_DEBUG(dbgs() << "Perform LICM on Loop with header at block " + << L->getHeader()->getNameOrAsOperand() << "\n"); + auto *SE = getAnalysisIfAvailable(); MemorySSA *MSSA = EnableMSSALoopDependency ? (&getAnalysis().getMSSA()) : nullptr; + bool hasProfileData = L->getHeader()->getParent()->hasProfileData(); + BlockFrequencyInfo *BFI = + hasProfileData ? &getAnalysis().getBFI() + : nullptr; // For the old PM, we can't use OptimizationRemarkEmitter as an analysis - // pass. Function analyses need to be preserved across loop transformations + // pass. Function analyses need to be preserved across loop transformations // but ORE cannot be preserved (see comment before the pass definition). OptimizationRemarkEmitter ORE(L->getHeader()->getParent()); - return LICM.runOnLoop(L, - &getAnalysis().getAAResults(), - &getAnalysis().getLoopInfo(), - &getAnalysis().getDomTree(), - &getAnalysis().getTLI( - *L->getHeader()->getParent()), - &getAnalysis().getTTI( - *L->getHeader()->getParent()), - SE ? &SE->getSE() : nullptr, MSSA, &ORE); + return LICM.runOnLoop( + L, &getAnalysis().getAAResults(), + &getAnalysis().getLoopInfo(), + &getAnalysis().getDomTree(), BFI, + &getAnalysis().getTLI( + *L->getHeader()->getParent()), + &getAnalysis().getTTI( + *L->getHeader()->getParent()), + SE ? &SE->getSE() : nullptr, MSSA, &ORE); } /// This transformation requires natural loop information & requires that @@ -236,6 +260,9 @@ struct LegacyLICMPass : public LoopPass { } AU.addRequired(); getLoopAnalysisUsage(AU); + LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU); + AU.addPreserved(); + AU.addPreserved(); } private: @@ -251,8 +278,8 @@ PreservedAnalyses LICMPass::run(Loop &L, LoopAnalysisManager &AM, OptimizationRemarkEmitter ORE(L.getHeader()->getParent()); LoopInvariantCodeMotion LICM(LicmMssaOptCap, LicmMssaNoAccForPromotionCap); - if (!LICM.runOnLoop(&L, &AR.AA, &AR.LI, &AR.DT, &AR.TLI, &AR.TTI, &AR.SE, - AR.MSSA, &ORE)) + if (!LICM.runOnLoop(&L, &AR.AA, &AR.LI, &AR.DT, AR.BFI, &AR.TLI, &AR.TTI, + &AR.SE, AR.MSSA, &ORE)) return PreservedAnalyses::all(); auto PA = getLoopPassPreservedAnalyses(); @@ -272,6 +299,7 @@ INITIALIZE_PASS_DEPENDENCY(LoopPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) +INITIALIZE_PASS_DEPENDENCY(LazyBFIPass) INITIALIZE_PASS_END(LegacyLICMPass, "licm", "Loop Invariant Code Motion", false, false) @@ -281,13 +309,42 @@ Pass *llvm::createLICMPass(unsigned LicmMssaOptCap, return new LegacyLICMPass(LicmMssaOptCap, LicmMssaNoAccForPromotionCap); } +llvm::SinkAndHoistLICMFlags::SinkAndHoistLICMFlags(bool IsSink, Loop *L, + MemorySSA *MSSA) + : SinkAndHoistLICMFlags(SetLicmMssaOptCap, SetLicmMssaNoAccForPromotionCap, + IsSink, L, MSSA) {} + +llvm::SinkAndHoistLICMFlags::SinkAndHoistLICMFlags( + unsigned LicmMssaOptCap, unsigned LicmMssaNoAccForPromotionCap, bool IsSink, + Loop *L, MemorySSA *MSSA) + : LicmMssaOptCap(LicmMssaOptCap), + LicmMssaNoAccForPromotionCap(LicmMssaNoAccForPromotionCap), + IsSink(IsSink) { + assert(((L != nullptr) == (MSSA != nullptr)) && + "Unexpected values for SinkAndHoistLICMFlags"); + if (!MSSA) + return; + + unsigned AccessCapCount = 0; + for (auto *BB : L->getBlocks()) + if (const auto *Accesses = MSSA->getBlockAccesses(BB)) + for (const auto &MA : *Accesses) { + (void)MA; + ++AccessCapCount; + if (AccessCapCount > LicmMssaNoAccForPromotionCap) { + NoOfMemAccTooLarge = true; + return; + } + } +} + /// Hoist expressions out of the specified loop. Note, alias info for inner /// loop is not preserved so it is not a good idea to run LICM multiple /// times on one loop. bool LoopInvariantCodeMotion::runOnLoop( Loop *L, AAResults *AA, LoopInfo *LI, DominatorTree *DT, - TargetLibraryInfo *TLI, TargetTransformInfo *TTI, ScalarEvolution *SE, - MemorySSA *MSSA, OptimizationRemarkEmitter *ORE) { + BlockFrequencyInfo *BFI, TargetLibraryInfo *TLI, TargetTransformInfo *TTI, + ScalarEvolution *SE, MemorySSA *MSSA, OptimizationRemarkEmitter *ORE) { bool Changed = false; assert(L->isLCSSAForm(*DT) && "Loop is not in LCSSA form."); @@ -300,31 +357,18 @@ bool LoopInvariantCodeMotion::runOnLoop( std::unique_ptr CurAST; std::unique_ptr MSSAU; - bool NoOfMemAccTooLarge = false; - unsigned LicmMssaOptCounter = 0; + std::unique_ptr Flags; if (!MSSA) { LLVM_DEBUG(dbgs() << "LICM: Using Alias Set Tracker.\n"); CurAST = collectAliasInfoForLoop(L, LI, AA); + Flags = std::make_unique( + LicmMssaOptCap, LicmMssaNoAccForPromotionCap, /*IsSink=*/true); } else { LLVM_DEBUG(dbgs() << "LICM: Using MemorySSA.\n"); MSSAU = std::make_unique(MSSA); - - unsigned AccessCapCount = 0; - for (auto *BB : L->getBlocks()) { - if (auto *Accesses = MSSA->getBlockAccesses(BB)) { - for (const auto &MA : *Accesses) { - (void)MA; - AccessCapCount++; - if (AccessCapCount > LicmMssaNoAccForPromotionCap) { - NoOfMemAccTooLarge = true; - break; - } - } - } - if (NoOfMemAccTooLarge) - break; - } + Flags = std::make_unique( + LicmMssaOptCap, LicmMssaNoAccForPromotionCap, /*IsSink=*/true, L, MSSA); } // Get the preheader block to move instructions into... @@ -343,17 +387,15 @@ bool LoopInvariantCodeMotion::runOnLoop( // that we are guaranteed to see definitions before we see uses. This allows // us to sink instructions in one pass, without iteration. After sinking // instructions, we perform another pass to hoist them out of the loop. - SinkAndHoistLICMFlags Flags = {NoOfMemAccTooLarge, LicmMssaOptCounter, - LicmMssaOptCap, LicmMssaNoAccForPromotionCap, - /*IsSink=*/true}; if (L->hasDedicatedExits()) - Changed |= sinkRegion(DT->getNode(L->getHeader()), AA, LI, DT, TLI, TTI, L, - CurAST.get(), MSSAU.get(), &SafetyInfo, Flags, ORE); - Flags.IsSink = false; - if (Preheader) Changed |= - hoistRegion(DT->getNode(L->getHeader()), AA, LI, DT, TLI, L, - CurAST.get(), MSSAU.get(), SE, &SafetyInfo, Flags, ORE); + sinkRegion(DT->getNode(L->getHeader()), AA, LI, DT, BFI, TLI, TTI, L, + CurAST.get(), MSSAU.get(), &SafetyInfo, *Flags.get(), ORE); + Flags->setIsSink(false); + if (Preheader) + Changed |= hoistRegion(DT->getNode(L->getHeader()), AA, LI, DT, BFI, TLI, L, + CurAST.get(), MSSAU.get(), SE, &SafetyInfo, + *Flags.get(), ORE); // Now that all loop invariants have been removed from the loop, promote any // memory references to scalars that we can. @@ -363,7 +405,7 @@ bool LoopInvariantCodeMotion::runOnLoop( // preheader for SSA updater, so also avoid sinking when no preheader // is available. if (!DisablePromotion && Preheader && L->hasDedicatedExits() && - !NoOfMemAccTooLarge) { + !Flags->tooManyMemoryAccesses()) { // Figure out the loop exits and their insertion points SmallVector ExitBlocks; L->getUniqueExitBlocks(ExitBlocks); @@ -432,7 +474,7 @@ bool LoopInvariantCodeMotion::runOnLoop( // specifically moving instructions across the loop boundary and so it is // especially in need of sanity checking here. assert(L->isLCSSAForm(*DT) && "Loop not left in LCSSA form after LICM!"); - assert((!L->getParentLoop() || L->getParentLoop()->isLCSSAForm(*DT)) && + assert((L->isOutermost() || L->getParentLoop()->isLCSSAForm(*DT)) && "Parent loop not left in LCSSA form after LICM!"); if (MSSAU.get() && VerifyMemorySSA) @@ -449,10 +491,10 @@ bool LoopInvariantCodeMotion::runOnLoop( /// definitions, allowing us to sink a loop body in one pass without iteration. /// bool llvm::sinkRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI, - DominatorTree *DT, TargetLibraryInfo *TLI, - TargetTransformInfo *TTI, Loop *CurLoop, - AliasSetTracker *CurAST, MemorySSAUpdater *MSSAU, - ICFLoopSafetyInfo *SafetyInfo, + DominatorTree *DT, BlockFrequencyInfo *BFI, + TargetLibraryInfo *TLI, TargetTransformInfo *TTI, + Loop *CurLoop, AliasSetTracker *CurAST, + MemorySSAUpdater *MSSAU, ICFLoopSafetyInfo *SafetyInfo, SinkAndHoistLICMFlags &Flags, OptimizationRemarkEmitter *ORE) { @@ -501,7 +543,7 @@ bool llvm::sinkRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI, isNotUsedOrFreeInLoop(I, CurLoop, SafetyInfo, TTI, FreeInLoop) && canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, MSSAU, true, &Flags, ORE)) { - if (sink(I, LI, DT, CurLoop, SafetyInfo, MSSAU, ORE)) { + if (sink(I, LI, DT, BFI, CurLoop, SafetyInfo, MSSAU, ORE)) { if (!FreeInLoop) { ++II; salvageDebugInfo(I); @@ -585,7 +627,7 @@ public: else if (!TrueDestSucc.empty()) { Function *F = TrueDest->getParent(); auto IsSucc = [&](BasicBlock &BB) { return TrueDestSucc.count(&BB); }; - auto It = std::find_if(F->begin(), F->end(), IsSucc); + auto It = llvm::find_if(*F, IsSucc); assert(It != F->end() && "Could not find successor in function"); CommonSucc = &*It; } @@ -653,15 +695,15 @@ public: return BB != Pair.second && (Pair.first->getSuccessor(0) == BB || Pair.first->getSuccessor(1) == BB); }; - auto It = std::find_if(HoistableBranches.begin(), HoistableBranches.end(), - HasBBAsSuccessor); + auto It = llvm::find_if(HoistableBranches, HasBBAsSuccessor); // If not involved in a pending branch, hoist to preheader BasicBlock *InitialPreheader = CurLoop->getLoopPreheader(); if (It == HoistableBranches.end()) { - LLVM_DEBUG(dbgs() << "LICM using " << InitialPreheader->getName() - << " as hoist destination for " << BB->getName() - << "\n"); + LLVM_DEBUG(dbgs() << "LICM using " + << InitialPreheader->getNameOrAsOperand() + << " as hoist destination for " + << BB->getNameOrAsOperand() << "\n"); HoistDestinationMap[BB] = InitialPreheader; return InitialPreheader; } @@ -746,13 +788,43 @@ public: }; } // namespace +// Hoisting/sinking instruction out of a loop isn't always beneficial. It's only +// only worthwhile if the destination block is actually colder than current +// block. +static bool worthSinkOrHoistInst(Instruction &I, BasicBlock *DstBlock, + OptimizationRemarkEmitter *ORE, + BlockFrequencyInfo *BFI) { + // Check block frequency only when runtime profile is available + // to avoid pathological cases. With static profile, lean towards + // hosting because it helps canonicalize the loop for vectorizer. + if (!DstBlock->getParent()->hasProfileData()) + return true; + + if (!HoistSinkColdnessThreshold || !BFI) + return true; + + BasicBlock *SrcBlock = I.getParent(); + if (BFI->getBlockFreq(DstBlock).getFrequency() / HoistSinkColdnessThreshold > + BFI->getBlockFreq(SrcBlock).getFrequency()) { + ORE->emit([&]() { + return OptimizationRemarkMissed(DEBUG_TYPE, "SinkHoistInst", &I) + << "failed to sink or hoist instruction because containing block " + "has lower frequency than destination block"; + }); + return false; + } + + return true; +} + /// Walk the specified region of the CFG (defined by all blocks dominated by /// the specified block, and that are in the current loop) in depth first /// order w.r.t the DominatorTree. This allows us to visit definitions before /// uses, allowing us to hoist a loop body in one pass without iteration. /// bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI, - DominatorTree *DT, TargetLibraryInfo *TLI, Loop *CurLoop, + DominatorTree *DT, BlockFrequencyInfo *BFI, + TargetLibraryInfo *TLI, Loop *CurLoop, AliasSetTracker *CurAST, MemorySSAUpdater *MSSAU, ScalarEvolution *SE, ICFLoopSafetyInfo *SafetyInfo, SinkAndHoistLICMFlags &Flags, @@ -803,13 +875,15 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI, // Try hoisting the instruction out to the preheader. We can only do // this if all of the operands of the instruction are loop invariant and - // if it is safe to hoist the instruction. + // if it is safe to hoist the instruction. We also check block frequency + // to make sure instruction only gets hoisted into colder blocks. // TODO: It may be safe to hoist if we are hoisting to a conditional block // and we have accurately duplicated the control flow from the loop header // to that block. if (CurLoop->hasLoopInvariantOperands(&I) && canSinkOrHoistInst(I, AA, DT, CurLoop, CurAST, MSSAU, true, &Flags, ORE) && + worthSinkOrHoistInst(I, CurLoop->getLoopPreheader(), ORE, BFI) && isSafeToExecuteUnconditionally( I, DT, CurLoop, SafetyInfo, ORE, CurLoop->getLoopPreheader()->getTerminator())) { @@ -908,7 +982,7 @@ bool llvm::hoistRegion(DomTreeNode *N, AAResults *AA, LoopInfo *LI, HoistPoint = Dominator->getTerminator(); } LLVM_DEBUG(dbgs() << "LICM rehoisting to " - << HoistPoint->getParent()->getName() + << HoistPoint->getParent()->getNameOrAsOperand() << ": " << *I << "\n"); moveInstructionBefore(*I, *HoistPoint, *SafetyInfo, MSSAU, SE); HoistPoint = I; @@ -940,7 +1014,19 @@ static bool isLoadInvariantInLoop(LoadInst *LI, DominatorTree *DT, Loop *CurLoop) { Value *Addr = LI->getOperand(0); const DataLayout &DL = LI->getModule()->getDataLayout(); - const uint32_t LocSizeInBits = DL.getTypeSizeInBits(LI->getType()); + const TypeSize LocSizeInBits = DL.getTypeSizeInBits(LI->getType()); + + // It is not currently possible for clang to generate an invariant.start + // intrinsic with scalable vector types because we don't support thread local + // sizeless types and we don't permit sizeless types in structs or classes. + // Furthermore, even if support is added for this in future the intrinsic + // itself is defined to have a size of -1 for variable sized objects. This + // makes it impossible to verify if the intrinsic envelops our region of + // interest. For example, both and + // types would have a -1 parameter, but the former is clearly double the size + // of the latter. + if (LocSizeInBits.isScalable()) + return false; // if the type is i8 addrspace(x)*, we know this is the type of // llvm.invariant.start operand @@ -970,13 +1056,17 @@ static bool isLoadInvariantInLoop(LoadInst *LI, DominatorTree *DT, if (!II || II->getIntrinsicID() != Intrinsic::invariant_start || !II->use_empty()) continue; - unsigned InvariantSizeInBits = - cast(II->getArgOperand(0))->getSExtValue() * 8; + ConstantInt *InvariantSize = cast(II->getArgOperand(0)); + // The intrinsic supports having a -1 argument for variable sized objects + // so we should check for that here. + if (InvariantSize->isNegative()) + continue; + uint64_t InvariantSizeInBits = InvariantSize->getSExtValue() * 8; // Confirm the invariant.start location size contains the load operand size // in bits. Also, the invariant.start should dominate the load, and we // should not hoist the load out of a loop that contains this dominating // invariant.start. - if (LocSizeInBits <= InvariantSizeInBits && + if (LocSizeInBits.getFixedSize() <= InvariantSizeInBits && DT->properlyDominates(II->getParent(), CurLoop->getHeader())) return true; } @@ -1041,6 +1131,9 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, bool TargetExecutesOncePerLoop, SinkAndHoistLICMFlags *Flags, OptimizationRemarkEmitter *ORE) { + assert(((CurAST != nullptr) ^ (MSSAU != nullptr)) && + "Either AliasSetTracker or MemorySSA should be initialized."); + // If we don't understand the instruction, bail early. if (!isHoistableAndSinkableInst(I)) return false; @@ -1074,7 +1167,7 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, CurLoop, AA); else Invalidated = pointerInvalidatedByLoopWithMSSA( - MSSA, cast(MSSA->getMemoryAccess(LI)), CurLoop, *Flags); + MSSA, cast(MSSA->getMemoryAccess(LI)), CurLoop, I, *Flags); // Check loop-invariant address because this may also be a sinkable load // whose address is not necessarily loop-invariant. if (ORE && Invalidated && CurLoop->isLoopInvariant(LI->getPointerOperand())) @@ -1095,6 +1188,13 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, if (CI->mayThrow()) return false; + // Convergent attribute has been used on operations that involve + // inter-thread communication which results are implicitly affected by the + // enclosing control flows. It is not safe to hoist or sink such operations + // across control flow. + if (CI->isConvergent()) + return false; + using namespace PatternMatch; if (match(CI, m_Intrinsic())) // Assumes don't actually alias anything or throw @@ -1119,11 +1219,10 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, bool Invalidated; if (CurAST) Invalidated = pointerInvalidatedByLoop( - MemoryLocation(Op, LocationSize::unknown(), AAMDNodes()), - CurAST, CurLoop, AA); + MemoryLocation::getBeforeOrAfter(Op), CurAST, CurLoop, AA); else Invalidated = pointerInvalidatedByLoopWithMSSA( - MSSA, cast(MSSA->getMemoryAccess(CI)), CurLoop, + MSSA, cast(MSSA->getMemoryAccess(CI)), CurLoop, I, *Flags); if (Invalidated) return false; @@ -1183,12 +1282,9 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, } else { // MSSAU if (isOnlyMemoryAccess(SI, CurLoop, MSSAU)) return true; - // If there are more accesses than the Promotion cap, give up, we're not - // walking a list that long. - if (Flags->NoOfMemAccTooLarge) - return false; - // Check store only if there's still "quota" to check clobber. - if (Flags->LicmMssaOptCounter >= Flags->LicmMssaOptCap) + // If there are more accesses than the Promotion cap or no "quota" to + // check clobber, then give up as we're not walking a list that long. + if (Flags->tooManyMemoryAccesses() || Flags->tooManyClobberingCalls()) return false; // If there are interfering Uses (i.e. their defining access is in the // loop), or ordered loads (stored as Defs!), don't move this store. @@ -1208,7 +1304,7 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, // Uses may point to an access outside the loop, as getClobbering // checks the previous iteration when walking the backedge. // FIXME: More precise: no Uses that alias SI. - if (!Flags->IsSink && !MSSA->dominates(SIMD, MU)) + if (!Flags->getIsSink() && !MSSA->dominates(SIMD, MU)) return false; } else if (const auto *MD = dyn_cast(&MA)) { if (auto *LI = dyn_cast(MD->getMemoryInst())) { @@ -1227,9 +1323,8 @@ bool llvm::canSinkOrHoistInst(Instruction &I, AAResults *AA, DominatorTree *DT, } } } - auto *Source = MSSA->getSkipSelfWalker()->getClobberingMemoryAccess(SI); - Flags->LicmMssaOptCounter++; + Flags->incrementClobberingCalls(); // If there are no clobbering Defs in the loop, store is safe to hoist. return MSSA->isLiveOnEntryDef(Source) || !CurLoop->contains(Source->getBlock()); @@ -1529,8 +1624,9 @@ static void splitPredecessorsOfLoopExit(PHINode *PN, DominatorTree *DT, /// position, and may either delete it or move it to outside of the loop. /// static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, - const Loop *CurLoop, ICFLoopSafetyInfo *SafetyInfo, - MemorySSAUpdater *MSSAU, OptimizationRemarkEmitter *ORE) { + BlockFrequencyInfo *BFI, const Loop *CurLoop, + ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU, + OptimizationRemarkEmitter *ORE) { LLVM_DEBUG(dbgs() << "LICM sinking instruction: " << I << "\n"); ORE->emit([&]() { return OptimizationRemark(DEBUG_TYPE, "InstSunk", &I) @@ -1606,7 +1702,10 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, // If this instruction is only used outside of the loop, then all users are // PHI nodes in exit blocks due to LCSSA form. Just RAUW them with clones of // the instruction. + // First check if I is worth sinking for all uses. Sink only when it is worth + // across all uses. SmallSetVector Users(I.user_begin(), I.user_end()); + SmallVector ExitPNs; for (auto *UI : Users) { auto *User = cast(UI); @@ -1616,6 +1715,15 @@ static bool sink(Instruction &I, LoopInfo *LI, DominatorTree *DT, PHINode *PN = cast(User); assert(ExitBlockSet.count(PN->getParent()) && "The LCSSA PHI is not in an exit block!"); + if (!worthSinkOrHoistInst(I, PN->getParent(), ORE, BFI)) { + return Changed; + } + + ExitPNs.push_back(PN); + } + + for (auto *PN : ExitPNs) { + // The PHI must be trivially replaceable. Instruction *New = sinkThroughTriviallyReplaceablePHI( PN, &I, LI, SunkCopies, SafetyInfo, CurLoop, MSSAU); @@ -1633,8 +1741,8 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop, BasicBlock *Dest, ICFLoopSafetyInfo *SafetyInfo, MemorySSAUpdater *MSSAU, ScalarEvolution *SE, OptimizationRemarkEmitter *ORE) { - LLVM_DEBUG(dbgs() << "LICM hoisting to " << Dest->getName() << ": " << I - << "\n"); + LLVM_DEBUG(dbgs() << "LICM hoisting to " << Dest->getNameOrAsOperand() << ": " + << I << "\n"); ORE->emit([&]() { return OptimizationRemark(DEBUG_TYPE, "Hoisted", &I) << "hoisting " << ore::NV("Inst", &I); @@ -1658,10 +1766,7 @@ static void hoist(Instruction &I, const DominatorTree *DT, const Loop *CurLoop, // Move the new node to the destination block, before its terminator. moveInstructionBefore(I, *Dest->getTerminator(), *SafetyInfo, MSSAU, SE); - // Apply line 0 debug locations when we are moving instructions to different - // basic blocks because we want to avoid jumpy line tables. - if (const DebugLoc &DL = I.getDebugLoc()) - I.setDebugLoc(DebugLoc::get(0, 0, DL.getScope(), DL.getInlinedAt())); + I.updateLocationAfterHoist(); if (isa(I)) ++NumMovedLoads; @@ -1707,7 +1812,7 @@ class LoopPromoter : public LoadAndStorePromoter { SmallVectorImpl &LoopInsertPts; SmallVectorImpl &MSSAInsertPts; PredIteratorCache &PredCache; - AliasSetTracker &AST; + AliasSetTracker *AST; MemorySSAUpdater *MSSAU; LoopInfo &LI; DebugLoc DL; @@ -1737,7 +1842,7 @@ public: SmallVectorImpl &LEB, SmallVectorImpl &LIP, SmallVectorImpl &MSSAIP, PredIteratorCache &PIC, - AliasSetTracker &ast, MemorySSAUpdater *MSSAU, LoopInfo &li, + AliasSetTracker *ast, MemorySSAUpdater *MSSAU, LoopInfo &li, DebugLoc dl, int alignment, bool UnorderedAtomic, const AAMDNodes &AATags, ICFLoopSafetyInfo &SafetyInfo) : LoadAndStorePromoter(Insts, S), SomePtr(SP), PointerMustAliases(PMA), @@ -1794,11 +1899,13 @@ public: void replaceLoadWithValue(LoadInst *LI, Value *V) const override { // Update alias analysis. - AST.copyValue(LI, V); + if (AST) + AST->copyValue(LI, V); } void instructionDeleted(Instruction *I) const override { SafetyInfo.removeInstruction(I); - AST.deleteValue(I); + if (AST) + AST->deleteValue(I); if (MSSAU) MSSAU->removeMemoryAccess(I); } @@ -1844,7 +1951,7 @@ bool llvm::promoteLoopAccessesToScalars( ICFLoopSafetyInfo *SafetyInfo, OptimizationRemarkEmitter *ORE) { // Verify inputs. assert(LI != nullptr && DT != nullptr && CurLoop != nullptr && - CurAST != nullptr && SafetyInfo != nullptr && + SafetyInfo != nullptr && "Unexpected Input to promoteLoopAccessesToScalars"); Value *SomePtr = *PointerMustAliases.begin(); @@ -1909,7 +2016,7 @@ bool llvm::promoteLoopAccessesToScalars( // we have to prove that the store is dead along the unwind edge. We do // this by proving that the caller can't have a reference to the object // after return and thus can't possibly load from the object. - Value *Object = GetUnderlyingObject(SomePtr, MDL); + Value *Object = getUnderlyingObject(SomePtr); if (!isKnownNonEscaping(Object, TLI)) return false; // Subtlety: Alloca's aren't visible to callers, but *are* potentially @@ -2041,7 +2148,7 @@ bool llvm::promoteLoopAccessesToScalars( if (IsKnownThreadLocalObject) SafeToInsertStore = true; else { - Value *Object = GetUnderlyingObject(SomePtr, MDL); + Value *Object = getUnderlyingObject(SomePtr); SafeToInsertStore = (isAllocLikeFn(Object, TLI) || isa(Object)) && !PointerMayBeCaptured(Object, true, true); @@ -2072,7 +2179,7 @@ bool llvm::promoteLoopAccessesToScalars( SmallVector NewPHIs; SSAUpdater SSA(&NewPHIs); LoopPromoter Promoter(SomePtr, LoopUses, SSA, PointerMustAliases, ExitBlocks, - InsertPts, MSSAInsertPts, PIC, *CurAST, MSSAU, *LI, DL, + InsertPts, MSSAInsertPts, PIC, CurAST, MSSAU, *LI, DL, Alignment.value(), SawUnorderedAtomic, AATags, *SafetyInfo); @@ -2187,18 +2294,18 @@ static bool pointerInvalidatedByLoop(MemoryLocation MemLoc, return false; } -static bool pointerInvalidatedByLoopWithMSSA(MemorySSA *MSSA, MemoryUse *MU, - Loop *CurLoop, - SinkAndHoistLICMFlags &Flags) { +bool pointerInvalidatedByLoopWithMSSA(MemorySSA *MSSA, MemoryUse *MU, + Loop *CurLoop, Instruction &I, + SinkAndHoistLICMFlags &Flags) { // For hoisting, use the walker to determine safety - if (!Flags.IsSink) { + if (!Flags.getIsSink()) { MemoryAccess *Source; // See declaration of SetLicmMssaOptCap for usage details. - if (Flags.LicmMssaOptCounter >= Flags.LicmMssaOptCap) + if (Flags.tooManyClobberingCalls()) Source = MU->getDefiningAccess(); else { Source = MSSA->getSkipSelfWalker()->getClobberingMemoryAccess(MU); - Flags.LicmMssaOptCounter++; + Flags.incrementClobberingCalls(); } return !MSSA->isLiveOnEntryDef(Source) && CurLoop->contains(Source->getBlock()); @@ -2221,15 +2328,25 @@ static bool pointerInvalidatedByLoopWithMSSA(MemorySSA *MSSA, MemoryUse *MU, // FIXME: Increase precision: Safe to sink if Use post dominates the Def; // needs PostDominatorTreeAnalysis. // FIXME: More precise: no Defs that alias this Use. - if (Flags.NoOfMemAccTooLarge) + if (Flags.tooManyMemoryAccesses()) return true; for (auto *BB : CurLoop->getBlocks()) - if (auto *Accesses = MSSA->getBlockDefs(BB)) - for (const auto &MA : *Accesses) - if (const auto *MD = dyn_cast(&MA)) - if (MU->getBlock() != MD->getBlock() || - !MSSA->locallyDominates(MD, MU)) - return true; + if (pointerInvalidatedByBlockWithMSSA(*BB, *MSSA, *MU)) + return true; + // When sinking, the source block may not be part of the loop so check it. + if (!CurLoop->contains(&I)) + return pointerInvalidatedByBlockWithMSSA(*I.getParent(), *MSSA, *MU); + + return false; +} + +bool pointerInvalidatedByBlockWithMSSA(BasicBlock &BB, MemorySSA &MSSA, + MemoryUse &MU) { + if (const auto *Accesses = MSSA.getBlockDefs(&BB)) + for (const auto &MA : *Accesses) + if (const auto *MD = dyn_cast(&MA)) + if (MU.getBlock() != MD->getBlock() || !MSSA.locallyDominates(MD, &MU)) + return true; return false; } diff --git a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp index 687e14d6d7d2..45cdcb2f37dd 100644 --- a/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDataPrefetch.cpp @@ -271,7 +271,7 @@ bool LoopDataPrefetch::runOnLoop(Loop *L) { bool MadeChange = false; // Only prefetch in the inner-most loop - if (!L->empty()) + if (!L->isInnermost()) return MadeChange; SmallPtrSet EphValues; diff --git a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp index be209d34be42..1266c93316fa 100644 --- a/llvm/lib/Transforms/Scalar/LoopDeletion.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDeletion.cpp @@ -26,6 +26,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Utils/LoopUtils.h" + using namespace llvm; #define DEBUG_TYPE "loop-delete" @@ -38,6 +39,14 @@ enum class LoopDeletionResult { Deleted, }; +static LoopDeletionResult merge(LoopDeletionResult A, LoopDeletionResult B) { + if (A == LoopDeletionResult::Deleted || B == LoopDeletionResult::Deleted) + return LoopDeletionResult::Deleted; + if (A == LoopDeletionResult::Modified || B == LoopDeletionResult::Modified) + return LoopDeletionResult::Modified; + return LoopDeletionResult::Unmodified; +} + /// Determines if a loop is dead. /// /// This assumes that we've already checked for unique exit and exiting blocks, @@ -53,26 +62,28 @@ static bool isLoopDead(Loop *L, ScalarEvolution &SE, // of the loop. bool AllEntriesInvariant = true; bool AllOutgoingValuesSame = true; - for (PHINode &P : ExitBlock->phis()) { - Value *incoming = P.getIncomingValueForBlock(ExitingBlocks[0]); - - // Make sure all exiting blocks produce the same incoming value for the exit - // block. If there are different incoming values for different exiting - // blocks, then it is impossible to statically determine which value should - // be used. - AllOutgoingValuesSame = - all_of(makeArrayRef(ExitingBlocks).slice(1), [&](BasicBlock *BB) { - return incoming == P.getIncomingValueForBlock(BB); - }); - - if (!AllOutgoingValuesSame) - break; - - if (Instruction *I = dyn_cast(incoming)) - if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator())) { - AllEntriesInvariant = false; + if (!L->hasNoExitBlocks()) { + for (PHINode &P : ExitBlock->phis()) { + Value *incoming = P.getIncomingValueForBlock(ExitingBlocks[0]); + + // Make sure all exiting blocks produce the same incoming value for the + // block. If there are different incoming values for different exiting + // blocks, then it is impossible to statically determine which value + // should be used. + AllOutgoingValuesSame = + all_of(makeArrayRef(ExitingBlocks).slice(1), [&](BasicBlock *BB) { + return incoming == P.getIncomingValueForBlock(BB); + }); + + if (!AllOutgoingValuesSame) break; - } + + if (Instruction *I = dyn_cast(incoming)) + if (!L->makeLoopInvariant(I, Changed, Preheader->getTerminator())) { + AllEntriesInvariant = false; + break; + } + } } if (Changed) @@ -85,7 +96,9 @@ static bool isLoopDead(Loop *L, ScalarEvolution &SE, // This includes instructions that could write to memory, and loads that are // marked volatile. for (auto &I : L->blocks()) - if (any_of(*I, [](Instruction &I) { return I.mayHaveSideEffects(); })) + if (any_of(*I, [](Instruction &I) { + return I.mayHaveSideEffects() && !I.isDroppable(); + })) return false; return true; } @@ -122,12 +135,33 @@ static bool isLoopNeverExecuted(Loop *L) { return true; } +/// If we can prove the backedge is untaken, remove it. This destroys the +/// loop, but leaves the (now trivially loop invariant) control flow and +/// side effects (if any) in place. +static LoopDeletionResult +breakBackedgeIfNotTaken(Loop *L, DominatorTree &DT, ScalarEvolution &SE, + LoopInfo &LI, MemorySSA *MSSA, + OptimizationRemarkEmitter &ORE) { + assert(L->isLCSSAForm(DT) && "Expected LCSSA!"); + + if (!L->getLoopLatch()) + return LoopDeletionResult::Unmodified; + + auto *BTC = SE.getBackedgeTakenCount(L); + if (!BTC->isZero()) + return LoopDeletionResult::Unmodified; + + breakLoopBackedge(L, DT, SE, LI, MSSA); + return LoopDeletionResult::Deleted; +} + /// Remove a loop if it is dead. /// -/// A loop is considered dead if it does not impact the observable behavior of -/// the program other than finite running time. This never removes a loop that -/// might be infinite (unless it is never executed), as doing so could change -/// the halting/non-halting nature of a program. +/// A loop is considered dead either if it does not impact the observable +/// behavior of the program other than finite running time, or if it is +/// required to make progress by an attribute such as 'mustprogress' or +/// 'llvm.loop.mustprogress' and does not make any. This may remove +/// infinite loops that have been required to make progress. /// /// This entire process relies pretty heavily on LoopSimplify form and LCSSA in /// order to make various safety checks work. @@ -151,18 +185,15 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT, << "Deletion requires Loop with preheader and dedicated exits.\n"); return LoopDeletionResult::Unmodified; } - // We can't remove loops that contain subloops. If the subloops were dead, - // they would already have been removed in earlier executions of this pass. - if (L->begin() != L->end()) { - LLVM_DEBUG(dbgs() << "Loop contains subloops.\n"); - return LoopDeletionResult::Unmodified; - } - BasicBlock *ExitBlock = L->getUniqueExitBlock(); if (ExitBlock && isLoopNeverExecuted(L)) { LLVM_DEBUG(dbgs() << "Loop is proven to never execute, delete it!"); + // We need to forget the loop before setting the incoming values of the exit + // phis to undef, so we properly invalidate the SCEV expressions for those + // phis. + SE.forgetLoop(L); // Set incoming value to undef for phi nodes in the exit block. for (PHINode &P : ExitBlock->phis()) { std::fill(P.incoming_values().begin(), P.incoming_values().end(), @@ -183,12 +214,12 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT, SmallVector ExitingBlocks; L->getExitingBlocks(ExitingBlocks); - // We require that the loop only have a single exit block. Otherwise, we'd - // be in the situation of needing to be able to solve statically which exit - // block will be branched to, or trying to preserve the branching logic in - // a loop invariant manner. - if (!ExitBlock) { - LLVM_DEBUG(dbgs() << "Deletion requires single exit block\n"); + // We require that the loop has at most one exit block. Otherwise, we'd be in + // the situation of needing to be able to solve statically which exit block + // will be branched to, or trying to preserve the branching logic in a loop + // invariant manner. + if (!ExitBlock && !L->hasNoExitBlocks()) { + LLVM_DEBUG(dbgs() << "Deletion requires at most one exit block.\n"); return LoopDeletionResult::Unmodified; } // Finally, we have to check that the loop really is dead. @@ -199,11 +230,13 @@ static LoopDeletionResult deleteLoopIfDead(Loop *L, DominatorTree &DT, : LoopDeletionResult::Unmodified; } - // Don't remove loops for which we can't solve the trip count. - // They could be infinite, in which case we'd be changing program behavior. + // Don't remove loops for which we can't solve the trip count unless the loop + // was required to make progress but has been determined to be dead. const SCEV *S = SE.getConstantMaxBackedgeTakenCount(L); - if (isa(S)) { - LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount.\n"); + if (isa(S) && + !L->getHeader()->getParent()->mustProgress() && !hasMustProgress(L)) { + LLVM_DEBUG(dbgs() << "Could not compute SCEV MaxBackedgeTakenCount and was " + "not required to make progress.\n"); return Changed ? LoopDeletionResult::Modified : LoopDeletionResult::Unmodified; } @@ -232,6 +265,14 @@ PreservedAnalyses LoopDeletionPass::run(Loop &L, LoopAnalysisManager &AM, // but ORE cannot be preserved (see comment before the pass definition). OptimizationRemarkEmitter ORE(L.getHeader()->getParent()); auto Result = deleteLoopIfDead(&L, AR.DT, AR.SE, AR.LI, AR.MSSA, ORE); + + // If we can prove the backedge isn't taken, just break it and be done. This + // leaves the loop structure in place which means it can handle dispatching + // to the right exit based on whatever loop invariant structure remains. + if (Result != LoopDeletionResult::Deleted) + Result = merge(Result, breakBackedgeIfNotTaken(&L, AR.DT, AR.SE, AR.LI, + AR.MSSA, ORE)); + if (Result == LoopDeletionResult::Unmodified) return PreservedAnalyses::all(); @@ -291,6 +332,12 @@ bool LoopDeletionLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) { LoopDeletionResult Result = deleteLoopIfDead(L, DT, SE, LI, MSSA, ORE); + // If we can prove the backedge isn't taken, just break it and be done. This + // leaves the loop structure in place which means it can handle dispatching + // to the right exit based on whatever loop invariant structure remains. + if (Result != LoopDeletionResult::Deleted) + Result = merge(Result, breakBackedgeIfNotTaken(L, DT, SE, LI, MSSA, ORE)); + if (Result == LoopDeletionResult::Deleted) LPM.markLoopAsDeleted(*L); diff --git a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp index 7867a5468891..1bd2529891b7 100644 --- a/llvm/lib/Transforms/Scalar/LoopDistribute.cpp +++ b/llvm/lib/Transforms/Scalar/LoopDistribute.cpp @@ -33,7 +33,6 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/LoopAccessAnalysis.h" @@ -664,21 +663,23 @@ public: /// Try to distribute an inner-most loop. bool processLoop(std::function &GetLAA) { - assert(L->empty() && "Only process inner loops."); + assert(L->isInnermost() && "Only process inner loops."); LLVM_DEBUG(dbgs() << "\nLDist: In \"" << L->getHeader()->getParent()->getName() << "\" checking " << *L << "\n"); + // Having a single exit block implies there's also one exiting block. if (!L->getExitBlock()) return fail("MultipleExitBlocks", "multiple exit blocks"); if (!L->isLoopSimplifyForm()) return fail("NotLoopSimplifyForm", "loop is not in loop-simplify form"); + if (!L->isRotatedForm()) + return fail("NotBottomTested", "loop is not bottom tested"); BasicBlock *PH = L->getLoopPreheader(); - // LAA will check that we only have a single exiting block. LAI = &GetLAA(*L); // Currently, we only distribute to isolate the part of the loop with @@ -814,9 +815,7 @@ public: LLVM_DEBUG(dbgs() << "\nPointers:\n"); LLVM_DEBUG(LAI->getRuntimePointerChecking()->printChecks(dbgs(), Checks)); - LoopVersioning LVer(*LAI, L, LI, DT, SE, false); - LVer.setAliasChecks(std::move(Checks)); - LVer.setSCEVChecks(LAI->getPSE().getUnionPredicate()); + LoopVersioning LVer(*LAI, Checks, L, LI, DT, SE); LVer.versionLoop(DefsUsedOutside); LVer.annotateLoopWithNoAlias(); @@ -982,7 +981,7 @@ static bool runImpl(Function &F, LoopInfo *LI, DominatorTree *DT, for (Loop *TopLevelLoop : *LI) for (Loop *L : depth_first(TopLevelLoop)) // We only handle inner-most loops. - if (L->empty()) + if (L->isInnermost()) Worklist.push_back(L); // Now walk the identified inner loops. @@ -1058,7 +1057,8 @@ PreservedAnalyses LoopDistributePass::run(Function &F, auto &LAM = AM.getResult(F).getManager(); std::function GetLAA = [&](Loop &L) -> const LoopAccessInfo & { - LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, TLI, TTI, nullptr}; + LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, + TLI, TTI, nullptr, nullptr}; return LAM.getResult(L, AR); }; diff --git a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp new file mode 100644 index 000000000000..aaff68436c13 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp @@ -0,0 +1,728 @@ +//===- LoopFlatten.cpp - Loop flattening pass------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass flattens pairs nested loops into a single loop. +// +// The intention is to optimise loop nests like this, which together access an +// array linearly: +// for (int i = 0; i < N; ++i) +// for (int j = 0; j < M; ++j) +// f(A[i*M+j]); +// into one loop: +// for (int i = 0; i < (N*M); ++i) +// f(A[i]); +// +// It can also flatten loops where the induction variables are not used in the +// loop. This is only worth doing if the induction variables are only used in an +// expression like i*M+j. If they had any other uses, we would have to insert a +// div/mod to reconstruct the original values, so this wouldn't be profitable. +// +// We also need to prove that N*M will not overflow. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/LoopFlatten.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/Analysis/ValueTracking.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/IR/Verifier.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/LoopUtils.h" +#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" +#include "llvm/Transforms/Utils/SimplifyIndVar.h" + +#define DEBUG_TYPE "loop-flatten" + +using namespace llvm; +using namespace llvm::PatternMatch; + +static cl::opt RepeatedInstructionThreshold( + "loop-flatten-cost-threshold", cl::Hidden, cl::init(2), + cl::desc("Limit on the cost of instructions that can be repeated due to " + "loop flattening")); + +static cl::opt + AssumeNoOverflow("loop-flatten-assume-no-overflow", cl::Hidden, + cl::init(false), + cl::desc("Assume that the product of the two iteration " + "limits will never overflow")); + +static cl::opt + WidenIV("loop-flatten-widen-iv", cl::Hidden, + cl::init(true), + cl::desc("Widen the loop induction variables, if possible, so " + "overflow checks won't reject flattening")); + +struct FlattenInfo { + Loop *OuterLoop = nullptr; + Loop *InnerLoop = nullptr; + PHINode *InnerInductionPHI = nullptr; + PHINode *OuterInductionPHI = nullptr; + Value *InnerLimit = nullptr; + Value *OuterLimit = nullptr; + BinaryOperator *InnerIncrement = nullptr; + BinaryOperator *OuterIncrement = nullptr; + BranchInst *InnerBranch = nullptr; + BranchInst *OuterBranch = nullptr; + SmallPtrSet LinearIVUses; + SmallPtrSet InnerPHIsToTransform; + + // Whether this holds the flatten info before or after widening. + bool Widened = false; + + FlattenInfo(Loop *OL, Loop *IL) : OuterLoop(OL), InnerLoop(IL) {}; +}; + +// Finds the induction variable, increment and limit for a simple loop that we +// can flatten. +static bool findLoopComponents( + Loop *L, SmallPtrSetImpl &IterationInstructions, + PHINode *&InductionPHI, Value *&Limit, BinaryOperator *&Increment, + BranchInst *&BackBranch, ScalarEvolution *SE) { + LLVM_DEBUG(dbgs() << "Finding components of loop: " << L->getName() << "\n"); + + if (!L->isLoopSimplifyForm()) { + LLVM_DEBUG(dbgs() << "Loop is not in normal form\n"); + return false; + } + + // There must be exactly one exiting block, and it must be the same at the + // latch. + BasicBlock *Latch = L->getLoopLatch(); + if (L->getExitingBlock() != Latch) { + LLVM_DEBUG(dbgs() << "Exiting and latch block are different\n"); + return false; + } + // Latch block must end in a conditional branch. + BackBranch = dyn_cast(Latch->getTerminator()); + if (!BackBranch || !BackBranch->isConditional()) { + LLVM_DEBUG(dbgs() << "Could not find back-branch\n"); + return false; + } + IterationInstructions.insert(BackBranch); + LLVM_DEBUG(dbgs() << "Found back branch: "; BackBranch->dump()); + bool ContinueOnTrue = L->contains(BackBranch->getSuccessor(0)); + + // Find the induction PHI. If there is no induction PHI, we can't do the + // transformation. TODO: could other variables trigger this? Do we have to + // search for the best one? + InductionPHI = nullptr; + for (PHINode &PHI : L->getHeader()->phis()) { + InductionDescriptor ID; + if (InductionDescriptor::isInductionPHI(&PHI, L, SE, ID)) { + InductionPHI = &PHI; + LLVM_DEBUG(dbgs() << "Found induction PHI: "; InductionPHI->dump()); + break; + } + } + if (!InductionPHI) { + LLVM_DEBUG(dbgs() << "Could not find induction PHI\n"); + return false; + } + + auto IsValidPredicate = [&](ICmpInst::Predicate Pred) { + if (ContinueOnTrue) + return Pred == CmpInst::ICMP_NE || Pred == CmpInst::ICMP_ULT; + else + return Pred == CmpInst::ICMP_EQ; + }; + + // Find Compare and make sure it is valid + ICmpInst *Compare = dyn_cast(BackBranch->getCondition()); + if (!Compare || !IsValidPredicate(Compare->getUnsignedPredicate()) || + Compare->hasNUsesOrMore(2)) { + LLVM_DEBUG(dbgs() << "Could not find valid comparison\n"); + return false; + } + IterationInstructions.insert(Compare); + LLVM_DEBUG(dbgs() << "Found comparison: "; Compare->dump()); + + // Find increment and limit from the compare + Increment = nullptr; + if (match(Compare->getOperand(0), + m_c_Add(m_Specific(InductionPHI), m_ConstantInt<1>()))) { + Increment = dyn_cast(Compare->getOperand(0)); + Limit = Compare->getOperand(1); + } else if (Compare->getUnsignedPredicate() == CmpInst::ICMP_NE && + match(Compare->getOperand(1), + m_c_Add(m_Specific(InductionPHI), m_ConstantInt<1>()))) { + Increment = dyn_cast(Compare->getOperand(1)); + Limit = Compare->getOperand(0); + } + if (!Increment || Increment->hasNUsesOrMore(3)) { + LLVM_DEBUG(dbgs() << "Cound not find valid increment\n"); + return false; + } + IterationInstructions.insert(Increment); + LLVM_DEBUG(dbgs() << "Found increment: "; Increment->dump()); + LLVM_DEBUG(dbgs() << "Found limit: "; Limit->dump()); + + assert(InductionPHI->getNumIncomingValues() == 2); + assert(InductionPHI->getIncomingValueForBlock(Latch) == Increment && + "PHI value is not increment inst"); + + auto *CI = dyn_cast( + InductionPHI->getIncomingValueForBlock(L->getLoopPreheader())); + if (!CI || !CI->isZero()) { + LLVM_DEBUG(dbgs() << "PHI value is not zero: "; CI->dump()); + return false; + } + + LLVM_DEBUG(dbgs() << "Successfully found all loop components\n"); + return true; +} + +static bool checkPHIs(struct FlattenInfo &FI, + const TargetTransformInfo *TTI) { + // All PHIs in the inner and outer headers must either be: + // - The induction PHI, which we are going to rewrite as one induction in + // the new loop. This is already checked by findLoopComponents. + // - An outer header PHI with all incoming values from outside the loop. + // LoopSimplify guarantees we have a pre-header, so we don't need to + // worry about that here. + // - Pairs of PHIs in the inner and outer headers, which implement a + // loop-carried dependency that will still be valid in the new loop. To + // be valid, this variable must be modified only in the inner loop. + + // The set of PHI nodes in the outer loop header that we know will still be + // valid after the transformation. These will not need to be modified (with + // the exception of the induction variable), but we do need to check that + // there are no unsafe PHI nodes. + SmallPtrSet SafeOuterPHIs; + SafeOuterPHIs.insert(FI.OuterInductionPHI); + + // Check that all PHI nodes in the inner loop header match one of the valid + // patterns. + for (PHINode &InnerPHI : FI.InnerLoop->getHeader()->phis()) { + // The induction PHIs break these rules, and that's OK because we treat + // them specially when doing the transformation. + if (&InnerPHI == FI.InnerInductionPHI) + continue; + + // Each inner loop PHI node must have two incoming values/blocks - one + // from the pre-header, and one from the latch. + assert(InnerPHI.getNumIncomingValues() == 2); + Value *PreHeaderValue = + InnerPHI.getIncomingValueForBlock(FI.InnerLoop->getLoopPreheader()); + Value *LatchValue = + InnerPHI.getIncomingValueForBlock(FI.InnerLoop->getLoopLatch()); + + // The incoming value from the outer loop must be the PHI node in the + // outer loop header, with no modifications made in the top of the outer + // loop. + PHINode *OuterPHI = dyn_cast(PreHeaderValue); + if (!OuterPHI || OuterPHI->getParent() != FI.OuterLoop->getHeader()) { + LLVM_DEBUG(dbgs() << "value modified in top of outer loop\n"); + return false; + } + + // The other incoming value must come from the inner loop, without any + // modifications in the tail end of the outer loop. We are in LCSSA form, + // so this will actually be a PHI in the inner loop's exit block, which + // only uses values from inside the inner loop. + PHINode *LCSSAPHI = dyn_cast( + OuterPHI->getIncomingValueForBlock(FI.OuterLoop->getLoopLatch())); + if (!LCSSAPHI) { + LLVM_DEBUG(dbgs() << "could not find LCSSA PHI\n"); + return false; + } + + // The value used by the LCSSA PHI must be the same one that the inner + // loop's PHI uses. + if (LCSSAPHI->hasConstantValue() != LatchValue) { + LLVM_DEBUG( + dbgs() << "LCSSA PHI incoming value does not match latch value\n"); + return false; + } + + LLVM_DEBUG(dbgs() << "PHI pair is safe:\n"); + LLVM_DEBUG(dbgs() << " Inner: "; InnerPHI.dump()); + LLVM_DEBUG(dbgs() << " Outer: "; OuterPHI->dump()); + SafeOuterPHIs.insert(OuterPHI); + FI.InnerPHIsToTransform.insert(&InnerPHI); + } + + for (PHINode &OuterPHI : FI.OuterLoop->getHeader()->phis()) { + if (!SafeOuterPHIs.count(&OuterPHI)) { + LLVM_DEBUG(dbgs() << "found unsafe PHI in outer loop: "; OuterPHI.dump()); + return false; + } + } + + LLVM_DEBUG(dbgs() << "checkPHIs: OK\n"); + return true; +} + +static bool +checkOuterLoopInsts(struct FlattenInfo &FI, + SmallPtrSetImpl &IterationInstructions, + const TargetTransformInfo *TTI) { + // Check for instructions in the outer but not inner loop. If any of these + // have side-effects then this transformation is not legal, and if there is + // a significant amount of code here which can't be optimised out that it's + // not profitable (as these instructions would get executed for each + // iteration of the inner loop). + unsigned RepeatedInstrCost = 0; + for (auto *B : FI.OuterLoop->getBlocks()) { + if (FI.InnerLoop->contains(B)) + continue; + + for (auto &I : *B) { + if (!isa(&I) && !I.isTerminator() && + !isSafeToSpeculativelyExecute(&I)) { + LLVM_DEBUG(dbgs() << "Cannot flatten because instruction may have " + "side effects: "; + I.dump()); + return false; + } + // The execution count of the outer loop's iteration instructions + // (increment, compare and branch) will be increased, but the + // equivalent instructions will be removed from the inner loop, so + // they make a net difference of zero. + if (IterationInstructions.count(&I)) + continue; + // The uncoditional branch to the inner loop's header will turn into + // a fall-through, so adds no cost. + BranchInst *Br = dyn_cast(&I); + if (Br && Br->isUnconditional() && + Br->getSuccessor(0) == FI.InnerLoop->getHeader()) + continue; + // Multiplies of the outer iteration variable and inner iteration + // count will be optimised out. + if (match(&I, m_c_Mul(m_Specific(FI.OuterInductionPHI), + m_Specific(FI.InnerLimit)))) + continue; + int Cost = TTI->getUserCost(&I, TargetTransformInfo::TCK_SizeAndLatency); + LLVM_DEBUG(dbgs() << "Cost " << Cost << ": "; I.dump()); + RepeatedInstrCost += Cost; + } + } + + LLVM_DEBUG(dbgs() << "Cost of instructions that will be repeated: " + << RepeatedInstrCost << "\n"); + // Bail out if flattening the loops would cause instructions in the outer + // loop but not in the inner loop to be executed extra times. + if (RepeatedInstrCost > RepeatedInstructionThreshold) { + LLVM_DEBUG(dbgs() << "checkOuterLoopInsts: not profitable, bailing.\n"); + return false; + } + + LLVM_DEBUG(dbgs() << "checkOuterLoopInsts: OK\n"); + return true; +} + +static bool checkIVUsers(struct FlattenInfo &FI) { + // We require all uses of both induction variables to match this pattern: + // + // (OuterPHI * InnerLimit) + InnerPHI + // + // Any uses of the induction variables not matching that pattern would + // require a div/mod to reconstruct in the flattened loop, so the + // transformation wouldn't be profitable. + + Value *InnerLimit = FI.InnerLimit; + if (FI.Widened && + (isa(InnerLimit) || isa(InnerLimit))) + InnerLimit = cast(InnerLimit)->getOperand(0); + + // Check that all uses of the inner loop's induction variable match the + // expected pattern, recording the uses of the outer IV. + SmallPtrSet ValidOuterPHIUses; + for (User *U : FI.InnerInductionPHI->users()) { + if (U == FI.InnerIncrement) + continue; + + // After widening the IVs, a trunc instruction might have been introduced, so + // look through truncs. + if (isa(U)) { + if (!U->hasOneUse()) + return false; + U = *U->user_begin(); + } + + LLVM_DEBUG(dbgs() << "Found use of inner induction variable: "; U->dump()); + + Value *MatchedMul; + Value *MatchedItCount; + bool IsAdd = match(U, m_c_Add(m_Specific(FI.InnerInductionPHI), + m_Value(MatchedMul))) && + match(MatchedMul, m_c_Mul(m_Specific(FI.OuterInductionPHI), + m_Value(MatchedItCount))); + + // Matches the same pattern as above, except it also looks for truncs + // on the phi, which can be the result of widening the induction variables. + bool IsAddTrunc = match(U, m_c_Add(m_Trunc(m_Specific(FI.InnerInductionPHI)), + m_Value(MatchedMul))) && + match(MatchedMul, + m_c_Mul(m_Trunc(m_Specific(FI.OuterInductionPHI)), + m_Value(MatchedItCount))); + + if ((IsAdd || IsAddTrunc) && MatchedItCount == InnerLimit) { + LLVM_DEBUG(dbgs() << "Use is optimisable\n"); + ValidOuterPHIUses.insert(MatchedMul); + FI.LinearIVUses.insert(U); + } else { + LLVM_DEBUG(dbgs() << "Did not match expected pattern, bailing\n"); + return false; + } + } + + // Check that there are no uses of the outer IV other than the ones found + // as part of the pattern above. + for (User *U : FI.OuterInductionPHI->users()) { + if (U == FI.OuterIncrement) + continue; + + auto IsValidOuterPHIUses = [&] (User *U) -> bool { + LLVM_DEBUG(dbgs() << "Found use of outer induction variable: "; U->dump()); + if (!ValidOuterPHIUses.count(U)) { + LLVM_DEBUG(dbgs() << "Did not match expected pattern, bailing\n"); + return false; + } + LLVM_DEBUG(dbgs() << "Use is optimisable\n"); + return true; + }; + + if (auto *V = dyn_cast(U)) { + for (auto *K : V->users()) { + if (!IsValidOuterPHIUses(K)) + return false; + } + continue; + } + + if (!IsValidOuterPHIUses(U)) + return false; + } + + LLVM_DEBUG(dbgs() << "checkIVUsers: OK\n"; + dbgs() << "Found " << FI.LinearIVUses.size() + << " value(s) that can be replaced:\n"; + for (Value *V : FI.LinearIVUses) { + dbgs() << " "; + V->dump(); + }); + return true; +} + +// Return an OverflowResult dependant on if overflow of the multiplication of +// InnerLimit and OuterLimit can be assumed not to happen. +static OverflowResult checkOverflow(struct FlattenInfo &FI, + DominatorTree *DT, AssumptionCache *AC) { + Function *F = FI.OuterLoop->getHeader()->getParent(); + const DataLayout &DL = F->getParent()->getDataLayout(); + + // For debugging/testing. + if (AssumeNoOverflow) + return OverflowResult::NeverOverflows; + + // Check if the multiply could not overflow due to known ranges of the + // input values. + OverflowResult OR = computeOverflowForUnsignedMul( + FI.InnerLimit, FI.OuterLimit, DL, AC, + FI.OuterLoop->getLoopPreheader()->getTerminator(), DT); + if (OR != OverflowResult::MayOverflow) + return OR; + + for (Value *V : FI.LinearIVUses) { + for (Value *U : V->users()) { + if (auto *GEP = dyn_cast(U)) { + // The IV is used as the operand of a GEP, and the IV is at least as + // wide as the address space of the GEP. In this case, the GEP would + // wrap around the address space before the IV increment wraps, which + // would be UB. + if (GEP->isInBounds() && + V->getType()->getIntegerBitWidth() >= + DL.getPointerTypeSizeInBits(GEP->getType())) { + LLVM_DEBUG( + dbgs() << "use of linear IV would be UB if overflow occurred: "; + GEP->dump()); + return OverflowResult::NeverOverflows; + } + } + } + } + + return OverflowResult::MayOverflow; +} + +static bool CanFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT, + LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, const TargetTransformInfo *TTI) { + SmallPtrSet IterationInstructions; + if (!findLoopComponents(FI.InnerLoop, IterationInstructions, FI.InnerInductionPHI, + FI.InnerLimit, FI.InnerIncrement, FI.InnerBranch, SE)) + return false; + if (!findLoopComponents(FI.OuterLoop, IterationInstructions, FI.OuterInductionPHI, + FI.OuterLimit, FI.OuterIncrement, FI.OuterBranch, SE)) + return false; + + // Both of the loop limit values must be invariant in the outer loop + // (non-instructions are all inherently invariant). + if (!FI.OuterLoop->isLoopInvariant(FI.InnerLimit)) { + LLVM_DEBUG(dbgs() << "inner loop limit not invariant\n"); + return false; + } + if (!FI.OuterLoop->isLoopInvariant(FI.OuterLimit)) { + LLVM_DEBUG(dbgs() << "outer loop limit not invariant\n"); + return false; + } + + if (!checkPHIs(FI, TTI)) + return false; + + // FIXME: it should be possible to handle different types correctly. + if (FI.InnerInductionPHI->getType() != FI.OuterInductionPHI->getType()) + return false; + + if (!checkOuterLoopInsts(FI, IterationInstructions, TTI)) + return false; + + // Find the values in the loop that can be replaced with the linearized + // induction variable, and check that there are no other uses of the inner + // or outer induction variable. If there were, we could still do this + // transformation, but we'd have to insert a div/mod to calculate the + // original IVs, so it wouldn't be profitable. + if (!checkIVUsers(FI)) + return false; + + LLVM_DEBUG(dbgs() << "CanFlattenLoopPair: OK\n"); + return true; +} + +static bool DoFlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT, + LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, + const TargetTransformInfo *TTI) { + Function *F = FI.OuterLoop->getHeader()->getParent(); + LLVM_DEBUG(dbgs() << "Checks all passed, doing the transformation\n"); + { + using namespace ore; + OptimizationRemark Remark(DEBUG_TYPE, "Flattened", FI.InnerLoop->getStartLoc(), + FI.InnerLoop->getHeader()); + OptimizationRemarkEmitter ORE(F); + Remark << "Flattened into outer loop"; + ORE.emit(Remark); + } + + Value *NewTripCount = + BinaryOperator::CreateMul(FI.InnerLimit, FI.OuterLimit, "flatten.tripcount", + FI.OuterLoop->getLoopPreheader()->getTerminator()); + LLVM_DEBUG(dbgs() << "Created new trip count in preheader: "; + NewTripCount->dump()); + + // Fix up PHI nodes that take values from the inner loop back-edge, which + // we are about to remove. + FI.InnerInductionPHI->removeIncomingValue(FI.InnerLoop->getLoopLatch()); + + // The old Phi will be optimised away later, but for now we can't leave + // leave it in an invalid state, so are updating them too. + for (PHINode *PHI : FI.InnerPHIsToTransform) + PHI->removeIncomingValue(FI.InnerLoop->getLoopLatch()); + + // Modify the trip count of the outer loop to be the product of the two + // trip counts. + cast(FI.OuterBranch->getCondition())->setOperand(1, NewTripCount); + + // Replace the inner loop backedge with an unconditional branch to the exit. + BasicBlock *InnerExitBlock = FI.InnerLoop->getExitBlock(); + BasicBlock *InnerExitingBlock = FI.InnerLoop->getExitingBlock(); + InnerExitingBlock->getTerminator()->eraseFromParent(); + BranchInst::Create(InnerExitBlock, InnerExitingBlock); + DT->deleteEdge(InnerExitingBlock, FI.InnerLoop->getHeader()); + + // Replace all uses of the polynomial calculated from the two induction + // variables with the one new one. + IRBuilder<> Builder(FI.OuterInductionPHI->getParent()->getTerminator()); + for (Value *V : FI.LinearIVUses) { + Value *OuterValue = FI.OuterInductionPHI; + if (FI.Widened) + OuterValue = Builder.CreateTrunc(FI.OuterInductionPHI, V->getType(), + "flatten.trunciv"); + + LLVM_DEBUG(dbgs() << "Replacing: "; V->dump(); + dbgs() << "with: "; OuterValue->dump()); + V->replaceAllUsesWith(OuterValue); + } + + // Tell LoopInfo, SCEV and the pass manager that the inner loop has been + // deleted, and any information that have about the outer loop invalidated. + SE->forgetLoop(FI.OuterLoop); + SE->forgetLoop(FI.InnerLoop); + LI->erase(FI.InnerLoop); + return true; +} + +static bool CanWidenIV(struct FlattenInfo &FI, DominatorTree *DT, + LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, const TargetTransformInfo *TTI) { + if (!WidenIV) { + LLVM_DEBUG(dbgs() << "Widening the IVs is disabled\n"); + return false; + } + + LLVM_DEBUG(dbgs() << "Try widening the IVs\n"); + Module *M = FI.InnerLoop->getHeader()->getParent()->getParent(); + auto &DL = M->getDataLayout(); + auto *InnerType = FI.InnerInductionPHI->getType(); + auto *OuterType = FI.OuterInductionPHI->getType(); + unsigned MaxLegalSize = DL.getLargestLegalIntTypeSizeInBits(); + auto *MaxLegalType = DL.getLargestLegalIntType(M->getContext()); + + // If both induction types are less than the maximum legal integer width, + // promote both to the widest type available so we know calculating + // (OuterLimit * InnerLimit) as the new trip count is safe. + if (InnerType != OuterType || + InnerType->getScalarSizeInBits() >= MaxLegalSize || + MaxLegalType->getScalarSizeInBits() < InnerType->getScalarSizeInBits() * 2) { + LLVM_DEBUG(dbgs() << "Can't widen the IV\n"); + return false; + } + + SCEVExpander Rewriter(*SE, DL, "loopflatten"); + SmallVector WideIVs; + SmallVector DeadInsts; + WideIVs.push_back( {FI.InnerInductionPHI, MaxLegalType, false }); + WideIVs.push_back( {FI.OuterInductionPHI, MaxLegalType, false }); + unsigned ElimExt; + unsigned Widened; + + for (unsigned i = 0; i < WideIVs.size(); i++) { + PHINode *WidePhi = createWideIV(WideIVs[i], LI, SE, Rewriter, DT, DeadInsts, + ElimExt, Widened, true /* HasGuards */, + true /* UsePostIncrementRanges */); + if (!WidePhi) + return false; + LLVM_DEBUG(dbgs() << "Created wide phi: "; WidePhi->dump()); + LLVM_DEBUG(dbgs() << "Deleting old phi: "; WideIVs[i].NarrowIV->dump()); + RecursivelyDeleteDeadPHINode(WideIVs[i].NarrowIV); + } + // After widening, rediscover all the loop components. + assert(Widened && "Widenend IV expected"); + FI.Widened = true; + return CanFlattenLoopPair(FI, DT, LI, SE, AC, TTI); +} + +static bool FlattenLoopPair(struct FlattenInfo &FI, DominatorTree *DT, + LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, + const TargetTransformInfo *TTI) { + LLVM_DEBUG( + dbgs() << "Loop flattening running on outer loop " + << FI.OuterLoop->getHeader()->getName() << " and inner loop " + << FI.InnerLoop->getHeader()->getName() << " in " + << FI.OuterLoop->getHeader()->getParent()->getName() << "\n"); + + if (!CanFlattenLoopPair(FI, DT, LI, SE, AC, TTI)) + return false; + + // Check if we can widen the induction variables to avoid overflow checks. + if (CanWidenIV(FI, DT, LI, SE, AC, TTI)) + return DoFlattenLoopPair(FI, DT, LI, SE, AC, TTI); + + // Check if the new iteration variable might overflow. In this case, we + // need to version the loop, and select the original version at runtime if + // the iteration space is too large. + // TODO: We currently don't version the loop. + OverflowResult OR = checkOverflow(FI, DT, AC); + if (OR == OverflowResult::AlwaysOverflowsHigh || + OR == OverflowResult::AlwaysOverflowsLow) { + LLVM_DEBUG(dbgs() << "Multiply would always overflow, so not profitable\n"); + return false; + } else if (OR == OverflowResult::MayOverflow) { + LLVM_DEBUG(dbgs() << "Multiply might overflow, not flattening\n"); + return false; + } + + LLVM_DEBUG(dbgs() << "Multiply cannot overflow, modifying loop in-place\n"); + return DoFlattenLoopPair(FI, DT, LI, SE, AC, TTI); +} + +bool Flatten(DominatorTree *DT, LoopInfo *LI, ScalarEvolution *SE, + AssumptionCache *AC, TargetTransformInfo *TTI) { + bool Changed = false; + for (auto *InnerLoop : LI->getLoopsInPreorder()) { + auto *OuterLoop = InnerLoop->getParentLoop(); + if (!OuterLoop) + continue; + struct FlattenInfo FI(OuterLoop, InnerLoop); + Changed |= FlattenLoopPair(FI, DT, LI, SE, AC, TTI); + } + return Changed; +} + +PreservedAnalyses LoopFlattenPass::run(Function &F, + FunctionAnalysisManager &AM) { + auto *DT = &AM.getResult(F); + auto *LI = &AM.getResult(F); + auto *SE = &AM.getResult(F); + auto *AC = &AM.getResult(F); + auto *TTI = &AM.getResult(F); + + if (!Flatten(DT, LI, SE, AC, TTI)) + return PreservedAnalyses::all(); + + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} + +namespace { +class LoopFlattenLegacyPass : public FunctionPass { +public: + static char ID; // Pass ID, replacement for typeid + LoopFlattenLegacyPass() : FunctionPass(ID) { + initializeLoopFlattenLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + // Possibly flatten loop L into its child. + bool runOnFunction(Function &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + getLoopAnalysisUsage(AU); + AU.addRequired(); + AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + } +}; +} // namespace + +char LoopFlattenLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(LoopFlattenLegacyPass, "loop-flatten", "Flattens loops", + false, false) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_END(LoopFlattenLegacyPass, "loop-flatten", "Flattens loops", + false, false) + +FunctionPass *llvm::createLoopFlattenPass() { return new LoopFlattenLegacyPass(); } + +bool LoopFlattenLegacyPass::runOnFunction(Function &F) { + ScalarEvolution *SE = &getAnalysis().getSE(); + LoopInfo *LI = &getAnalysis().getLoopInfo(); + auto *DTWP = getAnalysisIfAvailable(); + DominatorTree *DT = DTWP ? &DTWP->getDomTree() : nullptr; + auto &TTIP = getAnalysis(); + auto *TTI = &TTIP.getTTI(F); + auto *AC = &getAnalysis().getAssumptionCache(F); + return Flatten(DT, LI, SE, AC, TTI); +} diff --git a/llvm/lib/Transforms/Scalar/LoopFuse.cpp b/llvm/lib/Transforms/Scalar/LoopFuse.cpp index 20edc8699d79..b5f8dfa9aafb 100644 --- a/llvm/lib/Transforms/Scalar/LoopFuse.cpp +++ b/llvm/lib/Transforms/Scalar/LoopFuse.cpp @@ -46,6 +46,7 @@ #include "llvm/Transforms/Scalar/LoopFuse.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/DependenceAnalysis.h" #include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/LoopInfo.h" @@ -53,6 +54,7 @@ #include "llvm/Analysis/PostDominators.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" @@ -64,6 +66,7 @@ #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/CodeMoverUtils.h" +#include "llvm/Transforms/Utils/LoopPeel.h" using namespace llvm; @@ -114,6 +117,11 @@ static cl::opt FusionDependenceAnalysis( "Use all available analyses")), cl::Hidden, cl::init(FUSION_DEPENDENCE_ANALYSIS_ALL), cl::ZeroOrMore); +static cl::opt FusionPeelMaxCount( + "loop-fusion-peel-max-count", cl::init(0), cl::Hidden, + cl::desc("Max number of iterations to be peeled from a loop, such that " + "fusion can take place")); + #ifndef NDEBUG static cl::opt VerboseFusionDebugging("loop-fusion-verbose-debug", @@ -157,6 +165,12 @@ struct FusionCandidate { bool Valid; /// Guard branch of the loop, if it exists BranchInst *GuardBranch; + /// Peeling Paramaters of the Loop. + TTI::PeelingPreferences PP; + /// Can you Peel this Loop? + bool AbleToPeel; + /// Has this loop been Peeled + bool Peeled; /// Dominator and PostDominator trees are needed for the /// FusionCandidateCompare function, required by FusionCandidateSet to @@ -168,11 +182,13 @@ struct FusionCandidate { OptimizationRemarkEmitter &ORE; FusionCandidate(Loop *L, const DominatorTree *DT, - const PostDominatorTree *PDT, OptimizationRemarkEmitter &ORE) + const PostDominatorTree *PDT, OptimizationRemarkEmitter &ORE, + TTI::PeelingPreferences PP) : Preheader(L->getLoopPreheader()), Header(L->getHeader()), ExitingBlock(L->getExitingBlock()), ExitBlock(L->getExitBlock()), Latch(L->getLoopLatch()), L(L), Valid(true), - GuardBranch(L->getLoopGuardBranch()), DT(DT), PDT(PDT), ORE(ORE) { + GuardBranch(L->getLoopGuardBranch()), PP(PP), AbleToPeel(canPeel(L)), + Peeled(false), DT(DT), PDT(PDT), ORE(ORE) { // Walk over all blocks in the loop and check for conditions that may // prevent fusion. For each block, walk over all instructions and collect @@ -243,6 +259,17 @@ struct FusionCandidate { return Preheader; } + /// After Peeling the loop is modified quite a bit, hence all of the Blocks + /// need to be updated accordingly. + void updateAfterPeeling() { + Preheader = L->getLoopPreheader(); + Header = L->getHeader(); + ExitingBlock = L->getExitingBlock(); + ExitBlock = L->getExitBlock(); + Latch = L->getLoopLatch(); + verify(); + } + /// Given a guarded loop, get the successor of the guard that is not in the /// loop. /// @@ -254,6 +281,8 @@ struct FusionCandidate { assert(GuardBranch && "Only valid on guarded loops."); assert(GuardBranch->isConditional() && "Expecting guard to be a conditional branch."); + if (Peeled) + return GuardBranch->getSuccessor(1); return (GuardBranch->getSuccessor(0) == Preheader) ? GuardBranch->getSuccessor(1) : GuardBranch->getSuccessor(0); @@ -515,13 +544,17 @@ private: ScalarEvolution &SE; PostDominatorTree &PDT; OptimizationRemarkEmitter &ORE; + AssumptionCache &AC; + + const TargetTransformInfo &TTI; public: LoopFuser(LoopInfo &LI, DominatorTree &DT, DependenceInfo &DI, ScalarEvolution &SE, PostDominatorTree &PDT, - OptimizationRemarkEmitter &ORE, const DataLayout &DL) + OptimizationRemarkEmitter &ORE, const DataLayout &DL, + AssumptionCache &AC, const TargetTransformInfo &TTI) : LDT(LI), DTU(DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy), LI(LI), - DT(DT), DI(DI), SE(SE), PDT(PDT), ORE(ORE) {} + DT(DT), DI(DI), SE(SE), PDT(PDT), ORE(ORE), AC(AC), TTI(TTI) {} /// This is the main entry point for loop fusion. It will traverse the /// specified function and collect candidate loops to fuse, starting at the @@ -606,7 +639,9 @@ private: /// Flow Equivalent sets, sorted by dominance. void collectFusionCandidates(const LoopVector &LV) { for (Loop *L : LV) { - FusionCandidate CurrCand(L, &DT, &PDT, ORE); + TTI::PeelingPreferences PP = + gatherPeelingPreferences(L, SE, TTI, None, None); + FusionCandidate CurrCand(L, &DT, &PDT, ORE, PP); if (!CurrCand.isEligibleForFusion(SE)) continue; @@ -656,33 +691,133 @@ private: /// Determine if two fusion candidates have the same trip count (i.e., they /// execute the same number of iterations). /// - /// Note that for now this method simply returns a boolean value because there - /// are no mechanisms in loop fusion to handle different trip counts. In the - /// future, this behaviour can be extended to adjust one of the loops to make - /// the trip counts equal (e.g., loop peeling). When this is added, this - /// interface may need to change to return more information than just a - /// boolean value. - bool identicalTripCounts(const FusionCandidate &FC0, - const FusionCandidate &FC1) const { + /// This function will return a pair of values. The first is a boolean, + /// stating whether or not the two candidates are known at compile time to + /// have the same TripCount. The second is the difference in the two + /// TripCounts. This information can be used later to determine whether or not + /// peeling can be performed on either one of the candiates. + std::pair> + haveIdenticalTripCounts(const FusionCandidate &FC0, + const FusionCandidate &FC1) const { + const SCEV *TripCount0 = SE.getBackedgeTakenCount(FC0.L); if (isa(TripCount0)) { UncomputableTripCount++; LLVM_DEBUG(dbgs() << "Trip count of first loop could not be computed!"); - return false; + return {false, None}; } const SCEV *TripCount1 = SE.getBackedgeTakenCount(FC1.L); if (isa(TripCount1)) { UncomputableTripCount++; LLVM_DEBUG(dbgs() << "Trip count of second loop could not be computed!"); - return false; + return {false, None}; } + LLVM_DEBUG(dbgs() << "\tTrip counts: " << *TripCount0 << " & " << *TripCount1 << " are " << (TripCount0 == TripCount1 ? "identical" : "different") << "\n"); - return (TripCount0 == TripCount1); + if (TripCount0 == TripCount1) + return {true, 0}; + + LLVM_DEBUG(dbgs() << "The loops do not have the same tripcount, " + "determining the difference between trip counts\n"); + + // Currently only considering loops with a single exit point + // and a non-constant trip count. + const unsigned TC0 = SE.getSmallConstantTripCount(FC0.L); + const unsigned TC1 = SE.getSmallConstantTripCount(FC1.L); + + // If any of the tripcounts are zero that means that loop(s) do not have + // a single exit or a constant tripcount. + if (TC0 == 0 || TC1 == 0) { + LLVM_DEBUG(dbgs() << "Loop(s) do not have a single exit point or do not " + "have a constant number of iterations. Peeling " + "is not benefical\n"); + return {false, None}; + } + + Optional Difference = None; + int Diff = TC0 - TC1; + + if (Diff > 0) + Difference = Diff; + else { + LLVM_DEBUG( + dbgs() << "Difference is less than 0. FC1 (second loop) has more " + "iterations than the first one. Currently not supported\n"); + } + + LLVM_DEBUG(dbgs() << "Difference in loop trip count is: " << Difference + << "\n"); + + return {false, Difference}; + } + + void peelFusionCandidate(FusionCandidate &FC0, const FusionCandidate &FC1, + unsigned PeelCount) { + assert(FC0.AbleToPeel && "Should be able to peel loop"); + + LLVM_DEBUG(dbgs() << "Attempting to peel first " << PeelCount + << " iterations of the first loop. \n"); + + FC0.Peeled = peelLoop(FC0.L, PeelCount, &LI, &SE, &DT, &AC, true); + if (FC0.Peeled) { + LLVM_DEBUG(dbgs() << "Done Peeling\n"); + +#ifndef NDEBUG + auto IdenticalTripCount = haveIdenticalTripCounts(FC0, FC1); + + assert(IdenticalTripCount.first && *IdenticalTripCount.second == 0 && + "Loops should have identical trip counts after peeling"); +#endif + + FC0.PP.PeelCount += PeelCount; + + // Peeling does not update the PDT + PDT.recalculate(*FC0.Preheader->getParent()); + + FC0.updateAfterPeeling(); + + // In this case the iterations of the loop are constant, so the first + // loop will execute completely (will not jump from one of + // the peeled blocks to the second loop). Here we are updating the + // branch conditions of each of the peeled blocks, such that it will + // branch to its successor which is not the preheader of the second loop + // in the case of unguarded loops, or the succesors of the exit block of + // the first loop otherwise. Doing this update will ensure that the entry + // block of the first loop dominates the entry block of the second loop. + BasicBlock *BB = + FC0.GuardBranch ? FC0.ExitBlock->getUniqueSuccessor() : FC1.Preheader; + if (BB) { + SmallVector TreeUpdates; + SmallVector WorkList; + for (BasicBlock *Pred : predecessors(BB)) { + if (Pred != FC0.ExitBlock) { + WorkList.emplace_back(Pred->getTerminator()); + TreeUpdates.emplace_back( + DominatorTree::UpdateType(DominatorTree::Delete, Pred, BB)); + } + } + // Cannot modify the predecessors inside the above loop as it will cause + // the iterators to be nullptrs, causing memory errors. + for (Instruction *CurrentBranch: WorkList) { + BasicBlock *Succ = CurrentBranch->getSuccessor(0); + if (Succ == BB) + Succ = CurrentBranch->getSuccessor(1); + ReplaceInstWithInst(CurrentBranch, BranchInst::Create(Succ)); + } + + DTU.applyUpdates(TreeUpdates); + DTU.flush(); + } + LLVM_DEBUG( + dbgs() << "Sucessfully peeled " << FC0.PP.PeelCount + << " iterations from the first loop.\n" + "Both Loops have the same number of iterations now.\n"); + } } /// Walk each set of control flow equivalent fusion candidates and attempt to @@ -716,7 +851,32 @@ private: FC0->verify(); FC1->verify(); - if (!identicalTripCounts(*FC0, *FC1)) { + // Check if the candidates have identical tripcounts (first value of + // pair), and if not check the difference in the tripcounts between + // the loops (second value of pair). The difference is not equal to + // None iff the loops iterate a constant number of times, and have a + // single exit. + std::pair> IdenticalTripCountRes = + haveIdenticalTripCounts(*FC0, *FC1); + bool SameTripCount = IdenticalTripCountRes.first; + Optional TCDifference = IdenticalTripCountRes.second; + + // Here we are checking that FC0 (the first loop) can be peeled, and + // both loops have different tripcounts. + if (FC0->AbleToPeel && !SameTripCount && TCDifference) { + if (*TCDifference > FusionPeelMaxCount) { + LLVM_DEBUG(dbgs() + << "Difference in loop trip counts: " << *TCDifference + << " is greater than maximum peel count specificed: " + << FusionPeelMaxCount << "\n"); + } else { + // Dependent on peeling being performed on the first loop, and + // assuming all other conditions for fusion return true. + SameTripCount = true; + } + } + + if (!SameTripCount) { LLVM_DEBUG(dbgs() << "Fusion candidates do not have identical trip " "counts. Not fusing.\n"); reportLoopFusion(*FC0, *FC1, @@ -734,7 +894,7 @@ private: // Ensure that FC0 and FC1 have identical guards. // If one (or both) are not guarded, this check is not necessary. if (FC0->GuardBranch && FC1->GuardBranch && - !haveIdenticalGuards(*FC0, *FC1)) { + !haveIdenticalGuards(*FC0, *FC1) && !TCDifference) { LLVM_DEBUG(dbgs() << "Fusion candidates do not have identical " "guards. Not Fusing.\n"); reportLoopFusion(*FC0, *FC1, @@ -803,13 +963,23 @@ private: LLVM_DEBUG(dbgs() << "\tFusion is performed: " << *FC0 << " and " << *FC1 << "\n"); + FusionCandidate FC0Copy = *FC0; + // Peel the loop after determining that fusion is legal. The Loops + // will still be safe to fuse after the peeling is performed. + bool Peel = TCDifference && *TCDifference > 0; + if (Peel) + peelFusionCandidate(FC0Copy, *FC1, *TCDifference); + // Report fusion to the Optimization Remarks. // Note this needs to be done *before* performFusion because // performFusion will change the original loops, making it not // possible to identify them after fusion is complete. - reportLoopFusion(*FC0, *FC1, FuseCounter); + reportLoopFusion((Peel ? FC0Copy : *FC0), *FC1, + FuseCounter); - FusionCandidate FusedCand(performFusion(*FC0, *FC1), &DT, &PDT, ORE); + FusionCandidate FusedCand( + performFusion((Peel ? FC0Copy : *FC0), *FC1), &DT, &PDT, ORE, + FC0Copy.PP); FusedCand.verify(); assert(FusedCand.isEligibleForFusion(SE) && "Fused candidate should be eligible for fusion!"); @@ -1086,16 +1256,17 @@ private: return (FC1.GuardBranch->getSuccessor(1) == FC1.Preheader); } - /// Simplify the condition of the latch branch of \p FC to true, when both of - /// its successors are the same. + /// Modify the latch branch of FC to be unconditional since successors of the + /// branch are the same. void simplifyLatchBranch(const FusionCandidate &FC) const { BranchInst *FCLatchBranch = dyn_cast(FC.Latch->getTerminator()); if (FCLatchBranch) { assert(FCLatchBranch->isConditional() && FCLatchBranch->getSuccessor(0) == FCLatchBranch->getSuccessor(1) && "Expecting the two successors of FCLatchBranch to be the same"); - FCLatchBranch->setCondition( - llvm::ConstantInt::getTrue(FCLatchBranch->getCondition()->getType())); + BranchInst *NewBranch = + BranchInst::Create(FCLatchBranch->getSuccessor(0)); + ReplaceInstWithInst(FCLatchBranch, NewBranch); } } @@ -1155,7 +1326,8 @@ private: if (FC0.GuardBranch) return fuseGuardedLoops(FC0, FC1); - assert(FC1.Preheader == FC0.ExitBlock); + assert(FC1.Preheader == + (FC0.Peeled ? FC0.ExitBlock->getUniqueSuccessor() : FC0.ExitBlock)); assert(FC1.Preheader->size() == 1 && FC1.Preheader->getSingleSuccessor() == FC1.Header); @@ -1197,15 +1369,30 @@ private: // to FC1.Header? I think this is basically what the three sequences are // trying to accomplish; however, doing this directly in the CFG may mean // the DT/PDT becomes invalid - FC0.ExitingBlock->getTerminator()->replaceUsesOfWith(FC1.Preheader, - FC1.Header); - TreeUpdates.emplace_back(DominatorTree::UpdateType( - DominatorTree::Delete, FC0.ExitingBlock, FC1.Preheader)); - TreeUpdates.emplace_back(DominatorTree::UpdateType( - DominatorTree::Insert, FC0.ExitingBlock, FC1.Header)); + if (!FC0.Peeled) { + FC0.ExitingBlock->getTerminator()->replaceUsesOfWith(FC1.Preheader, + FC1.Header); + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Delete, FC0.ExitingBlock, FC1.Preheader)); + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Insert, FC0.ExitingBlock, FC1.Header)); + } else { + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Delete, FC0.ExitBlock, FC1.Preheader)); + + // Remove the ExitBlock of the first Loop (also not needed) + FC0.ExitingBlock->getTerminator()->replaceUsesOfWith(FC0.ExitBlock, + FC1.Header); + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Delete, FC0.ExitingBlock, FC0.ExitBlock)); + FC0.ExitBlock->getTerminator()->eraseFromParent(); + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Insert, FC0.ExitingBlock, FC1.Header)); + new UnreachableInst(FC0.ExitBlock->getContext(), FC0.ExitBlock); + } // The pre-header of L1 is not necessary anymore. - assert(pred_begin(FC1.Preheader) == pred_end(FC1.Preheader)); + assert(pred_empty(FC1.Preheader)); FC1.Preheader->getTerminator()->eraseFromParent(); new UnreachableInst(FC1.Preheader->getContext(), FC1.Preheader); TreeUpdates.emplace_back(DominatorTree::UpdateType( @@ -1246,7 +1433,7 @@ private: FC0.Latch->getTerminator()->replaceUsesOfWith(FC0.Header, FC1.Header); FC1.Latch->getTerminator()->replaceUsesOfWith(FC1.Header, FC0.Header); - // Change the condition of FC0 latch branch to true, as both successors of + // Modify the latch branch of FC0 to be unconditional as both successors of // the branch are the same. simplifyLatchBranch(FC0); @@ -1268,6 +1455,11 @@ private: LI.removeBlock(FC1.Preheader); DTU.deleteBB(FC1.Preheader); + if (FC0.Peeled) { + LI.removeBlock(FC0.ExitBlock); + DTU.deleteBB(FC0.ExitBlock); + } + DTU.flush(); // Is there a way to keep SE up-to-date so we don't need to forget the loops @@ -1282,8 +1474,7 @@ private: mergeLatch(FC0, FC1); // Merge the loops. - SmallVector Blocks(FC1.L->block_begin(), - FC1.L->block_end()); + SmallVector Blocks(FC1.L->blocks()); for (BasicBlock *BB : Blocks) { FC0.L->addBlockEntry(BB); FC1.L->removeBlockFromLoop(BB); @@ -1291,7 +1482,7 @@ private: continue; LI.changeLoopFor(BB, FC0.L); } - while (!FC1.L->empty()) { + while (!FC1.L->isInnermost()) { const auto &ChildLoopIt = FC1.L->begin(); Loop *ChildLoop = *ChildLoopIt; FC1.L->removeChildLoop(ChildLoopIt); @@ -1364,10 +1555,15 @@ private: BasicBlock *FC1GuardBlock = FC1.GuardBranch->getParent(); BasicBlock *FC0NonLoopBlock = FC0.getNonLoopBlock(); BasicBlock *FC1NonLoopBlock = FC1.getNonLoopBlock(); + BasicBlock *FC0ExitBlockSuccessor = FC0.ExitBlock->getUniqueSuccessor(); // Move instructions from the exit block of FC0 to the beginning of the exit - // block of FC1. - moveInstructionsToTheBeginning(*FC0.ExitBlock, *FC1.ExitBlock, DT, PDT, DI); + // block of FC1, in the case that the FC0 loop has not been peeled. In the + // case that FC0 loop is peeled, then move the instructions of the successor + // of the FC0 Exit block to the beginning of the exit block of FC1. + moveInstructionsToTheBeginning( + (FC0.Peeled ? *FC0ExitBlockSuccessor : *FC0.ExitBlock), *FC1.ExitBlock, + DT, PDT, DI); // Move instructions from the guard block of FC1 to the end of the guard // block of FC0. @@ -1387,8 +1583,9 @@ private: // for FC1 (where FC1 guard would have gone if FC1 was not executed). FC1NonLoopBlock->replacePhiUsesWith(FC1GuardBlock, FC0GuardBlock); FC0.GuardBranch->replaceUsesOfWith(FC0NonLoopBlock, FC1NonLoopBlock); - FC0.ExitBlock->getTerminator()->replaceUsesOfWith(FC1GuardBlock, - FC1.Header); + + BasicBlock *BBToUpdate = FC0.Peeled ? FC0ExitBlockSuccessor : FC0.ExitBlock; + BBToUpdate->getTerminator()->replaceUsesOfWith(FC1GuardBlock, FC1.Header); // The guard of FC1 is not necessary anymore. FC1.GuardBranch->eraseFromParent(); @@ -1403,9 +1600,18 @@ private: TreeUpdates.emplace_back(DominatorTree::UpdateType( DominatorTree::Insert, FC0GuardBlock, FC1NonLoopBlock)); - assert(pred_begin(FC1GuardBlock) == pred_end(FC1GuardBlock) && + if (FC0.Peeled) { + // Remove the Block after the ExitBlock of FC0 + TreeUpdates.emplace_back(DominatorTree::UpdateType( + DominatorTree::Delete, FC0ExitBlockSuccessor, FC1GuardBlock)); + FC0ExitBlockSuccessor->getTerminator()->eraseFromParent(); + new UnreachableInst(FC0ExitBlockSuccessor->getContext(), + FC0ExitBlockSuccessor); + } + + assert(pred_empty(FC1GuardBlock) && "Expecting guard block to have no predecessors"); - assert(succ_begin(FC1GuardBlock) == succ_end(FC1GuardBlock) && + assert(succ_empty(FC1GuardBlock) && "Expecting guard block to have no successors"); // Remember the phi nodes originally in the header of FC0 in order to rewire @@ -1459,14 +1665,13 @@ private: // TODO: In the future, we can handle non-empty exit blocks my merging any // instructions from FC0 exit block into FC1 exit block prior to removing // the block. - assert(pred_begin(FC0.ExitBlock) == pred_end(FC0.ExitBlock) && - "Expecting exit block to be empty"); + assert(pred_empty(FC0.ExitBlock) && "Expecting exit block to be empty"); FC0.ExitBlock->getTerminator()->eraseFromParent(); new UnreachableInst(FC0.ExitBlock->getContext(), FC0.ExitBlock); // Remove FC1 Preheader // The pre-header of L1 is not necessary anymore. - assert(pred_begin(FC1.Preheader) == pred_end(FC1.Preheader)); + assert(pred_empty(FC1.Preheader)); FC1.Preheader->getTerminator()->eraseFromParent(); new UnreachableInst(FC1.Preheader->getContext(), FC1.Preheader); TreeUpdates.emplace_back(DominatorTree::UpdateType( @@ -1509,7 +1714,7 @@ private: FC0.Latch->getTerminator()->replaceUsesOfWith(FC0.Header, FC1.Header); FC1.Latch->getTerminator()->replaceUsesOfWith(FC1.Header, FC0.Header); - // Change the condition of FC0 latch branch to true, as both successors of + // Modify the latch branch of FC0 to be unconditional as both successors of // the branch are the same. simplifyLatchBranch(FC0); @@ -1529,10 +1734,8 @@ private: // All done // Apply the updates to the Dominator Tree and cleanup. - assert(succ_begin(FC1GuardBlock) == succ_end(FC1GuardBlock) && - "FC1GuardBlock has successors!!"); - assert(pred_begin(FC1GuardBlock) == pred_end(FC1GuardBlock) && - "FC1GuardBlock has predecessors!!"); + assert(succ_empty(FC1GuardBlock) && "FC1GuardBlock has successors!!"); + assert(pred_empty(FC1GuardBlock) && "FC1GuardBlock has predecessors!!"); // Update DT/PDT DTU.applyUpdates(TreeUpdates); @@ -1540,6 +1743,10 @@ private: LI.removeBlock(FC1GuardBlock); LI.removeBlock(FC1.Preheader); LI.removeBlock(FC0.ExitBlock); + if (FC0.Peeled) { + LI.removeBlock(FC0ExitBlockSuccessor); + DTU.deleteBB(FC0ExitBlockSuccessor); + } DTU.deleteBB(FC1GuardBlock); DTU.deleteBB(FC1.Preheader); DTU.deleteBB(FC0.ExitBlock); @@ -1557,8 +1764,7 @@ private: mergeLatch(FC0, FC1); // Merge the loops. - SmallVector Blocks(FC1.L->block_begin(), - FC1.L->block_end()); + SmallVector Blocks(FC1.L->blocks()); for (BasicBlock *BB : Blocks) { FC0.L->addBlockEntry(BB); FC1.L->removeBlockFromLoop(BB); @@ -1566,7 +1772,7 @@ private: continue; LI.changeLoopFor(BB, FC0.L); } - while (!FC1.L->empty()) { + while (!FC1.L->isInnermost()) { const auto &ChildLoopIt = FC1.L->begin(); Loop *ChildLoop = *ChildLoopIt; FC1.L->removeChildLoop(ChildLoopIt); @@ -1606,6 +1812,8 @@ struct LoopFuseLegacy : public FunctionPass { AU.addRequired(); AU.addRequired(); AU.addRequired(); + AU.addRequired(); + AU.addRequired(); AU.addPreserved(); AU.addPreserved(); @@ -1622,9 +1830,12 @@ struct LoopFuseLegacy : public FunctionPass { auto &SE = getAnalysis().getSE(); auto &PDT = getAnalysis().getPostDomTree(); auto &ORE = getAnalysis().getORE(); - + auto &AC = getAnalysis().getAssumptionCache(F); + const TargetTransformInfo &TTI = + getAnalysis().getTTI(F); const DataLayout &DL = F.getParent()->getDataLayout(); - LoopFuser LF(LI, DT, DI, SE, PDT, ORE, DL); + + LoopFuser LF(LI, DT, DI, SE, PDT, ORE, DL, AC, TTI); return LF.fuseLoops(F); } }; @@ -1637,9 +1848,11 @@ PreservedAnalyses LoopFusePass::run(Function &F, FunctionAnalysisManager &AM) { auto &SE = AM.getResult(F); auto &PDT = AM.getResult(F); auto &ORE = AM.getResult(F); - + auto &AC = AM.getResult(F); + const TargetTransformInfo &TTI = AM.getResult(F); const DataLayout &DL = F.getParent()->getDataLayout(); - LoopFuser LF(LI, DT, DI, SE, PDT, ORE, DL); + + LoopFuser LF(LI, DT, DI, SE, PDT, ORE, DL, AC, TTI); bool Changed = LF.fuseLoops(F); if (!Changed) return PreservedAnalyses::all(); @@ -1662,6 +1875,8 @@ INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(DependenceAnalysisWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_END(LoopFuseLegacy, "loop-fusion", "Loop Fusion", false, false) FunctionPass *llvm::createLoopFusePass() { return new LoopFuseLegacy(); } diff --git a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp index 3cb4df12e9b0..8064c02e2b39 100644 --- a/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp +++ b/llvm/lib/Transforms/Scalar/LoopIdiomRecognize.cpp @@ -47,6 +47,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/CmpInstAnalysis.h" #include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" @@ -79,6 +80,7 @@ #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassManager.h" +#include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" @@ -106,6 +108,32 @@ using namespace llvm; STATISTIC(NumMemSet, "Number of memset's formed from loop stores"); STATISTIC(NumMemCpy, "Number of memcpy's formed from loop load+stores"); +STATISTIC( + NumShiftUntilBitTest, + "Number of uncountable loops recognized as 'shift until bitttest' idiom"); + +bool DisableLIRP::All; +static cl::opt + DisableLIRPAll("disable-" DEBUG_TYPE "-all", + cl::desc("Options to disable Loop Idiom Recognize Pass."), + cl::location(DisableLIRP::All), cl::init(false), + cl::ReallyHidden); + +bool DisableLIRP::Memset; +static cl::opt + DisableLIRPMemset("disable-" DEBUG_TYPE "-memset", + cl::desc("Proceed with loop idiom recognize pass, but do " + "not convert loop(s) to memset."), + cl::location(DisableLIRP::Memset), cl::init(false), + cl::ReallyHidden); + +bool DisableLIRP::Memcpy; +static cl::opt + DisableLIRPMemcpy("disable-" DEBUG_TYPE "-memcpy", + cl::desc("Proceed with loop idiom recognize pass, but do " + "not convert loop(s) to memcpy."), + cl::location(DisableLIRP::Memcpy), cl::init(false), + cl::ReallyHidden); static cl::opt UseLIRCodeSizeHeurs( "use-lir-code-size-heurs", @@ -204,6 +232,8 @@ private: const DebugLoc &DL, bool ZeroCheck, bool IsCntPhiUsedOutsideLoop); + bool recognizeShiftUntilBitTest(); + /// @} }; @@ -217,6 +247,9 @@ public: } bool runOnLoop(Loop *L, LPPassManager &LPM) override { + if (DisableLIRP::All) + return false; + if (skipLoop(L)) return false; @@ -262,6 +295,9 @@ char LoopIdiomRecognizeLegacyPass::ID = 0; PreservedAnalyses LoopIdiomRecognizePass::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &) { + if (DisableLIRP::All) + return PreservedAnalyses::all(); + const auto *DL = &L.getHeader()->getModule()->getDataLayout(); // For the new PM, we also can't use OptimizationRemarkEmitter as an analysis @@ -426,11 +462,6 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) { if (!SI->isUnordered()) return LegalStoreKind::None; - // Don't convert stores of non-integral pointer types to memsets (which stores - // integers). - if (DL->isNonIntegralPointerType(SI->getValueOperand()->getType())) - return LegalStoreKind::None; - // Avoid merging nontemporal stores. if (SI->getMetadata(LLVMContext::MD_nontemporal)) return LegalStoreKind::None; @@ -438,9 +469,17 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) { Value *StoredVal = SI->getValueOperand(); Value *StorePtr = SI->getPointerOperand(); + // Don't convert stores of non-integral pointer types to memsets (which stores + // integers). + if (DL->isNonIntegralPointerType(StoredVal->getType()->getScalarType())) + return LegalStoreKind::None; + // Reject stores that are so large that they overflow an unsigned. - uint64_t SizeInBits = DL->getTypeSizeInBits(StoredVal->getType()); - if ((SizeInBits & 7) || (SizeInBits >> 32) != 0) + // When storing out scalable vectors we bail out for now, since the code + // below currently only works for constant strides. + TypeSize SizeInBits = DL->getTypeSizeInBits(StoredVal->getType()); + if (SizeInBits.isScalable() || (SizeInBits.getFixedSize() & 7) || + (SizeInBits.getFixedSize() >> 32) != 0) return LegalStoreKind::None; // See if the pointer expression is an AddRec like {base,+,1} on the current @@ -469,13 +508,13 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) { // If we're allowed to form a memset, and the stored value would be // acceptable for memset, use it. - if (!UnorderedAtomic && HasMemset && SplatValue && + if (!UnorderedAtomic && HasMemset && SplatValue && !DisableLIRP::Memset && // Verify that the stored value is loop invariant. If not, we can't // promote the memset. CurLoop->isLoopInvariant(SplatValue)) { // It looks like we can use SplatValue. return LegalStoreKind::Memset; - } else if (!UnorderedAtomic && HasMemsetPattern && + } else if (!UnorderedAtomic && HasMemsetPattern && !DisableLIRP::Memset && // Don't create memset_pattern16s with address spaces. StorePtr->getType()->getPointerAddressSpace() == 0 && (PatternValue = getMemSetPatternValue(StoredVal, DL))) { @@ -484,7 +523,7 @@ LoopIdiomRecognize::isLegalStore(StoreInst *SI) { } // Otherwise, see if the store can be turned into a memcpy. - if (HasMemcpy) { + if (HasMemcpy && !DisableLIRP::Memcpy) { // Check to see if the stride matches the size of the store. If so, then we // know that every byte is touched in the loop. APInt Stride = getStoreStride(StoreEv); @@ -539,12 +578,12 @@ void LoopIdiomRecognize::collectStores(BasicBlock *BB) { break; case LegalStoreKind::Memset: { // Find the base pointer. - Value *Ptr = GetUnderlyingObject(SI->getPointerOperand(), *DL); + Value *Ptr = getUnderlyingObject(SI->getPointerOperand()); StoreRefsForMemset[Ptr].push_back(SI); } break; case LegalStoreKind::MemsetPattern: { // Find the base pointer. - Value *Ptr = GetUnderlyingObject(SI->getPointerOperand(), *DL); + Value *Ptr = getUnderlyingObject(SI->getPointerOperand()); StoreRefsForMemsetPattern[Ptr].push_back(SI); } break; case LegalStoreKind::Memcpy: @@ -812,7 +851,7 @@ mayLoopAccessLocation(Value *Ptr, ModRefInfo Access, Loop *L, // Get the location that may be stored across the loop. Since the access is // strided positively through memory, we say that the modified location starts // at the pointer and has infinite size. - LocationSize AccessSize = LocationSize::unknown(); + LocationSize AccessSize = LocationSize::afterPointer(); // If the loop iterates a fixed number of times, we can refine the access size // to be exactly the size of the memset, which is (BECount+1)*StoreSize @@ -864,8 +903,8 @@ static const SCEV *getNumBytes(const SCEV *BECount, Type *IntPtr, // If we're going to need to zero extend the BE count, check if we can add // one to it prior to zero extending without overflow. Provided this is safe, // it allows better simplification of the +1. - if (DL->getTypeSizeInBits(BECount->getType()) < - DL->getTypeSizeInBits(IntPtr) && + if (DL->getTypeSizeInBits(BECount->getType()).getFixedSize() < + DL->getTypeSizeInBits(IntPtr).getFixedSize() && SE->isLoopEntryGuardedByCond( CurLoop, ICmpInst::ICMP_NE, BECount, SE->getNegativeSCEV(SE->getOne(BECount->getType())))) { @@ -908,10 +947,12 @@ bool LoopIdiomRecognize::processLoopStridedStore( BasicBlock *Preheader = CurLoop->getLoopPreheader(); IRBuilder<> Builder(Preheader->getTerminator()); SCEVExpander Expander(*SE, *DL, "loop-idiom"); + SCEVExpanderCleaner ExpCleaner(Expander, *DT); Type *DestInt8PtrTy = Builder.getInt8PtrTy(DestAS); Type *IntIdxTy = DL->getIndexType(DestPtr->getType()); + bool Changed = false; const SCEV *Start = Ev->getStart(); // Handle negative strided loops. if (NegStride) @@ -920,7 +961,7 @@ bool LoopIdiomRecognize::processLoopStridedStore( // TODO: ideally we should still be able to generate memset if SCEV expander // is taught to generate the dependencies at the latest point. if (!isSafeToExpand(Start, *SE)) - return false; + return Changed; // Okay, we have a strided store "p[i]" of a splattable value. We can turn // this into a memset in the loop preheader now if we want. However, this @@ -929,16 +970,22 @@ bool LoopIdiomRecognize::processLoopStridedStore( // base pointer and checking the region. Value *BasePtr = Expander.expandCodeFor(Start, DestInt8PtrTy, Preheader->getTerminator()); + + // From here on out, conservatively report to the pass manager that we've + // changed the IR, even if we later clean up these added instructions. There + // may be structural differences e.g. in the order of use lists not accounted + // for in just a textual dump of the IR. This is written as a variable, even + // though statically all the places this dominates could be replaced with + // 'true', with the hope that anyone trying to be clever / "more precise" with + // the return value will read this comment, and leave them alone. + Changed = true; + if (mayLoopAccessLocation(BasePtr, ModRefInfo::ModRef, CurLoop, BECount, - StoreSize, *AA, Stores)) { - Expander.clear(); - // If we generated new code for the base pointer, clean up. - RecursivelyDeleteTriviallyDeadInstructions(BasePtr, TLI); - return false; - } + StoreSize, *AA, Stores)) + return Changed; if (avoidLIRForMultiBlockLoop(/*IsMemset=*/true, IsLoopMemset)) - return false; + return Changed; // Okay, everything looks good, insert the memset. @@ -948,7 +995,7 @@ bool LoopIdiomRecognize::processLoopStridedStore( // TODO: ideally we should still be able to generate memset if SCEV expander // is taught to generate the dependencies at the latest point. if (!isSafeToExpand(NumBytesS, *SE)) - return false; + return Changed; Value *NumBytes = Expander.expandCodeFor(NumBytesS, IntIdxTy, Preheader->getTerminator()); @@ -1007,32 +1054,10 @@ bool LoopIdiomRecognize::processLoopStridedStore( if (MSSAU && VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); ++NumMemSet; + ExpCleaner.markResultUsed(); return true; } -class ExpandedValuesCleaner { - SCEVExpander &Expander; - TargetLibraryInfo *TLI; - SmallVector ExpandedValues; - bool Commit = false; - -public: - ExpandedValuesCleaner(SCEVExpander &Expander, TargetLibraryInfo *TLI) - : Expander(Expander), TLI(TLI) {} - - void add(Value *V) { ExpandedValues.push_back(V); } - - void commit() { Commit = true; } - - ~ExpandedValuesCleaner() { - if (!Commit) { - Expander.clear(); - for (auto *V : ExpandedValues) - RecursivelyDeleteTriviallyDeadInstructions(V, TLI); - } - } -}; - /// If the stored value is a strided load in the same loop with the same stride /// this may be transformable into a memcpy. This kicks in for stuff like /// for (i) A[i] = B[i]; @@ -1063,8 +1088,9 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, IRBuilder<> Builder(Preheader->getTerminator()); SCEVExpander Expander(*SE, *DL, "loop-idiom"); - ExpandedValuesCleaner EVC(Expander, TLI); + SCEVExpanderCleaner ExpCleaner(Expander, *DT); + bool Changed = false; const SCEV *StrStart = StoreEv->getStart(); unsigned StrAS = SI->getPointerAddressSpace(); Type *IntIdxTy = Builder.getIntNTy(DL->getIndexSizeInBits(StrAS)); @@ -1081,13 +1107,21 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, // checking everything. Value *StoreBasePtr = Expander.expandCodeFor( StrStart, Builder.getInt8PtrTy(StrAS), Preheader->getTerminator()); - EVC.add(StoreBasePtr); + + // From here on out, conservatively report to the pass manager that we've + // changed the IR, even if we later clean up these added instructions. There + // may be structural differences e.g. in the order of use lists not accounted + // for in just a textual dump of the IR. This is written as a variable, even + // though statically all the places this dominates could be replaced with + // 'true', with the hope that anyone trying to be clever / "more precise" with + // the return value will read this comment, and leave them alone. + Changed = true; SmallPtrSet Stores; Stores.insert(SI); if (mayLoopAccessLocation(StoreBasePtr, ModRefInfo::ModRef, CurLoop, BECount, StoreSize, *AA, Stores)) - return false; + return Changed; const SCEV *LdStart = LoadEv->getStart(); unsigned LdAS = LI->getPointerAddressSpace(); @@ -1100,14 +1134,13 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, // mutated by the loop. Value *LoadBasePtr = Expander.expandCodeFor( LdStart, Builder.getInt8PtrTy(LdAS), Preheader->getTerminator()); - EVC.add(LoadBasePtr); if (mayLoopAccessLocation(LoadBasePtr, ModRefInfo::Mod, CurLoop, BECount, StoreSize, *AA, Stores)) - return false; + return Changed; if (avoidLIRForMultiBlockLoop()) - return false; + return Changed; // Okay, everything is safe, we can transform this! @@ -1116,7 +1149,6 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, Value *NumBytes = Expander.expandCodeFor(NumBytesS, IntIdxTy, Preheader->getTerminator()); - EVC.add(NumBytes); CallInst *NewCall = nullptr; // Check whether to generate an unordered atomic memcpy: @@ -1131,14 +1163,14 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, const Align StoreAlign = SI->getAlign(); const Align LoadAlign = LI->getAlign(); if (StoreAlign < StoreSize || LoadAlign < StoreSize) - return false; + return Changed; // If the element.atomic memcpy is not lowered into explicit // loads/stores later, then it will be lowered into an element-size // specific lib call. If the lib call doesn't exist for our store size, then // we shouldn't generate the memcpy. if (StoreSize > TTI->getAtomicMemIntrinsicMaxElementSize()) - return false; + return Changed; // Create the call. // Note that unordered atomic loads/stores are *required* by the spec to @@ -1176,7 +1208,7 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, if (MSSAU && VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); ++NumMemCpy; - EVC.commit(); + ExpCleaner.markResultUsed(); return true; } @@ -1186,7 +1218,7 @@ bool LoopIdiomRecognize::processLoopStoreOfLoopLoad(StoreInst *SI, bool LoopIdiomRecognize::avoidLIRForMultiBlockLoop(bool IsMemset, bool IsLoopMemset) { if (ApplyCodeSizeHeuristics && CurLoop->getNumBlocks() > 1) { - if (!CurLoop->getParentLoop() && (!IsMemset || !IsLoopMemset)) { + if (CurLoop->isOutermost() && (!IsMemset || !IsLoopMemset)) { LLVM_DEBUG(dbgs() << " " << CurLoop->getHeader()->getParent()->getName() << " : LIR " << (IsMemset ? "Memset" : "Memcpy") << " avoided: multi-block top-level loop\n"); @@ -1203,7 +1235,8 @@ bool LoopIdiomRecognize::runOnNoncountableLoop() { << "] Noncountable Loop %" << CurLoop->getHeader()->getName() << "\n"); - return recognizePopcount() || recognizeAndInsertFFS(); + return recognizePopcount() || recognizeAndInsertFFS() || + recognizeShiftUntilBitTest(); } /// Check if the given conditional branch is based on the comparison between @@ -1450,6 +1483,7 @@ static bool detectShiftUntilZeroIdiom(Loop *CurLoop, const DataLayout &DL, return false; // step 4: Find the instruction which count the CTLZ: cnt.next = cnt + 1 + // or cnt.next = cnt + -1. // TODO: We can skip the step. If loop trip count is known (CTLZ), // then all uses of "cnt.next" could be optimized to the trip count // plus "cnt0". Currently it is not optimized. @@ -1463,7 +1497,7 @@ static bool detectShiftUntilZeroIdiom(Loop *CurLoop, const DataLayout &DL, continue; ConstantInt *Inc = dyn_cast(Inst->getOperand(1)); - if (!Inc || !Inc->isOne()) + if (!Inc || (!Inc->isOne() && !Inc->isMinusOne())) continue; PHINode *Phi = getRecurrenceVar(Inst->getOperand(0), Inst, LoopEntry); @@ -1692,11 +1726,13 @@ void LoopIdiomRecognize::transformLoopToCountable( // Step 1: Insert the CTLZ/CTTZ instruction at the end of the preheader block IRBuilder<> Builder(PreheaderBr); Builder.SetCurrentDebugLocation(DL); - Value *FFS, *Count, *CountPrev, *NewCount, *InitXNext; // Count = BitWidth - CTLZ(InitX); + // NewCount = Count; // If there are uses of CntPhi create: - // CountPrev = BitWidth - CTLZ(InitX >> 1); + // NewCount = BitWidth - CTLZ(InitX >> 1); + // Count = NewCount + 1; + Value *InitXNext; if (IsCntPhiUsedOutsideLoop) { if (DefX->getOpcode() == Instruction::AShr) InitXNext = @@ -1711,27 +1747,31 @@ void LoopIdiomRecognize::transformLoopToCountable( llvm_unreachable("Unexpected opcode!"); } else InitXNext = InitX; - FFS = createFFSIntrinsic(Builder, InitXNext, DL, ZeroCheck, IntrinID); - Count = Builder.CreateSub( - ConstantInt::get(FFS->getType(), - FFS->getType()->getIntegerBitWidth()), + Value *FFS = createFFSIntrinsic(Builder, InitXNext, DL, ZeroCheck, IntrinID); + Value *Count = Builder.CreateSub( + ConstantInt::get(FFS->getType(), FFS->getType()->getIntegerBitWidth()), FFS); + Value *NewCount = Count; if (IsCntPhiUsedOutsideLoop) { - CountPrev = Count; - Count = Builder.CreateAdd( - CountPrev, - ConstantInt::get(CountPrev->getType(), 1)); + NewCount = Count; + Count = Builder.CreateAdd(Count, ConstantInt::get(Count->getType(), 1)); } - NewCount = Builder.CreateZExtOrTrunc( - IsCntPhiUsedOutsideLoop ? CountPrev : Count, - cast(CntInst->getType())); + NewCount = Builder.CreateZExtOrTrunc(NewCount, + cast(CntInst->getType())); - // If the counter's initial value is not zero, insert Add Inst. Value *CntInitVal = CntPhi->getIncomingValueForBlock(Preheader); - ConstantInt *InitConst = dyn_cast(CntInitVal); - if (!InitConst || !InitConst->isZero()) - NewCount = Builder.CreateAdd(NewCount, CntInitVal); + if (cast(CntInst->getOperand(1))->isOne()) { + // If the counter was being incremented in the loop, add NewCount to the + // counter's initial value, but only if the initial value is not zero. + ConstantInt *InitConst = dyn_cast(CntInitVal); + if (!InitConst || !InitConst->isZero()) + NewCount = Builder.CreateAdd(NewCount, CntInitVal); + } else { + // If the count was being decremented in the loop, subtract NewCount from + // the counter's initial value. + NewCount = Builder.CreateSub(CntInitVal, NewCount); + } // Step 2: Insert new IV and loop condition: // loop: @@ -1879,3 +1919,343 @@ void LoopIdiomRecognize::transformLoopToPopcount(BasicBlock *PreCondBB, // loop. The loop would otherwise not be deleted even if it becomes empty. SE->forgetLoop(CurLoop); } + +/// Match loop-invariant value. +template struct match_LoopInvariant { + SubPattern_t SubPattern; + const Loop *L; + + match_LoopInvariant(const SubPattern_t &SP, const Loop *L) + : SubPattern(SP), L(L) {} + + template bool match(ITy *V) { + return L->isLoopInvariant(V) && SubPattern.match(V); + } +}; + +/// Matches if the value is loop-invariant. +template +inline match_LoopInvariant m_LoopInvariant(const Ty &M, const Loop *L) { + return match_LoopInvariant(M, L); +} + +/// Return true if the idiom is detected in the loop. +/// +/// The core idiom we are trying to detect is: +/// \code +/// entry: +/// <...> +/// %bitmask = shl i32 1, %bitpos +/// br label %loop +/// +/// loop: +/// %x.curr = phi i32 [ %x, %entry ], [ %x.next, %loop ] +/// %x.curr.bitmasked = and i32 %x.curr, %bitmask +/// %x.curr.isbitunset = icmp eq i32 %x.curr.bitmasked, 0 +/// %x.next = shl i32 %x.curr, 1 +/// <...> +/// br i1 %x.curr.isbitunset, label %loop, label %end +/// +/// end: +/// %x.curr.res = phi i32 [ %x.curr, %loop ] <...> +/// %x.next.res = phi i32 [ %x.next, %loop ] <...> +/// <...> +/// \endcode +static bool detectShiftUntilBitTestIdiom(Loop *CurLoop, Value *&BaseX, + Value *&BitMask, Value *&BitPos, + Value *&CurrX, Instruction *&NextX) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE + " Performing shift-until-bittest idiom detection.\n"); + + // Give up if the loop has multiple blocks or multiple backedges. + if (CurLoop->getNumBlocks() != 1 || CurLoop->getNumBackEdges() != 1) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad block/backedge count.\n"); + return false; + } + + BasicBlock *LoopHeaderBB = CurLoop->getHeader(); + BasicBlock *LoopPreheaderBB = CurLoop->getLoopPreheader(); + assert(LoopPreheaderBB && "There is always a loop preheader."); + + using namespace PatternMatch; + + // Step 1: Check if the loop backedge is in desirable form. + + ICmpInst::Predicate Pred; + Value *CmpLHS, *CmpRHS; + BasicBlock *TrueBB, *FalseBB; + if (!match(LoopHeaderBB->getTerminator(), + m_Br(m_ICmp(Pred, m_Value(CmpLHS), m_Value(CmpRHS)), + m_BasicBlock(TrueBB), m_BasicBlock(FalseBB)))) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad backedge structure.\n"); + return false; + } + + // Step 2: Check if the backedge's condition is in desirable form. + + auto MatchVariableBitMask = [&]() { + return ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero()) && + match(CmpLHS, + m_c_And(m_Value(CurrX), + m_CombineAnd( + m_Value(BitMask), + m_LoopInvariant(m_Shl(m_One(), m_Value(BitPos)), + CurLoop)))); + }; + auto MatchConstantBitMask = [&]() { + return ICmpInst::isEquality(Pred) && match(CmpRHS, m_Zero()) && + match(CmpLHS, m_And(m_Value(CurrX), + m_CombineAnd(m_Value(BitMask), m_Power2()))) && + (BitPos = ConstantExpr::getExactLogBase2(cast(BitMask))); + }; + auto MatchDecomposableConstantBitMask = [&]() { + APInt Mask; + return llvm::decomposeBitTestICmp(CmpLHS, CmpRHS, Pred, CurrX, Mask) && + ICmpInst::isEquality(Pred) && Mask.isPowerOf2() && + (BitMask = ConstantInt::get(CurrX->getType(), Mask)) && + (BitPos = ConstantInt::get(CurrX->getType(), Mask.logBase2())); + }; + + if (!MatchVariableBitMask() && !MatchConstantBitMask() && + !MatchDecomposableConstantBitMask()) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad backedge comparison.\n"); + return false; + } + + // Step 3: Check if the recurrence is in desirable form. + auto *CurrXPN = dyn_cast(CurrX); + if (!CurrXPN || CurrXPN->getParent() != LoopHeaderBB) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Not an expected PHI node.\n"); + return false; + } + + BaseX = CurrXPN->getIncomingValueForBlock(LoopPreheaderBB); + NextX = + dyn_cast(CurrXPN->getIncomingValueForBlock(LoopHeaderBB)); + + if (!NextX || !match(NextX, m_Shl(m_Specific(CurrX), m_One()))) { + // FIXME: support right-shift? + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad recurrence.\n"); + return false; + } + + // Step 4: Check if the backedge's destinations are in desirable form. + + assert(ICmpInst::isEquality(Pred) && + "Should only get equality predicates here."); + + // cmp-br is commutative, so canonicalize to a single variant. + if (Pred != ICmpInst::Predicate::ICMP_EQ) { + Pred = ICmpInst::getInversePredicate(Pred); + std::swap(TrueBB, FalseBB); + } + + // We expect to exit loop when comparison yields false, + // so when it yields true we should branch back to loop header. + if (TrueBB != LoopHeaderBB) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Bad backedge flow.\n"); + return false; + } + + // Okay, idiom checks out. + return true; +} + +/// Look for the following loop: +/// \code +/// entry: +/// <...> +/// %bitmask = shl i32 1, %bitpos +/// br label %loop +/// +/// loop: +/// %x.curr = phi i32 [ %x, %entry ], [ %x.next, %loop ] +/// %x.curr.bitmasked = and i32 %x.curr, %bitmask +/// %x.curr.isbitunset = icmp eq i32 %x.curr.bitmasked, 0 +/// %x.next = shl i32 %x.curr, 1 +/// <...> +/// br i1 %x.curr.isbitunset, label %loop, label %end +/// +/// end: +/// %x.curr.res = phi i32 [ %x.curr, %loop ] <...> +/// %x.next.res = phi i32 [ %x.next, %loop ] <...> +/// <...> +/// \endcode +/// +/// And transform it into: +/// \code +/// entry: +/// %bitmask = shl i32 1, %bitpos +/// %lowbitmask = add i32 %bitmask, -1 +/// %mask = or i32 %lowbitmask, %bitmask +/// %x.masked = and i32 %x, %mask +/// %x.masked.numleadingzeros = call i32 @llvm.ctlz.i32(i32 %x.masked, +/// i1 true) +/// %x.masked.numactivebits = sub i32 32, %x.masked.numleadingzeros +/// %x.masked.leadingonepos = add i32 %x.masked.numactivebits, -1 +/// %backedgetakencount = sub i32 %bitpos, %x.masked.leadingonepos +/// %tripcount = add i32 %backedgetakencount, 1 +/// %x.curr = shl i32 %x, %backedgetakencount +/// %x.next = shl i32 %x, %tripcount +/// br label %loop +/// +/// loop: +/// %loop.iv = phi i32 [ 0, %entry ], [ %loop.iv.next, %loop ] +/// %loop.iv.next = add nuw i32 %loop.iv, 1 +/// %loop.ivcheck = icmp eq i32 %loop.iv.next, %tripcount +/// <...> +/// br i1 %loop.ivcheck, label %end, label %loop +/// +/// end: +/// %x.curr.res = phi i32 [ %x.curr, %loop ] <...> +/// %x.next.res = phi i32 [ %x.next, %loop ] <...> +/// <...> +/// \endcode +bool LoopIdiomRecognize::recognizeShiftUntilBitTest() { + bool MadeChange = false; + + Value *X, *BitMask, *BitPos, *XCurr; + Instruction *XNext; + if (!detectShiftUntilBitTestIdiom(CurLoop, X, BitMask, BitPos, XCurr, + XNext)) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE + " shift-until-bittest idiom detection failed.\n"); + return MadeChange; + } + LLVM_DEBUG(dbgs() << DEBUG_TYPE " shift-until-bittest idiom detected!\n"); + + // Ok, it is the idiom we were looking for, we *could* transform this loop, + // but is it profitable to transform? + + BasicBlock *LoopHeaderBB = CurLoop->getHeader(); + BasicBlock *LoopPreheaderBB = CurLoop->getLoopPreheader(); + assert(LoopPreheaderBB && "There is always a loop preheader."); + + BasicBlock *SuccessorBB = CurLoop->getExitBlock(); + assert(LoopPreheaderBB && "There is only a single successor."); + + IRBuilder<> Builder(LoopPreheaderBB->getTerminator()); + Builder.SetCurrentDebugLocation(cast(XCurr)->getDebugLoc()); + + Intrinsic::ID IntrID = Intrinsic::ctlz; + Type *Ty = X->getType(); + + TargetTransformInfo::TargetCostKind CostKind = + TargetTransformInfo::TCK_SizeAndLatency; + + // The rewrite is considered to be unprofitable iff and only iff the + // intrinsic/shift we'll use are not cheap. Note that we are okay with *just* + // making the loop countable, even if nothing else changes. + IntrinsicCostAttributes Attrs( + IntrID, Ty, {UndefValue::get(Ty), /*is_zero_undef=*/Builder.getTrue()}); + int Cost = TTI->getIntrinsicInstrCost(Attrs, CostKind); + if (Cost > TargetTransformInfo::TCC_Basic) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE + " Intrinsic is too costly, not beneficial\n"); + return MadeChange; + } + if (TTI->getArithmeticInstrCost(Instruction::Shl, Ty, CostKind) > + TargetTransformInfo::TCC_Basic) { + LLVM_DEBUG(dbgs() << DEBUG_TYPE " Shift is too costly, not beneficial\n"); + return MadeChange; + } + + // Ok, transform appears worthwhile. + MadeChange = true; + + // Step 1: Compute the loop trip count. + + Value *LowBitMask = Builder.CreateAdd(BitMask, Constant::getAllOnesValue(Ty), + BitPos->getName() + ".lowbitmask"); + Value *Mask = + Builder.CreateOr(LowBitMask, BitMask, BitPos->getName() + ".mask"); + Value *XMasked = Builder.CreateAnd(X, Mask, X->getName() + ".masked"); + CallInst *XMaskedNumLeadingZeros = Builder.CreateIntrinsic( + IntrID, Ty, {XMasked, /*is_zero_undef=*/Builder.getTrue()}, + /*FMFSource=*/nullptr, XMasked->getName() + ".numleadingzeros"); + Value *XMaskedNumActiveBits = Builder.CreateSub( + ConstantInt::get(Ty, Ty->getScalarSizeInBits()), XMaskedNumLeadingZeros, + XMasked->getName() + ".numactivebits"); + Value *XMaskedLeadingOnePos = + Builder.CreateAdd(XMaskedNumActiveBits, Constant::getAllOnesValue(Ty), + XMasked->getName() + ".leadingonepos"); + + Value *LoopBackedgeTakenCount = Builder.CreateSub( + BitPos, XMaskedLeadingOnePos, CurLoop->getName() + ".backedgetakencount"); + // We know loop's backedge-taken count, but what's loop's trip count? + // Note that while NUW is always safe, while NSW is only for bitwidths != 2. + Value *LoopTripCount = + Builder.CreateNUWAdd(LoopBackedgeTakenCount, ConstantInt::get(Ty, 1), + CurLoop->getName() + ".tripcount"); + + // Step 2: Compute the recurrence's final value without a loop. + + // NewX is always safe to compute, because `LoopBackedgeTakenCount` + // will always be smaller than `bitwidth(X)`, i.e. we never get poison. + Value *NewX = Builder.CreateShl(X, LoopBackedgeTakenCount); + NewX->takeName(XCurr); + if (auto *I = dyn_cast(NewX)) + I->copyIRFlags(XNext, /*IncludeWrapFlags=*/true); + + Value *NewXNext; + // Rewriting XNext is more complicated, however, because `X << LoopTripCount` + // will be poison iff `LoopTripCount == bitwidth(X)` (which will happen + // iff `BitPos` is `bitwidth(x) - 1` and `X` is `1`). So unless we know + // that isn't the case, we'll need to emit an alternative, safe IR. + if (XNext->hasNoSignedWrap() || XNext->hasNoUnsignedWrap() || + PatternMatch::match( + BitPos, PatternMatch::m_SpecificInt_ICMP( + ICmpInst::ICMP_NE, APInt(Ty->getScalarSizeInBits(), + Ty->getScalarSizeInBits() - 1)))) + NewXNext = Builder.CreateShl(X, LoopTripCount); + else { + // Otherwise, just additionally shift by one. It's the smallest solution, + // alternatively, we could check that NewX is INT_MIN (or BitPos is ) + // and select 0 instead. + NewXNext = Builder.CreateShl(NewX, ConstantInt::get(Ty, 1)); + } + + NewXNext->takeName(XNext); + if (auto *I = dyn_cast(NewXNext)) + I->copyIRFlags(XNext, /*IncludeWrapFlags=*/true); + + // Step 3: Adjust the successor basic block to recieve the computed + // recurrence's final value instead of the recurrence itself. + + XCurr->replaceUsesOutsideBlock(NewX, LoopHeaderBB); + XNext->replaceUsesOutsideBlock(NewXNext, LoopHeaderBB); + + // Step 4: Rewrite the loop into a countable form, with canonical IV. + + // The new canonical induction variable. + Builder.SetInsertPoint(&LoopHeaderBB->front()); + auto *IV = Builder.CreatePHI(Ty, 2, CurLoop->getName() + ".iv"); + + // The induction itself. + // Note that while NUW is always safe, while NSW is only for bitwidths != 2. + Builder.SetInsertPoint(LoopHeaderBB->getTerminator()); + auto *IVNext = Builder.CreateNUWAdd(IV, ConstantInt::get(Ty, 1), + IV->getName() + ".next"); + + // The loop trip count check. + auto *IVCheck = Builder.CreateICmpEQ(IVNext, LoopTripCount, + CurLoop->getName() + ".ivcheck"); + Builder.CreateCondBr(IVCheck, SuccessorBB, LoopHeaderBB); + LoopHeaderBB->getTerminator()->eraseFromParent(); + + // Populate the IV PHI. + IV->addIncoming(ConstantInt::get(Ty, 0), LoopPreheaderBB); + IV->addIncoming(IVNext, LoopHeaderBB); + + // Step 5: Forget the "non-computable" trip-count SCEV associated with the + // loop. The loop would otherwise not be deleted even if it becomes empty. + + SE->forgetLoop(CurLoop); + + // Other passes will take care of actually deleting the loop if possible. + + LLVM_DEBUG(dbgs() << DEBUG_TYPE " shift-until-bittest idiom optimized!\n"); + + ++NumShiftUntilBitTest; + return MadeChange; +} diff --git a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp index 7787c0bccd4c..d9dbc0deb42a 100644 --- a/llvm/lib/Transforms/Scalar/LoopInterchange.cpp +++ b/llvm/lib/Transforms/Scalar/LoopInterchange.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/LoopInterchange.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -27,6 +28,7 @@ #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" @@ -427,9 +429,7 @@ private: const LoopInterchangeLegality &LIL; }; -// Main LoopInterchange Pass. -struct LoopInterchange : public LoopPass { - static char ID; +struct LoopInterchange { ScalarEvolution *SE = nullptr; LoopInfo *LI = nullptr; DependenceInfo *DI = nullptr; @@ -438,34 +438,21 @@ struct LoopInterchange : public LoopPass { /// Interface to emit optimization remarks. OptimizationRemarkEmitter *ORE; - LoopInterchange() : LoopPass(ID) { - initializeLoopInterchangePass(*PassRegistry::getPassRegistry()); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); + LoopInterchange(ScalarEvolution *SE, LoopInfo *LI, DependenceInfo *DI, + DominatorTree *DT, OptimizationRemarkEmitter *ORE) + : SE(SE), LI(LI), DI(DI), DT(DT), ORE(ORE) {} - getLoopAnalysisUsage(AU); - } - - bool runOnLoop(Loop *L, LPPassManager &LPM) override { - if (skipLoop(L) || L->getParentLoop()) + bool run(Loop *L) { + if (L->getParentLoop()) return false; - SE = &getAnalysis().getSE(); - LI = &getAnalysis().getLoopInfo(); - DI = &getAnalysis().getDI(); - DT = &getAnalysis().getDomTree(); - ORE = &getAnalysis().getORE(); - return processLoopList(populateWorklist(*L)); } bool isComputableLoopNest(LoopVector LoopList) { for (Loop *L : LoopList) { const SCEV *ExitCountOuter = SE->getBackedgeTakenCount(L); - if (ExitCountOuter == SE->getCouldNotCompute()) { + if (isa(ExitCountOuter)) { LLVM_DEBUG(dbgs() << "Couldn't compute backedge count\n"); return false; } @@ -624,6 +611,13 @@ bool LoopInterchangeLegality::tightlyNested(Loop *OuterLoop, Loop *InnerLoop) { containsUnsafeInstructions(OuterLoopLatch)) return false; + // Also make sure the inner loop preheader does not contain any unsafe + // instructions. Note that all instructions in the preheader will be moved to + // the outer loop header when interchanging. + if (InnerLoopPreHeader != OuterLoopHeader && + containsUnsafeInstructions(InnerLoopPreHeader)) + return false; + LLVM_DEBUG(dbgs() << "Loops are perfectly nested\n"); // We have a perfect loop nest. return true; @@ -667,6 +661,10 @@ static Value *followLCSSA(Value *SV) { // Check V's users to see if it is involved in a reduction in L. static PHINode *findInnerReductionPhi(Loop *L, Value *V) { + // Reduction variables cannot be constants. + if (isa(V)) + return nullptr; + for (Value *User : V->users()) { if (PHINode *PHI = dyn_cast(User)) { if (PHI->getNumIncomingValues() == 1) @@ -707,8 +705,7 @@ bool LoopInterchangeLegality::findInductionAndReductions( Value *V = followLCSSA(PHI.getIncomingValueForBlock(L->getLoopLatch())); PHINode *InnerRedPhi = findInnerReductionPhi(InnerLoop, V); if (!InnerRedPhi || - !llvm::any_of(InnerRedPhi->incoming_values(), - [&PHI](Value *V) { return V == &PHI; })) { + !llvm::is_contained(InnerRedPhi->incoming_values(), &PHI)) { LLVM_DEBUG( dbgs() << "Failed to recognize PHI as an induction or reduction.\n"); @@ -1045,6 +1042,10 @@ int LoopInterchangeProfitability::getInstrOrderCost() { bool FoundInnerInduction = false; bool FoundOuterInduction = false; for (unsigned i = 0; i < NumOp; ++i) { + // Skip operands that are not SCEV-able. + if (!SE->isSCEVable(GEP->getOperand(i)->getType())) + continue; + const SCEV *OperandVal = SE->getSCEV(GEP->getOperand(i)); const SCEVAddRecExpr *AR = dyn_cast(OperandVal); if (!AR) @@ -1189,7 +1190,7 @@ void LoopInterchangeTransform::restructureLoops( removeChildLoop(NewInner, NewOuter); LI->changeTopLevelLoop(NewInner, NewOuter); } - while (!NewOuter->empty()) + while (!NewOuter->isInnermost()) NewInner->addChildLoop(NewOuter->removeChildLoop(NewOuter->begin())); NewOuter->addChildLoop(NewInner); @@ -1305,6 +1306,21 @@ bool LoopInterchangeTransform::transform() { LLVM_DEBUG(dbgs() << "splitting InnerLoopHeader done\n"); } + // Instructions in the original inner loop preheader may depend on values + // defined in the outer loop header. Move them there, because the original + // inner loop preheader will become the entry into the interchanged loop nest. + // Currently we move all instructions and rely on LICM to move invariant + // instructions outside the loop nest. + BasicBlock *InnerLoopPreHeader = InnerLoop->getLoopPreheader(); + BasicBlock *OuterLoopHeader = OuterLoop->getHeader(); + if (InnerLoopPreHeader != OuterLoopHeader) { + SmallPtrSet NeedsMoving; + for (Instruction &I : + make_early_inc_range(make_range(InnerLoopPreHeader->begin(), + std::prev(InnerLoopPreHeader->end())))) + I.moveBefore(OuterLoopHeader->getTerminator()); + } + Transformed |= adjustLoopLinks(); if (!Transformed) { LLVM_DEBUG(dbgs() << "adjustLoopLinks failed\n"); @@ -1521,8 +1537,7 @@ bool LoopInterchangeTransform::adjustLoopBranches() { InnerLoopPreHeader, DTUpdates, /*MustUpdateOnce=*/false); // The outer loop header might or might not branch to the outer latch. // We are guaranteed to branch to the inner loop preheader. - if (std::find(succ_begin(OuterLoopHeaderBI), succ_end(OuterLoopHeaderBI), - OuterLoopLatch) != succ_end(OuterLoopHeaderBI)) + if (llvm::is_contained(OuterLoopHeaderBI->successors(), OuterLoopLatch)) updateSuccessor(OuterLoopHeaderBI, OuterLoopLatch, LoopExit, DTUpdates, /*MustUpdateOnce=*/false); updateSuccessor(OuterLoopHeaderBI, InnerLoopPreHeader, @@ -1569,9 +1584,9 @@ bool LoopInterchangeTransform::adjustLoopBranches() { // Now update the reduction PHIs in the inner and outer loop headers. SmallVector InnerLoopPHIs, OuterLoopPHIs; - for (PHINode &PHI : drop_begin(InnerLoopHeader->phis(), 1)) + for (PHINode &PHI : drop_begin(InnerLoopHeader->phis())) InnerLoopPHIs.push_back(cast(&PHI)); - for (PHINode &PHI : drop_begin(OuterLoopHeader->phis(), 1)) + for (PHINode &PHI : drop_begin(OuterLoopHeader->phis())) OuterLoopPHIs.push_back(cast(&PHI)); auto &OuterInnerReductions = LIL.getOuterInnerReductions(); @@ -1595,6 +1610,17 @@ bool LoopInterchangeTransform::adjustLoopBranches() { InnerLoopHeader->replacePhiUsesWith(OuterLoopPreHeader, InnerLoopPreHeader); InnerLoopHeader->replacePhiUsesWith(OuterLoopLatch, InnerLoopLatch); + // Values defined in the outer loop header could be used in the inner loop + // latch. In that case, we need to create LCSSA phis for them, because after + // interchanging they will be defined in the new inner loop and used in the + // new outer loop. + IRBuilder<> Builder(OuterLoopHeader->getContext()); + SmallVector MayNeedLCSSAPhis; + for (Instruction &I : + make_range(OuterLoopHeader->begin(), std::prev(OuterLoopHeader->end()))) + MayNeedLCSSAPhis.push_back(&I); + formLCSSAForInstructions(MayNeedLCSSAPhis, *DT, *LI, SE, Builder); + return true; } @@ -1612,15 +1638,58 @@ bool LoopInterchangeTransform::adjustLoopLinks() { return Changed; } -char LoopInterchange::ID = 0; +/// Main LoopInterchange Pass. +struct LoopInterchangeLegacyPass : public LoopPass { + static char ID; + + LoopInterchangeLegacyPass() : LoopPass(ID) { + initializeLoopInterchangeLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + + getLoopAnalysisUsage(AU); + } + + bool runOnLoop(Loop *L, LPPassManager &LPM) override { + if (skipLoop(L)) + return false; + + auto *SE = &getAnalysis().getSE(); + auto *LI = &getAnalysis().getLoopInfo(); + auto *DI = &getAnalysis().getDI(); + auto *DT = &getAnalysis().getDomTree(); + auto *ORE = &getAnalysis().getORE(); + + return LoopInterchange(SE, LI, DI, DT, ORE).run(L); + } +}; -INITIALIZE_PASS_BEGIN(LoopInterchange, "loop-interchange", +char LoopInterchangeLegacyPass::ID = 0; + +INITIALIZE_PASS_BEGIN(LoopInterchangeLegacyPass, "loop-interchange", "Interchanges loops for cache reuse", false, false) INITIALIZE_PASS_DEPENDENCY(LoopPass) INITIALIZE_PASS_DEPENDENCY(DependenceAnalysisWrapperPass) INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) -INITIALIZE_PASS_END(LoopInterchange, "loop-interchange", +INITIALIZE_PASS_END(LoopInterchangeLegacyPass, "loop-interchange", "Interchanges loops for cache reuse", false, false) -Pass *llvm::createLoopInterchangePass() { return new LoopInterchange(); } +Pass *llvm::createLoopInterchangePass() { + return new LoopInterchangeLegacyPass(); +} + +PreservedAnalyses LoopInterchangePass::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + Function &F = *L.getHeader()->getParent(); + + DependenceInfo DI(&F, &AR.AA, &AR.SE, &AR.LI); + OptimizationRemarkEmitter ORE(&F); + if (!LoopInterchange(&AR.SE, &AR.LI, &DI, &AR.DT, &ORE).run(&L)) + return PreservedAnalyses::all(); + return getLoopPassPreservedAnalyses(); +} diff --git a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp index 4412b3079461..058612149a94 100644 --- a/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp +++ b/llvm/lib/Transforms/Scalar/LoopLoadElimination.cpp @@ -27,7 +27,6 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BlockFrequencyInfo.h" #include "llvm/Analysis/GlobalsModRef.h" @@ -56,6 +55,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/LoopVersioning.h" #include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" #include "llvm/Transforms/Utils/SizeOpts.h" @@ -308,8 +308,8 @@ public: /// We need a check if one is a pointer for a candidate load and the other is /// a pointer for a possibly intervening store. bool needsChecking(unsigned PtrIdx1, unsigned PtrIdx2, - const SmallPtrSet &PtrsWrittenOnFwdingPath, - const std::set &CandLoadPtrs) { + const SmallPtrSetImpl &PtrsWrittenOnFwdingPath, + const SmallPtrSetImpl &CandLoadPtrs) { Value *Ptr1 = LAI.getRuntimePointerChecking()->getPointerInfo(PtrIdx1).PointerValue; Value *Ptr2 = @@ -384,11 +384,9 @@ public: findPointersWrittenOnForwardingPath(Candidates); // Collect the pointers of the candidate loads. - // FIXME: SmallPtrSet does not work with std::inserter. - std::set CandLoadPtrs; - transform(Candidates, - std::inserter(CandLoadPtrs, CandLoadPtrs.begin()), - std::mem_fn(&StoreToLoadForwardingCandidate::getLoadPtr)); + SmallPtrSet CandLoadPtrs; + for (const auto &Candidate : Candidates) + CandLoadPtrs.insert(Candidate.getLoadPtr()); const auto &AllChecks = LAI.getRuntimePointerChecking()->getChecks(); SmallVector Checks; @@ -488,7 +486,6 @@ public: // Filter the candidates further. SmallVector Candidates; - unsigned NumForwarding = 0; for (const StoreToLoadForwardingCandidate &Cand : StoreToLoadDependences) { LLVM_DEBUG(dbgs() << "Candidate " << Cand); @@ -508,12 +505,17 @@ public: if (!Cand.isDependenceDistanceOfOne(PSE, L)) continue; - ++NumForwarding; + assert(isa(PSE.getSCEV(Cand.Load->getPointerOperand())) && + "Loading from something other than indvar?"); + assert( + isa(PSE.getSCEV(Cand.Store->getPointerOperand())) && + "Storing to something other than indvar?"); + + Candidates.push_back(Cand); LLVM_DEBUG( dbgs() - << NumForwarding + << Candidates.size() << ". Valid store-to-load forwarding across the loop backedge\n"); - Candidates.push_back(Cand); } if (Candidates.empty()) return false; @@ -561,10 +563,19 @@ public: // Point of no-return, start the transformation. First, version the loop // if necessary. - LoopVersioning LV(LAI, L, LI, DT, PSE.getSE(), false); - LV.setAliasChecks(std::move(Checks)); - LV.setSCEVChecks(LAI.getPSE().getUnionPredicate()); + LoopVersioning LV(LAI, Checks, L, LI, DT, PSE.getSE()); LV.versionLoop(); + + // After versioning, some of the candidates' pointers could stop being + // SCEVAddRecs. We need to filter them out. + auto NoLongerGoodCandidate = [this]( + const StoreToLoadForwardingCandidate &Cand) { + return !isa( + PSE.getSCEV(Cand.Load->getPointerOperand())) || + !isa( + PSE.getSCEV(Cand.Store->getPointerOperand())); + }; + llvm::erase_if(Candidates, NoLongerGoodCandidate); } // Next, propagate the value stored by the store to the users of the load. @@ -573,7 +584,7 @@ public: "storeforward"); for (const auto &Cand : Candidates) propagateStoredValueToLoadUsers(Cand, SEE); - NumLoopLoadEliminted += NumForwarding; + NumLoopLoadEliminted += Candidates.size(); return true; } @@ -599,6 +610,7 @@ private: static bool eliminateLoadsAcrossLoops(Function &F, LoopInfo &LI, DominatorTree &DT, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, + ScalarEvolution *SE, AssumptionCache *AC, function_ref GetLAI) { // Build up a worklist of inner-loops to transform to avoid iterator // invalidation. @@ -607,15 +619,21 @@ eliminateLoadsAcrossLoops(Function &F, LoopInfo &LI, DominatorTree &DT, // which merely optimizes the use of loads in a loop. SmallVector Worklist; + bool Changed = false; + for (Loop *TopLevelLoop : LI) - for (Loop *L : depth_first(TopLevelLoop)) + for (Loop *L : depth_first(TopLevelLoop)) { + Changed |= simplifyLoop(L, &DT, &LI, SE, AC, /*MSSAU*/ nullptr, false); // We only handle inner-most loops. - if (L->empty()) + if (L->isInnermost()) Worklist.push_back(L); + } // Now walk the identified inner loops. - bool Changed = false; for (Loop *L : Worklist) { + // Match historical behavior + if (!L->isRotatedForm() || !L->getExitingBlock()) + continue; // The actual work is performed by LoadEliminationForLoop. LoadEliminationForLoop LEL(L, &LI, GetLAI(*L), &DT, BFI, PSI); Changed |= LEL.processLoop(); @@ -649,7 +667,7 @@ public: // Process each loop nest in the function. return eliminateLoadsAcrossLoops( - F, LI, DT, BFI, PSI, + F, LI, DT, BFI, PSI, /*SE*/ nullptr, /*AC*/ nullptr, [&LAA](Loop &L) -> const LoopAccessInfo & { return LAA.getInfo(&L); }); } @@ -706,8 +724,9 @@ PreservedAnalyses LoopLoadEliminationPass::run(Function &F, auto &LAM = AM.getResult(F).getManager(); bool Changed = eliminateLoadsAcrossLoops( - F, LI, DT, BFI, PSI, [&](Loop &L) -> const LoopAccessInfo & { - LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, TLI, TTI, MSSA}; + F, LI, DT, BFI, PSI, &SE, &AC, [&](Loop &L) -> const LoopAccessInfo & { + LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, + TLI, TTI, nullptr, MSSA}; return LAM.getResult(L, AR); }); diff --git a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp index 98889a9df116..3fe8e7259114 100644 --- a/llvm/lib/Transforms/Scalar/LoopPassManager.cpp +++ b/llvm/lib/Transforms/Scalar/LoopPassManager.cpp @@ -6,74 +6,113 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Support/TimeProfiler.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" -#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/AssumptionCache.h" +#include "llvm/Analysis/BasicAliasAnalysis.h" +#include "llvm/Analysis/BlockFrequencyInfo.h" +#include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" +#include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/Support/TimeProfiler.h" using namespace llvm; -// Explicit template instantiations and specialization defininitions for core -// template typedefs. namespace llvm { -template class PassManager; /// Explicitly specialize the pass manager's run method to handle loop nest /// structure updates. -template <> PreservedAnalyses PassManager::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &U) { - PreservedAnalyses PA = PreservedAnalyses::all(); if (DebugLogging) dbgs() << "Starting Loop pass manager run.\n"; + // Runs loop-nest passes only when the current loop is a top-level one. + PreservedAnalyses PA = (L.isOutermost() && !LoopNestPasses.empty()) + ? runWithLoopNestPasses(L, AM, AR, U) + : runWithoutLoopNestPasses(L, AM, AR, U); + + // Invalidation for the current loop should be handled above, and other loop + // analysis results shouldn't be impacted by runs over this loop. Therefore, + // the remaining analysis results in the AnalysisManager are preserved. We + // mark this with a set so that we don't need to inspect each one + // individually. + // FIXME: This isn't correct! This loop and all nested loops' analyses should + // be preserved, but unrolling should invalidate the parent loop's analyses. + PA.preserveSet>(); + + if (DebugLogging) + dbgs() << "Finished Loop pass manager run.\n"; + + return PA; +} + +// Run both loop passes and loop-nest passes on top-level loop \p L. +PreservedAnalyses +LoopPassManager::runWithLoopNestPasses(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + assert(L.isOutermost() && + "Loop-nest passes should only run on top-level loops."); + PreservedAnalyses PA = PreservedAnalyses::all(); + // Request PassInstrumentation from analysis manager, will use it to run // instrumenting callbacks for the passes later. PassInstrumentation PI = AM.getResult(L, AR); - for (auto &Pass : Passes) { - // Check the PassInstrumentation's BeforePass callbacks before running the - // pass, skip its execution completely if asked to (callback returns false). - if (!PI.runBeforePass(*Pass, L)) - continue; - if (DebugLogging) - dbgs() << "Running pass: " << Pass->name() << " on " << L; + unsigned LoopPassIndex = 0, LoopNestPassIndex = 0; - PreservedAnalyses PassPA; - { - TimeTraceScope TimeScope(Pass->name(), L.getName()); - PassPA = Pass->run(L, AM, AR, U); + // `LoopNestPtr` points to the `LoopNest` object for the current top-level + // loop and `IsLoopNestPtrValid` indicates whether the pointer is still valid. + // The `LoopNest` object will have to be re-constructed if the pointer is + // invalid when encountering a loop-nest pass. + std::unique_ptr LoopNestPtr; + bool IsLoopNestPtrValid = false; + + for (size_t I = 0, E = IsLoopNestPass.size(); I != E; ++I) { + Optional PassPA; + if (!IsLoopNestPass[I]) { + // The `I`-th pass is a loop pass. + auto &Pass = LoopPasses[LoopPassIndex++]; + PassPA = runSinglePass(L, Pass, AM, AR, U, PI); + } else { + // The `I`-th pass is a loop-nest pass. + auto &Pass = LoopNestPasses[LoopNestPassIndex++]; + + // If the loop-nest object calculated before is no longer valid, + // re-calculate it here before running the loop-nest pass. + if (!IsLoopNestPtrValid) { + LoopNestPtr = LoopNest::getLoopNest(L, AR.SE); + IsLoopNestPtrValid = true; + } + PassPA = runSinglePass(*LoopNestPtr, Pass, AM, AR, U, PI); } - // do not pass deleted Loop into the instrumentation - if (U.skipCurrentLoop()) - PI.runAfterPassInvalidated(*Pass); - else - PI.runAfterPass(*Pass, L); + // `PassPA` is `None` means that the before-pass callbacks in + // `PassInstrumentation` return false. The pass does not run in this case, + // so we can skip the following procedure. + if (!PassPA) + continue; // If the loop was deleted, abort the run and return to the outer walk. if (U.skipCurrentLoop()) { - PA.intersect(std::move(PassPA)); + PA.intersect(std::move(*PassPA)); break; } -#ifndef NDEBUG - // Verify the loop structure and LCSSA form before visiting the loop. - L.verifyLoop(); - assert(L.isRecursivelyLCSSAForm(AR.DT, AR.LI) && - "Loops must remain in LCSSA form!"); -#endif - // Update the analysis manager as each pass runs and potentially // invalidates analyses. - AM.invalidate(L, PassPA); + AM.invalidate(L, *PassPA); // Finally, we intersect the final preserved analyses to compute the // aggregate preserved set for this pass manager. - PA.intersect(std::move(PassPA)); + PA.intersect(std::move(*PassPA)); + + // Check if the current pass preserved the loop-nest object or not. + IsLoopNestPtrValid &= PassPA->getChecker().preserved(); // FIXME: Historically, the pass managers all called the LLVM context's // yield function here. We don't have a generic way to acquire the @@ -81,21 +120,207 @@ PassManager>(); +// Run all loop passes on loop \p L. Loop-nest passes don't run either because +// \p L is not a top-level one or simply because there are no loop-nest passes +// in the pass manager at all. +PreservedAnalyses +LoopPassManager::runWithoutLoopNestPasses(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + PreservedAnalyses PA = PreservedAnalyses::all(); - if (DebugLogging) - dbgs() << "Finished Loop pass manager run.\n"; + // Request PassInstrumentation from analysis manager, will use it to run + // instrumenting callbacks for the passes later. + PassInstrumentation PI = AM.getResult(L, AR); + for (auto &Pass : LoopPasses) { + Optional PassPA = runSinglePass(L, Pass, AM, AR, U, PI); + + // `PassPA` is `None` means that the before-pass callbacks in + // `PassInstrumentation` return false. The pass does not run in this case, + // so we can skip the following procedure. + if (!PassPA) + continue; + + // If the loop was deleted, abort the run and return to the outer walk. + if (U.skipCurrentLoop()) { + PA.intersect(std::move(*PassPA)); + break; + } + // Update the analysis manager as each pass runs and potentially + // invalidates analyses. + AM.invalidate(L, *PassPA); + + // Finally, we intersect the final preserved analyses to compute the + // aggregate preserved set for this pass manager. + PA.intersect(std::move(*PassPA)); + + // FIXME: Historically, the pass managers all called the LLVM context's + // yield function here. We don't have a generic way to acquire the + // context and it isn't yet clear what the right pattern is for yielding + // in the new pass manager so it is currently omitted. + // ...getContext().yield(); + } return PA; } +} // namespace llvm + +PreservedAnalyses FunctionToLoopPassAdaptor::run(Function &F, + FunctionAnalysisManager &AM) { + // Before we even compute any loop analyses, first run a miniature function + // pass pipeline to put loops into their canonical form. Note that we can + // directly build up function analyses after this as the function pass + // manager handles all the invalidation at that layer. + PassInstrumentation PI = AM.getResult(F); + + PreservedAnalyses PA = PreservedAnalyses::all(); + // Check the PassInstrumentation's BeforePass callbacks before running the + // canonicalization pipeline. + if (PI.runBeforePass(LoopCanonicalizationFPM, F)) { + PA = LoopCanonicalizationFPM.run(F, AM); + PI.runAfterPass(LoopCanonicalizationFPM, F, PA); + } + + // Get the loop structure for this function + LoopInfo &LI = AM.getResult(F); + + // If there are no loops, there is nothing to do here. + if (LI.empty()) + return PA; + + // Get the analysis results needed by loop passes. + MemorySSA *MSSA = + UseMemorySSA ? (&AM.getResult(F).getMSSA()) : nullptr; + BlockFrequencyInfo *BFI = UseBlockFrequencyInfo && F.hasProfileData() + ? (&AM.getResult(F)) + : nullptr; + LoopStandardAnalysisResults LAR = {AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + AM.getResult(F), + BFI, + MSSA}; + + // Setup the loop analysis manager from its proxy. It is important that + // this is only done when there are loops to process and we have built the + // LoopStandardAnalysisResults object. The loop analyses cached in this + // manager have access to those analysis results and so it must invalidate + // itself when they go away. + auto &LAMFP = AM.getResult(F); + if (UseMemorySSA) + LAMFP.markMSSAUsed(); + LoopAnalysisManager &LAM = LAMFP.getManager(); + + // A postorder worklist of loops to process. + SmallPriorityWorklist Worklist; + + // Register the worklist and loop analysis manager so that loop passes can + // update them when they mutate the loop nest structure. + LPMUpdater Updater(Worklist, LAM, LoopNestMode); + + // Add the loop nests in the reverse order of LoopInfo. See method + // declaration. + if (!LoopNestMode) { + appendLoopsToWorklist(LI, Worklist); + } else { + for (Loop *L : LI) + Worklist.insert(L); + } + +#ifndef NDEBUG + PI.pushBeforeNonSkippedPassCallback([&LAR, &LI](StringRef PassID, Any IR) { + if (isSpecialPass(PassID, {"PassManager"})) + return; + assert(any_isa(IR) || any_isa(IR)); + const Loop *L = any_isa(IR) + ? any_cast(IR) + : &any_cast(IR)->getOutermostLoop(); + assert(L && "Loop should be valid for printing"); + + // Verify the loop structure and LCSSA form before visiting the loop. + L->verifyLoop(); + assert(L->isRecursivelyLCSSAForm(LAR.DT, LI) && + "Loops must remain in LCSSA form!"); + }); +#endif + + do { + Loop *L = Worklist.pop_back_val(); + assert(!(LoopNestMode && L->getParentLoop()) && + "L should be a top-level loop in loop-nest mode."); + + // Reset the update structure for this loop. + Updater.CurrentL = L; + Updater.SkipCurrentLoop = false; + +#ifndef NDEBUG + // Save a parent loop pointer for asserts. + Updater.ParentL = L->getParentLoop(); +#endif + // Check the PassInstrumentation's BeforePass callbacks before running the + // pass, skip its execution completely if asked to (callback returns + // false). + if (!PI.runBeforePass(*Pass, *L)) + continue; + + PreservedAnalyses PassPA; + { + TimeTraceScope TimeScope(Pass->name()); + PassPA = Pass->run(*L, LAM, LAR, Updater); + } + + // Do not pass deleted Loop into the instrumentation. + if (Updater.skipCurrentLoop()) + PI.runAfterPassInvalidated(*Pass, PassPA); + else + PI.runAfterPass(*Pass, *L, PassPA); + + // FIXME: We should verify the set of analyses relevant to Loop passes + // are preserved. + + // If the loop hasn't been deleted, we need to handle invalidation here. + if (!Updater.skipCurrentLoop()) + // We know that the loop pass couldn't have invalidated any other + // loop's analyses (that's the contract of a loop pass), so directly + // handle the loop analysis manager's invalidation here. + LAM.invalidate(*L, PassPA); + + // Then intersect the preserved set so that invalidation of module + // analyses will eventually occur when the module pass completes. + PA.intersect(std::move(PassPA)); + } while (!Worklist.empty()); + +#ifndef NDEBUG + PI.popBeforeNonSkippedPassCallback(); +#endif + + // By definition we preserve the proxy. We also preserve all analyses on + // Loops. This precludes *any* invalidation of loop analyses by the proxy, + // but that's OK because we've taken care to invalidate analyses in the + // loop analysis manager incrementally above. + PA.preserveSet>(); + PA.preserve(); + // We also preserve the set of standard analyses. + PA.preserve(); + PA.preserve(); + PA.preserve(); + if (UseBlockFrequencyInfo && F.hasProfileData()) + PA.preserve(); + if (UseMemorySSA) + PA.preserve(); + // FIXME: What we really want to do here is preserve an AA category, but + // that concept doesn't exist yet. + PA.preserve(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + return PA; } PrintLoopPass::PrintLoopPass() : OS(dbgs()) {} diff --git a/llvm/lib/Transforms/Scalar/LoopPredication.cpp b/llvm/lib/Transforms/Scalar/LoopPredication.cpp index edde22d6708f..4f97641e2027 100644 --- a/llvm/lib/Transforms/Scalar/LoopPredication.cpp +++ b/llvm/lib/Transforms/Scalar/LoopPredication.cpp @@ -362,7 +362,7 @@ PreservedAnalyses LoopPredicationPass::run(Loop &L, LoopAnalysisManager &AM, // For the new PM, we also can't use BranchProbabilityInfo as an analysis // pass. Function analyses need to be preserved across loop transformations // but BPI is not preserved, hence a newly built one is needed. - BranchProbabilityInfo BPI(*F, AR.LI, &AR.TLI); + BranchProbabilityInfo BPI(*F, AR.LI, &AR.TLI, &AR.DT, nullptr); LoopPredication LP(&AR.AA, &AR.DT, &AR.SE, &AR.LI, &BPI); if (!LP.runOnLoop(&L)) return PreservedAnalyses::all(); @@ -439,8 +439,8 @@ static bool isSafeToTruncateWideIVType(const DataLayout &DL, Type *RangeCheckType) { if (!EnableIVTruncation) return false; - assert(DL.getTypeSizeInBits(LatchCheck.IV->getType()) > - DL.getTypeSizeInBits(RangeCheckType) && + assert(DL.getTypeSizeInBits(LatchCheck.IV->getType()).getFixedSize() > + DL.getTypeSizeInBits(RangeCheckType).getFixedSize() && "Expected latch check IV type to be larger than range check operand " "type!"); // The start and end values of the IV should be known. This is to guarantee @@ -454,13 +454,13 @@ static bool isSafeToTruncateWideIVType(const DataLayout &DL, // LatchEnd = 2, rangeCheckType = i32. If it's not a monotonic predicate, the // IV wraps around, and the truncation of the IV would lose the range of // iterations between 2^32 and 2^64. - bool Increasing; - if (!SE.isMonotonicPredicate(LatchCheck.IV, LatchCheck.Pred, Increasing)) + if (!SE.getMonotonicPredicateType(LatchCheck.IV, LatchCheck.Pred)) return false; // The active bits should be less than the bits in the RangeCheckType. This // guarantees that truncating the latch check to RangeCheckType is a safe // operation. - auto RangeCheckTypeBitSize = DL.getTypeSizeInBits(RangeCheckType); + auto RangeCheckTypeBitSize = + DL.getTypeSizeInBits(RangeCheckType).getFixedSize(); return Start->getAPInt().getActiveBits() < RangeCheckTypeBitSize && Limit->getAPInt().getActiveBits() < RangeCheckTypeBitSize; } @@ -477,7 +477,8 @@ static Optional generateLoopLatchCheck(const DataLayout &DL, if (RangeCheckType == LatchType) return LatchCheck; // For now, bail out if latch type is narrower than range type. - if (DL.getTypeSizeInBits(LatchType) < DL.getTypeSizeInBits(RangeCheckType)) + if (DL.getTypeSizeInBits(LatchType).getFixedSize() < + DL.getTypeSizeInBits(RangeCheckType).getFixedSize()) return None; if (!isSafeToTruncateWideIVType(DL, SE, LatchCheck, RangeCheckType)) return None; diff --git a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp index 3542d0a4ee73..b3bae47e96de 100644 --- a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp @@ -50,6 +50,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Scalar/LoopReroll.h" #include "llvm/Transforms/Utils.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" @@ -161,12 +162,12 @@ namespace { IL_End }; - class LoopReroll : public LoopPass { + class LoopRerollLegacyPass : public LoopPass { public: static char ID; // Pass ID, replacement for typeid - LoopReroll() : LoopPass(ID) { - initializeLoopRerollPass(*PassRegistry::getPassRegistry()); + LoopRerollLegacyPass() : LoopPass(ID) { + initializeLoopRerollLegacyPassPass(*PassRegistry::getPassRegistry()); } bool runOnLoop(Loop *L, LPPassManager &LPM) override; @@ -175,6 +176,15 @@ namespace { AU.addRequired(); getLoopAnalysisUsage(AU); } + }; + + class LoopReroll { + public: + LoopReroll(AliasAnalysis *AA, LoopInfo *LI, ScalarEvolution *SE, + TargetLibraryInfo *TLI, DominatorTree *DT, bool PreserveLCSSA) + : AA(AA), LI(LI), SE(SE), TLI(TLI), DT(DT), + PreserveLCSSA(PreserveLCSSA) {} + bool runOnLoop(Loop *L); protected: AliasAnalysis *AA; @@ -484,16 +494,16 @@ namespace { } // end anonymous namespace -char LoopReroll::ID = 0; +char LoopRerollLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(LoopReroll, "loop-reroll", "Reroll loops", false, false) +INITIALIZE_PASS_BEGIN(LoopRerollLegacyPass, "loop-reroll", "Reroll loops", + false, false) INITIALIZE_PASS_DEPENDENCY(LoopPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) -INITIALIZE_PASS_END(LoopReroll, "loop-reroll", "Reroll loops", false, false) +INITIALIZE_PASS_END(LoopRerollLegacyPass, "loop-reroll", "Reroll loops", false, + false) -Pass *llvm::createLoopRerollPass() { - return new LoopReroll; -} +Pass *llvm::createLoopRerollPass() { return new LoopRerollLegacyPass; } // Returns true if the provided instruction is used outside the given loop. // This operates like Instruction::isUsedOutsideOfBlock, but considers PHIs in @@ -1086,7 +1096,7 @@ LoopReroll::DAGRootTracker::nextInstr(int Val, UsesTy &In, UsesTy::iterator *StartI) { UsesTy::iterator I = StartI ? *StartI : In.begin(); while (I != In.end() && (I->second.test(Val) == 0 || - Exclude.count(I->first) != 0)) + Exclude.contains(I->first))) ++I; return I; } @@ -1644,18 +1654,7 @@ bool LoopReroll::reroll(Instruction *IV, Loop *L, BasicBlock *Header, return true; } -bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) { - if (skipLoop(L)) - return false; - - AA = &getAnalysis().getAAResults(); - LI = &getAnalysis().getLoopInfo(); - SE = &getAnalysis().getSE(); - TLI = &getAnalysis().getTLI( - *L->getHeader()->getParent()); - DT = &getAnalysis().getDomTree(); - PreserveLCSSA = mustPreserveAnalysisID(LCSSAID); - +bool LoopReroll::runOnLoop(Loop *L) { BasicBlock *Header = L->getHeader(); LLVM_DEBUG(dbgs() << "LRR: F[" << Header->getParent()->getName() << "] Loop %" << Header->getName() << " (" << L->getNumBlocks() @@ -1704,3 +1703,26 @@ bool LoopReroll::runOnLoop(Loop *L, LPPassManager &LPM) { return Changed; } + +bool LoopRerollLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) { + if (skipLoop(L)) + return false; + + auto *AA = &getAnalysis().getAAResults(); + auto *LI = &getAnalysis().getLoopInfo(); + auto *SE = &getAnalysis().getSE(); + auto *TLI = &getAnalysis().getTLI( + *L->getHeader()->getParent()); + auto *DT = &getAnalysis().getDomTree(); + bool PreserveLCSSA = mustPreserveAnalysisID(LCSSAID); + + return LoopReroll(AA, LI, SE, TLI, DT, PreserveLCSSA).runOnLoop(L); +} + +PreservedAnalyses LoopRerollPass::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &AR, + LPMUpdater &U) { + return LoopReroll(&AR.AA, &AR.LI, &AR.SE, &AR.TLI, &AR.DT, true).runOnLoop(&L) + ? getLoopPassPreservedAnalyses() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Scalar/LoopRotation.cpp b/llvm/lib/Transforms/Scalar/LoopRotation.cpp index f92566ba77ce..ad1cfc68ece0 100644 --- a/llvm/lib/Transforms/Scalar/LoopRotation.cpp +++ b/llvm/lib/Transforms/Scalar/LoopRotation.cpp @@ -12,6 +12,7 @@ #include "llvm/Transforms/Scalar/LoopRotation.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/MemorySSA.h" @@ -33,22 +34,35 @@ static cl::opt DefaultRotationThreshold( "rotation-max-header-size", cl::init(16), cl::Hidden, cl::desc("The default maximum header size for automatic loop rotation")); -LoopRotatePass::LoopRotatePass(bool EnableHeaderDuplication) - : EnableHeaderDuplication(EnableHeaderDuplication) {} +static cl::opt PrepareForLTOOption( + "rotation-prepare-for-lto", cl::init(false), cl::Hidden, + cl::desc("Run loop-rotation in the prepare-for-lto stage. This option " + "should be used for testing only.")); + +LoopRotatePass::LoopRotatePass(bool EnableHeaderDuplication, bool PrepareForLTO) + : EnableHeaderDuplication(EnableHeaderDuplication), + PrepareForLTO(PrepareForLTO) {} PreservedAnalyses LoopRotatePass::run(Loop &L, LoopAnalysisManager &AM, LoopStandardAnalysisResults &AR, LPMUpdater &) { - int Threshold = EnableHeaderDuplication ? DefaultRotationThreshold : 0; + // Vectorization requires loop-rotation. Use default threshold for loops the + // user explicitly marked for vectorization, even when header duplication is + // disabled. + int Threshold = EnableHeaderDuplication || + hasVectorizeTransformation(&L) == TM_ForcedByUser + ? DefaultRotationThreshold + : 0; const DataLayout &DL = L.getHeader()->getModule()->getDataLayout(); const SimplifyQuery SQ = getBestSimplifyQuery(AR, DL); Optional MSSAU; if (AR.MSSA) MSSAU = MemorySSAUpdater(AR.MSSA); - bool Changed = LoopRotation(&L, &AR.LI, &AR.TTI, &AR.AC, &AR.DT, &AR.SE, - MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, - SQ, false, Threshold, false); + bool Changed = + LoopRotation(&L, &AR.LI, &AR.TTI, &AR.AC, &AR.DT, &AR.SE, + MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, SQ, false, + Threshold, false, PrepareForLTO || PrepareForLTOOption); if (!Changed) return PreservedAnalyses::all(); @@ -66,10 +80,13 @@ namespace { class LoopRotateLegacyPass : public LoopPass { unsigned MaxHeaderSize; + bool PrepareForLTO; public: static char ID; // Pass ID, replacement for typeid - LoopRotateLegacyPass(int SpecifiedMaxHeaderSize = -1) : LoopPass(ID) { + LoopRotateLegacyPass(int SpecifiedMaxHeaderSize = -1, + bool PrepareForLTO = false) + : LoopPass(ID), PrepareForLTO(PrepareForLTO) { initializeLoopRotateLegacyPassPass(*PassRegistry::getPassRegistry()); if (SpecifiedMaxHeaderSize == -1) MaxHeaderSize = DefaultRotationThreshold; @@ -105,9 +122,17 @@ public: if (MSSAA) MSSAU = MemorySSAUpdater(&MSSAA->getMSSA()); } + // Vectorization requires loop-rotation. Use default threshold for loops the + // user explicitly marked for vectorization, even when header duplication is + // disabled. + int Threshold = hasVectorizeTransformation(L) == TM_ForcedByUser + ? DefaultRotationThreshold + : MaxHeaderSize; + return LoopRotation(L, LI, TTI, AC, &DT, &SE, MSSAU.hasValue() ? MSSAU.getPointer() : nullptr, SQ, - false, MaxHeaderSize, false); + false, Threshold, false, + PrepareForLTO || PrepareForLTOOption); } }; } // end namespace @@ -122,6 +147,6 @@ INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) INITIALIZE_PASS_END(LoopRotateLegacyPass, "loop-rotate", "Rotate Loops", false, false) -Pass *llvm::createLoopRotatePass(int MaxHeaderSize) { - return new LoopRotateLegacyPass(MaxHeaderSize); +Pass *llvm::createLoopRotatePass(int MaxHeaderSize, bool PrepareForLTO) { + return new LoopRotateLegacyPass(MaxHeaderSize, PrepareForLTO); } diff --git a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp index 031e5b9c1d2c..cc6d11220807 100644 --- a/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp +++ b/llvm/lib/Transforms/Scalar/LoopSimplifyCFG.cpp @@ -16,7 +16,6 @@ #include "llvm/Transforms/Scalar/LoopSimplifyCFG.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/DependenceAnalysis.h" @@ -366,15 +365,20 @@ private: unsigned DummyIdx = 1; for (BasicBlock *BB : DeadExitBlocks) { - SmallVector DeadPhis; + // Eliminate all Phis and LandingPads from dead exits. + // TODO: Consider removing all instructions in this dead block. + SmallVector DeadInstructions; for (auto &PN : BB->phis()) - DeadPhis.push_back(&PN); + DeadInstructions.push_back(&PN); - // Eliminate all Phis from dead exits. - for (Instruction *PN : DeadPhis) { - PN->replaceAllUsesWith(UndefValue::get(PN->getType())); - PN->eraseFromParent(); + if (auto *LandingPad = dyn_cast(BB->getFirstNonPHI())) + DeadInstructions.emplace_back(LandingPad); + + for (Instruction *I : DeadInstructions) { + I->replaceAllUsesWith(UndefValue::get(I->getType())); + I->eraseFromParent(); } + assert(DummyIdx != 0 && "Too many dead exits!"); DummySwitch->addCase(Builder.getInt32(DummyIdx++), BB); DTUpdates.push_back({DominatorTree::Insert, Preheader, BB}); @@ -410,9 +414,10 @@ private: FixLCSSALoop = FixLCSSALoop->getParentLoop(); assert(FixLCSSALoop && "Should be a loop!"); // We need all DT updates to be done before forming LCSSA. - DTU.applyUpdates(DTUpdates); if (MSSAU) - MSSAU->applyUpdates(DTUpdates, DT); + MSSAU->applyUpdates(DTUpdates, DT, /*UpdateDT=*/true); + else + DTU.applyUpdates(DTUpdates); DTUpdates.clear(); formLCSSARecursively(*FixLCSSALoop, DT, &LI, &SE); } @@ -420,8 +425,7 @@ private: if (MSSAU) { // Clear all updates now. Facilitates deletes that follow. - DTU.applyUpdates(DTUpdates); - MSSAU->applyUpdates(DTUpdates, DT); + MSSAU->applyUpdates(DTUpdates, DT, /*UpdateDT=*/true); DTUpdates.clear(); if (VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); @@ -447,7 +451,7 @@ private: if (LI.isLoopHeader(BB)) { assert(LI.getLoopFor(BB) != &L && "Attempt to remove current loop!"); Loop *DL = LI.getLoopFor(BB); - if (DL->getParentLoop()) { + if (!DL->isOutermost()) { for (auto *PL = DL->getParentLoop(); PL; PL = PL->getParentLoop()) for (auto *BB : DL->getBlocks()) PL->removeBlockFromLoop(BB); diff --git a/llvm/lib/Transforms/Scalar/LoopSink.cpp b/llvm/lib/Transforms/Scalar/LoopSink.cpp index 1c03a4bf6c02..47698fdde69f 100644 --- a/llvm/lib/Transforms/Scalar/LoopSink.cpp +++ b/llvm/lib/Transforms/Scalar/LoopSink.cpp @@ -39,6 +39,8 @@ #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopPass.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h" #include "llvm/IR/Dominators.h" @@ -67,6 +69,14 @@ static cl::opt MaxNumberOfUseBBsForSinking( "max-uses-for-sinking", cl::Hidden, cl::init(30), cl::desc("Do not sink instructions that have too many uses.")); +static cl::opt EnableMSSAInLoopSink( + "enable-mssa-in-loop-sink", cl::Hidden, cl::init(true), + cl::desc("Enable MemorySSA for LoopSink in new pass manager")); + +static cl::opt EnableMSSAInLegacyLoopSink( + "enable-mssa-in-legacy-loop-sink", cl::Hidden, cl::init(false), + cl::desc("Enable MemorySSA for LoopSink in legacy pass manager")); + /// Return adjusted total frequency of \p BBs. /// /// * If there is only one BB, sinking instruction will not introduce code @@ -172,11 +182,10 @@ findBBsToSinkInto(const Loop &L, const SmallPtrSetImpl &UseBBs, // sinking is successful. // \p LoopBlockNumber is used to sort the insertion blocks to ensure // determinism. -static bool sinkInstruction(Loop &L, Instruction &I, - const SmallVectorImpl &ColdLoopBBs, - const SmallDenseMap &LoopBlockNumber, - LoopInfo &LI, DominatorTree &DT, - BlockFrequencyInfo &BFI) { +static bool sinkInstruction( + Loop &L, Instruction &I, const SmallVectorImpl &ColdLoopBBs, + const SmallDenseMap &LoopBlockNumber, LoopInfo &LI, + DominatorTree &DT, BlockFrequencyInfo &BFI, MemorySSAUpdater *MSSAU) { // Compute the set of blocks in loop L which contain a use of I. SmallPtrSet BBs; for (auto &U : I.uses()) { @@ -213,8 +222,7 @@ static bool sinkInstruction(Loop &L, Instruction &I, // of the loop block numbers as iterating the set doesn't give a useful // order. No need to stable sort as the block numbers are a total ordering. SmallVector SortedBBsToSinkInto; - SortedBBsToSinkInto.insert(SortedBBsToSinkInto.begin(), BBsToSinkInto.begin(), - BBsToSinkInto.end()); + llvm::append_range(SortedBBsToSinkInto, BBsToSinkInto); llvm::sort(SortedBBsToSinkInto, [&](BasicBlock *A, BasicBlock *B) { return LoopBlockNumber.find(A)->second < LoopBlockNumber.find(B)->second; }); @@ -230,6 +238,21 @@ static bool sinkInstruction(Loop &L, Instruction &I, Instruction *IC = I.clone(); IC->setName(I.getName()); IC->insertBefore(&*N->getFirstInsertionPt()); + + if (MSSAU && MSSAU->getMemorySSA()->getMemoryAccess(&I)) { + // Create a new MemoryAccess and let MemorySSA set its defining access. + MemoryAccess *NewMemAcc = + MSSAU->createMemoryAccessInBB(IC, nullptr, N, MemorySSA::Beginning); + if (NewMemAcc) { + if (auto *MemDef = dyn_cast(NewMemAcc)) + MSSAU->insertDef(MemDef, /*RenameUses=*/true); + else { + auto *MemUse = cast(NewMemAcc); + MSSAU->insertUse(MemUse, /*RenameUses=*/true); + } + } + } + // Replaces uses of I with IC in N I.replaceUsesWithIf(IC, [N](Use &U) { return cast(U.getUser())->getParent() == N; @@ -244,6 +267,11 @@ static bool sinkInstruction(Loop &L, Instruction &I, NumLoopSunk++; I.moveBefore(&*MoveBB->getFirstInsertionPt()); + if (MSSAU) + if (MemoryUseOrDef *OldMemAcc = cast_or_null( + MSSAU->getMemorySSA()->getMemoryAccess(&I))) + MSSAU->moveToPlace(OldMemAcc, MoveBB, MemorySSA::Beginning); + return true; } @@ -252,15 +280,14 @@ static bool sinkInstruction(Loop &L, Instruction &I, static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI, DominatorTree &DT, BlockFrequencyInfo &BFI, - ScalarEvolution *SE) { + ScalarEvolution *SE, + AliasSetTracker *CurAST, + MemorySSA *MSSA) { BasicBlock *Preheader = L.getLoopPreheader(); - if (!Preheader) - return false; + assert(Preheader && "Expected loop to have preheader"); - // Enable LoopSink only when runtime profile is available. - // With static profile, the sinking decision may be sub-optimal. - if (!Preheader->getParent()->hasProfileData()) - return false; + assert(Preheader->getParent()->hasProfileData() && + "Unexpected call when profile data unavailable."); const BlockFrequency PreheaderFreq = BFI.getBlockFreq(Preheader); // If there are no basic blocks with lower frequency than the preheader then @@ -271,13 +298,15 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI, })) return false; - bool Changed = false; - AliasSetTracker CurAST(AA); + std::unique_ptr MSSAU; + std::unique_ptr LICMFlags; + if (MSSA) { + MSSAU = std::make_unique(MSSA); + LICMFlags = + std::make_unique(/*IsSink=*/true, &L, MSSA); + } - // Compute alias set. - for (BasicBlock *BB : L.blocks()) - CurAST.add(*BB); - CurAST.add(*Preheader); + bool Changed = false; // Sort loop's basic blocks by frequency SmallVector ColdLoopBBs; @@ -300,9 +329,11 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI, // No need to check for instruction's operands are loop invariant. assert(L.hasLoopInvariantOperands(I) && "Insts in a loop's preheader should have loop invariant operands!"); - if (!canSinkOrHoistInst(*I, &AA, &DT, &L, &CurAST, nullptr, false)) + if (!canSinkOrHoistInst(*I, &AA, &DT, &L, CurAST, MSSAU.get(), false, + LICMFlags.get())) continue; - if (sinkInstruction(L, *I, ColdLoopBBs, LoopBlockNumber, LI, DT, BFI)) + if (sinkInstruction(L, *I, ColdLoopBBs, LoopBlockNumber, LI, DT, BFI, + MSSAU.get())) Changed = true; } @@ -311,6 +342,13 @@ static bool sinkLoopInvariantInstructions(Loop &L, AAResults &AA, LoopInfo &LI, return Changed; } +static void computeAliasSet(Loop &L, BasicBlock &Preheader, + AliasSetTracker &CurAST) { + for (BasicBlock *BB : L.blocks()) + CurAST.add(*BB); + CurAST.add(Preheader); +} + PreservedAnalyses LoopSinkPass::run(Function &F, FunctionAnalysisManager &FAM) { LoopInfo &LI = FAM.getResult(F); // Nothing to do if there are no loops. @@ -321,6 +359,10 @@ PreservedAnalyses LoopSinkPass::run(Function &F, FunctionAnalysisManager &FAM) { DominatorTree &DT = FAM.getResult(F); BlockFrequencyInfo &BFI = FAM.getResult(F); + MemorySSA *MSSA = EnableMSSAInLoopSink + ? &FAM.getResult(F).getMSSA() + : nullptr; + // We want to do a postorder walk over the loops. Since loops are a tree this // is equivalent to a reversed preorder walk and preorder is easy to compute // without recursion. Since we reverse the preorder, we will visit siblings @@ -332,11 +374,27 @@ PreservedAnalyses LoopSinkPass::run(Function &F, FunctionAnalysisManager &FAM) { do { Loop &L = *PreorderLoops.pop_back_val(); + BasicBlock *Preheader = L.getLoopPreheader(); + if (!Preheader) + continue; + + // Enable LoopSink only when runtime profile is available. + // With static profile, the sinking decision may be sub-optimal. + if (!Preheader->getParent()->hasProfileData()) + continue; + + std::unique_ptr CurAST; + if (!EnableMSSAInLoopSink) { + CurAST = std::make_unique(AA); + computeAliasSet(L, *Preheader, *CurAST.get()); + } + // Note that we don't pass SCEV here because it is only used to invalidate // loops in SCEV and we don't preserve (or request) SCEV at all making that // unnecessary. Changed |= sinkLoopInvariantInstructions(L, AA, LI, DT, BFI, - /*ScalarEvolution*/ nullptr); + /*ScalarEvolution*/ nullptr, + CurAST.get(), MSSA); } while (!PreorderLoops.empty()); if (!Changed) @@ -344,6 +402,14 @@ PreservedAnalyses LoopSinkPass::run(Function &F, FunctionAnalysisManager &FAM) { PreservedAnalyses PA; PA.preserveSet(); + + if (MSSA) { + PA.preserve(); + + if (VerifyMemorySSA) + MSSA->verifyMemorySSA(); + } + return PA; } @@ -358,19 +424,46 @@ struct LegacyLoopSinkPass : public LoopPass { if (skipLoop(L)) return false; + BasicBlock *Preheader = L->getLoopPreheader(); + if (!Preheader) + return false; + + // Enable LoopSink only when runtime profile is available. + // With static profile, the sinking decision may be sub-optimal. + if (!Preheader->getParent()->hasProfileData()) + return false; + + AAResults &AA = getAnalysis().getAAResults(); auto *SE = getAnalysisIfAvailable(); - return sinkLoopInvariantInstructions( - *L, getAnalysis().getAAResults(), - getAnalysis().getLoopInfo(), + std::unique_ptr CurAST; + MemorySSA *MSSA = nullptr; + if (EnableMSSAInLegacyLoopSink) + MSSA = &getAnalysis().getMSSA(); + else { + CurAST = std::make_unique(AA); + computeAliasSet(*L, *Preheader, *CurAST.get()); + } + + bool Changed = sinkLoopInvariantInstructions( + *L, AA, getAnalysis().getLoopInfo(), getAnalysis().getDomTree(), getAnalysis().getBFI(), - SE ? &SE->getSE() : nullptr); + SE ? &SE->getSE() : nullptr, CurAST.get(), MSSA); + + if (MSSA && VerifyMemorySSA) + MSSA->verifyMemorySSA(); + + return Changed; } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); getLoopAnalysisUsage(AU); + if (EnableMSSAInLegacyLoopSink) { + AU.addRequired(); + AU.addPreserved(); + } } }; } @@ -380,6 +473,7 @@ INITIALIZE_PASS_BEGIN(LegacyLoopSinkPass, "loop-sink", "Loop Sink", false, false) INITIALIZE_PASS_DEPENDENCY(LoopPass) INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(MemorySSAWrapperPass) INITIALIZE_PASS_END(LegacyLoopSinkPass, "loop-sink", "Loop Sink", false, false) Pass *llvm::createLoopSinkPass() { return new LegacyLoopSinkPass(); } diff --git a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp index cf02ef1e83f3..5dec9b542076 100644 --- a/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp +++ b/llvm/lib/Transforms/Scalar/LoopStrengthReduce.cpp @@ -75,11 +75,13 @@ #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/Analysis/ScalarEvolutionExpressions.h" #include "llvm/Analysis/ScalarEvolutionNormalization.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" +#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GlobalValue.h" @@ -422,7 +424,7 @@ static void DoInitialMatch(const SCEV *S, Loop *L, // Handle a multiplication by -1 (negation) if it didn't fold. if (const SCEVMulExpr *Mul = dyn_cast(S)) if (Mul->getOperand(0)->isAllOnesValue()) { - SmallVector Ops(Mul->op_begin()+1, Mul->op_end()); + SmallVector Ops(drop_begin(Mul->operands())); const SCEV *NewMul = SE.getMulExpr(Ops); SmallVector MyGood; @@ -483,11 +485,10 @@ bool Formula::isCanonical(const Loop &L) const { // If ScaledReg is not a recurrent expr, or it is but its loop is not current // loop, meanwhile BaseRegs contains a recurrent expr reg related with current // loop, we want to swap the reg in BaseRegs with ScaledReg. - auto I = - find_if(make_range(BaseRegs.begin(), BaseRegs.end()), [&](const SCEV *S) { - return isa(S) && - (cast(S)->getLoop() == &L); - }); + auto I = find_if(BaseRegs, [&](const SCEV *S) { + return isa(S) && + (cast(S)->getLoop() == &L); + }); return I == BaseRegs.end(); } @@ -506,8 +507,7 @@ void Formula::canonicalize(const Loop &L) { // Keep the invariant sum in BaseRegs and one of the variant sum in ScaledReg. if (!ScaledReg) { - ScaledReg = BaseRegs.back(); - BaseRegs.pop_back(); + ScaledReg = BaseRegs.pop_back_val(); Scale = 1; } @@ -516,11 +516,10 @@ void Formula::canonicalize(const Loop &L) { // reg with ScaledReg. const SCEVAddRecExpr *SAR = dyn_cast(ScaledReg); if (!SAR || SAR->getLoop() != &L) { - auto I = find_if(make_range(BaseRegs.begin(), BaseRegs.end()), - [&](const SCEV *S) { - return isa(S) && - (cast(S)->getLoop() == &L); - }); + auto I = find_if(BaseRegs, [&](const SCEV *S) { + return isa(S) && + (cast(S)->getLoop() == &L); + }); if (I != BaseRegs.end()) std::swap(ScaledReg, *I); } @@ -753,13 +752,13 @@ static int64_t ExtractImmediate(const SCEV *&S, ScalarEvolution &SE) { return C->getValue()->getSExtValue(); } } else if (const SCEVAddExpr *Add = dyn_cast(S)) { - SmallVector NewOps(Add->op_begin(), Add->op_end()); + SmallVector NewOps(Add->operands()); int64_t Result = ExtractImmediate(NewOps.front(), SE); if (Result != 0) S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { - SmallVector NewOps(AR->op_begin(), AR->op_end()); + SmallVector NewOps(AR->operands()); int64_t Result = ExtractImmediate(NewOps.front(), SE); if (Result != 0) S = SE.getAddRecExpr(NewOps, AR->getLoop(), @@ -779,13 +778,13 @@ static GlobalValue *ExtractSymbol(const SCEV *&S, ScalarEvolution &SE) { return GV; } } else if (const SCEVAddExpr *Add = dyn_cast(S)) { - SmallVector NewOps(Add->op_begin(), Add->op_end()); + SmallVector NewOps(Add->operands()); GlobalValue *Result = ExtractSymbol(NewOps.back(), SE); if (Result) S = SE.getAddExpr(NewOps); return Result; } else if (const SCEVAddRecExpr *AR = dyn_cast(S)) { - SmallVector NewOps(AR->op_begin(), AR->op_end()); + SmallVector NewOps(AR->operands()); GlobalValue *Result = ExtractSymbol(NewOps.front(), SE); if (Result) S = SE.getAddRecExpr(NewOps, AR->getLoop(), @@ -935,6 +934,8 @@ static bool isHighCostExpansion(const SCEV *S, case scSignExtend: return isHighCostExpansion(cast(S)->getOperand(), Processed, SE); + default: + break; } if (!Processed.insert(S).second) @@ -1210,7 +1211,7 @@ static unsigned getSetupCost(const SCEV *Reg, unsigned Depth) { return 0; if (const auto *S = dyn_cast(Reg)) return getSetupCost(S->getStart(), Depth - 1); - if (auto S = dyn_cast(Reg)) + if (auto S = dyn_cast(Reg)) return getSetupCost(S->getOperand(), Depth - 1); if (auto S = dyn_cast(Reg)) return std::accumulate(S->op_begin(), S->op_end(), 0, @@ -2786,6 +2787,7 @@ static const SCEV *getExprBase(const SCEV *S) { case scAddRecExpr: return getExprBase(cast(S)->getStart()); } + llvm_unreachable("Unknown SCEV kind!"); } /// Return true if the chain increment is profitable to expand into a loop @@ -2861,7 +2863,6 @@ static bool isProfitableChain(IVChain &Chain, for (const IVInc &Inc : Chain) { if (TTI.isProfitableLSRChainElement(Inc.UserInst)) return true; - if (Inc.IncExpr->isZero()) continue; @@ -3401,7 +3402,7 @@ LSRInstance::CollectLoopInvariantFixupsAndFormulae() { if (const SCEVNAryExpr *N = dyn_cast(S)) Worklist.append(N->op_begin(), N->op_end()); - else if (const SCEVCastExpr *C = dyn_cast(S)) + else if (const SCEVIntegralCastExpr *C = dyn_cast(S)) Worklist.push_back(C->getOperand()); else if (const SCEVUDivExpr *D = dyn_cast(S)) { Worklist.push_back(D->getLHS()); @@ -3834,10 +3835,14 @@ void LSRInstance::GenerateConstantOffsetsImpl( F.BaseOffset = (uint64_t)F.BaseOffset + Imm; if (!isLegalUse(TTI, LU.MinOffset, LU.MaxOffset, LU.Kind, LU.AccessTy, F)) return; - if (IsScaledReg) + if (IsScaledReg) { F.ScaledReg = G; - else + } else { F.BaseRegs[Idx] = G; + // We may generate non canonical Formula if G is a recurrent expr reg + // related with current loop while F.ScaledReg is not. + F.canonicalize(*L); + } (void)InsertFormula(LU, LUIdx, F); } @@ -5378,10 +5383,11 @@ void LSRInstance::RewriteForPHI( // Split the critical edge. BasicBlock *NewBB = nullptr; if (!Parent->isLandingPad()) { - NewBB = SplitCriticalEdge(BB, Parent, - CriticalEdgeSplittingOptions(&DT, &LI) - .setMergeIdenticalEdges() - .setKeepOneInputPHIs()); + NewBB = + SplitCriticalEdge(BB, Parent, + CriticalEdgeSplittingOptions(&DT, &LI, MSSAU) + .setMergeIdenticalEdges() + .setKeepOneInputPHIs()); } else { SmallVector NewBBs; SplitLandingPadPredecessors(Parent, BB, "", "", NewBBs, &DT, &LI); @@ -5514,8 +5520,8 @@ void LSRInstance::ImplementSolution( // we can remove them after we are done working. SmallVector DeadInsts; - SCEVExpander Rewriter(SE, L->getHeader()->getModule()->getDataLayout(), - "lsr"); + SCEVExpander Rewriter(SE, L->getHeader()->getModule()->getDataLayout(), "lsr", + false); #ifndef NDEBUG Rewriter.setDebugType(DEBUG_TYPE); #endif @@ -5614,13 +5620,19 @@ LSRInstance::LSRInstance(Loop *L, IVUsers &IU, ScalarEvolution &SE, if (IU.empty()) return; // Skip nested loops until we can model them better with formulae. - if (!L->empty()) { + if (!L->isInnermost()) { LLVM_DEBUG(dbgs() << "LSR skipping outer loop " << *L << "\n"); return; } // Start collecting data and preparing for the solver. - CollectChains(); + // If number of registers is not the major cost, we cannot benefit from the + // current profitable chain optimization which is based on number of + // registers. + // FIXME: add profitable chain optimization for other kinds major cost, for + // example number of instructions. + if (TTI.isNumRegsMajorCostOfLSR() || StressIVChain) + CollectChains(); CollectInterestingTypesAndFactors(); CollectFixupsAndInitialFormulae(); CollectLoopInvariantFixupsAndFormulae(); @@ -5760,6 +5772,63 @@ void LoopStrengthReduce::getAnalysisUsage(AnalysisUsage &AU) const { AU.addPreserved(); } +using EqualValues = SmallVector, 4>; +using EqualValuesMap = DenseMap; + +static void DbgGatherEqualValues(Loop *L, ScalarEvolution &SE, + EqualValuesMap &DbgValueToEqualSet) { + for (auto &B : L->getBlocks()) { + for (auto &I : *B) { + auto DVI = dyn_cast(&I); + if (!DVI) + continue; + auto V = DVI->getVariableLocation(); + if (!V || !SE.isSCEVable(V->getType())) + continue; + auto DbgValueSCEV = SE.getSCEV(V); + EqualValues EqSet; + for (PHINode &Phi : L->getHeader()->phis()) { + if (V->getType() != Phi.getType()) + continue; + if (!SE.isSCEVable(Phi.getType())) + continue; + auto PhiSCEV = SE.getSCEV(&Phi); + Optional Offset = + SE.computeConstantDifference(DbgValueSCEV, PhiSCEV); + if (Offset && Offset->getMinSignedBits() <= 64) + EqSet.emplace_back(std::make_tuple( + &Phi, Offset.getValue().getSExtValue(), DVI->getExpression())); + } + DbgValueToEqualSet[DVI] = std::move(EqSet); + } + } +} + +static void DbgApplyEqualValues(EqualValuesMap &DbgValueToEqualSet) { + for (auto A : DbgValueToEqualSet) { + auto DVI = A.first; + // Only update those that are now undef. + if (!isa_and_nonnull(DVI->getVariableLocation())) + continue; + for (auto EV : A.second) { + auto V = std::get(EV); + if (!V) + continue; + auto DbgDIExpr = std::get(EV); + auto Offset = std::get(EV); + auto &Ctx = DVI->getContext(); + DVI->setOperand(0, MetadataAsValue::get(Ctx, ValueAsMetadata::get(V))); + if (Offset) { + SmallVector Ops; + DIExpression::appendOffset(Ops, Offset); + DbgDIExpr = DIExpression::prependOpcodes(DbgDIExpr, Ops, true); + } + DVI->setOperand(2, MetadataAsValue::get(Ctx, DbgDIExpr)); + break; + } + } +} + static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE, DominatorTree &DT, LoopInfo &LI, const TargetTransformInfo &TTI, @@ -5775,12 +5844,17 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE, Changed |= LSRInstance(L, IU, SE, DT, LI, TTI, AC, TLI, MSSAU.get()).getChanged(); + // Debug preservation - before we start removing anything create equivalence + // sets for the llvm.dbg.value intrinsics. + EqualValuesMap DbgValueToEqualSet; + DbgGatherEqualValues(L, SE, DbgValueToEqualSet); + // Remove any extra phis created by processing inner loops. Changed |= DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get()); if (EnablePhiElim && L->isLoopSimplifyForm()) { SmallVector DeadInsts; const DataLayout &DL = L->getHeader()->getModule()->getDataLayout(); - SCEVExpander Rewriter(SE, DL, "lsr"); + SCEVExpander Rewriter(SE, DL, "lsr", false); #ifndef NDEBUG Rewriter.setDebugType(DEBUG_TYPE); #endif @@ -5792,6 +5866,9 @@ static bool ReduceLoopStrength(Loop *L, IVUsers &IU, ScalarEvolution &SE, DeleteDeadPHIs(L->getHeader(), &TLI, MSSAU.get()); } } + + DbgApplyEqualValues(DbgValueToEqualSet); + return Changed; } diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp index 285cba6ee205..495906e1a763 100644 --- a/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnrollAndJamPass.cpp @@ -41,6 +41,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/LoopPeel.h" #include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/UnrollLoop.h" @@ -287,6 +288,13 @@ tryToUnrollAndJamLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, None, None, None, None, None); TargetTransformInfo::PeelingPreferences PP = gatherPeelingPreferences(L, SE, TTI, None, None); + + TransformationMode EnableMode = hasUnrollAndJamTransformation(L); + if (EnableMode & TM_Disable) + return LoopUnrollResult::Unmodified; + if (EnableMode & TM_ForcedByUser) + UP.UnrollAndJam = true; + if (AllowUnrollAndJam.getNumOccurrences() > 0) UP.UnrollAndJam = AllowUnrollAndJam; if (UnrollAndJamThreshold.getNumOccurrences() > 0) @@ -299,10 +307,6 @@ tryToUnrollAndJamLoop(Loop *L, DominatorTree &DT, LoopInfo *LI, << L->getHeader()->getParent()->getName() << "] Loop %" << L->getHeader()->getName() << "\n"); - TransformationMode EnableMode = hasUnrollAndJamTransformation(L); - if (EnableMode & TM_Disable) - return LoopUnrollResult::Unmodified; - // A loop with any unroll pragma (enabling/disabling/count/etc) is left for // the unroller, so long as it does not explicitly have unroll_and_jam // metadata. This means #pragma nounroll will disable unroll and jam as well diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp index 87f40bb7ba85..1b974576a3cc 100644 --- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp @@ -56,6 +56,7 @@ #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/LoopPassManager.h" #include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/LoopPeel.h" #include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/SizeOpts.h" @@ -75,13 +76,19 @@ using namespace llvm; cl::opt llvm::ForgetSCEVInLoopUnroll( "forget-scev-loop-unroll", cl::init(false), cl::Hidden, cl::desc("Forget everything in SCEV when doing LoopUnroll, instead of just" - " the current top-most loop. This is somtimes preferred to reduce" + " the current top-most loop. This is sometimes preferred to reduce" " compile time.")); static cl::opt UnrollThreshold("unroll-threshold", cl::Hidden, cl::desc("The cost threshold for loop unrolling")); +static cl::opt + UnrollOptSizeThreshold( + "unroll-optsize-threshold", cl::init(0), cl::Hidden, + cl::desc("The cost threshold for loop unrolling when optimizing for " + "size")); + static cl::opt UnrollPartialThreshold( "unroll-partial-threshold", cl::Hidden, cl::desc("The cost threshold for partial loop unrolling")); @@ -115,10 +122,6 @@ static cl::opt UnrollFullMaxCount( cl::desc( "Set the max unroll count for full unrolling, for testing purposes")); -static cl::opt UnrollPeelCount( - "unroll-peel-count", cl::Hidden, - cl::desc("Set the unroll peeling count, for testing purposes")); - static cl::opt UnrollAllowPartial("unroll-allow-partial", cl::Hidden, cl::desc("Allows loops to be partially unrolled until " @@ -149,15 +152,6 @@ static cl::opt FlatLoopTripCountThreshold( "threshold, the loop is considered as flat and will be less " "aggressively unrolled.")); -static cl::opt - UnrollAllowPeeling("unroll-allow-peeling", cl::init(true), cl::Hidden, - cl::desc("Allows loops to be peeled when the dynamic " - "trip count is known to be low.")); - -static cl::opt UnrollAllowLoopNestsPeeling( - "unroll-allow-loop-nests-peeling", cl::init(false), cl::Hidden, - cl::desc("Allows loop nests to be peeled.")); - static cl::opt UnrollUnrollRemainder( "unroll-remainder", cl::Hidden, cl::desc("Allow the loop remainder to be unrolled.")); @@ -200,9 +194,9 @@ TargetTransformInfo::UnrollingPreferences llvm::gatherUnrollingPreferences( UP.Threshold = OptLevel > 2 ? UnrollThresholdAggressive : UnrollThresholdDefault; UP.MaxPercentThresholdBoost = 400; - UP.OptSizeThreshold = 0; + UP.OptSizeThreshold = UnrollOptSizeThreshold; UP.PartialThreshold = 150; - UP.PartialOptSizeThreshold = 0; + UP.PartialOptSizeThreshold = UnrollOptSizeThreshold; UP.Count = 0; UP.DefaultUnrollRuntimeCount = 8; UP.MaxCount = std::numeric_limits::max(); @@ -224,8 +218,10 @@ TargetTransformInfo::UnrollingPreferences llvm::gatherUnrollingPreferences( // Apply size attributes bool OptForSize = L->getHeader()->getParent()->hasOptSize() || - llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI, - PGSOQueryType::IRPass); + // Let unroll hints / pragmas take precedence over PGSO. + (hasUnrollTransformation(L) != TM_ForcedByUser && + llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI, + PGSOQueryType::IRPass)); if (OptForSize) { UP.Threshold = UP.OptSizeThreshold; UP.PartialThreshold = UP.PartialOptSizeThreshold; @@ -275,39 +271,6 @@ TargetTransformInfo::UnrollingPreferences llvm::gatherUnrollingPreferences( return UP; } -TargetTransformInfo::PeelingPreferences -llvm::gatherPeelingPreferences(Loop *L, ScalarEvolution &SE, - const TargetTransformInfo &TTI, - Optional UserAllowPeeling, - Optional UserAllowProfileBasedPeeling) { - TargetTransformInfo::PeelingPreferences PP; - - // Default values - PP.PeelCount = 0; - PP.AllowPeeling = true; - PP.AllowLoopNestsPeeling = false; - PP.PeelProfiledIterations = true; - - // Get Target Specifc Values - TTI.getPeelingPreferences(L, SE, PP); - - // User Specified Values using cl::opt - if (UnrollPeelCount.getNumOccurrences() > 0) - PP.PeelCount = UnrollPeelCount; - if (UnrollAllowPeeling.getNumOccurrences() > 0) - PP.AllowPeeling = UnrollAllowPeeling; - if (UnrollAllowLoopNestsPeeling.getNumOccurrences() > 0) - PP.AllowLoopNestsPeeling = UnrollAllowLoopNestsPeeling; - - // User Specifed values provided by argument - if (UserAllowPeeling.hasValue()) - PP.AllowPeeling = *UserAllowPeeling; - if (UserAllowProfileBasedPeeling.hasValue()) - PP.PeelProfiledIterations = *UserAllowProfileBasedPeeling; - - return PP; -} - namespace { /// A struct to densely store the state of an instruction after unrolling at @@ -384,7 +347,7 @@ static Optional analyzeLoopUnrollCost( // Only analyze inner loops. We can't properly estimate cost of nested loops // and we won't visit inner loops again anyway. - if (!L->empty()) + if (!L->isInnermost()) return None; // Don't simulate loops with a big or unknown tripcount @@ -426,6 +389,10 @@ static Optional analyzeLoopUnrollCost( assert(CostWorklist.empty() && "Must start with an empty cost list"); assert(PHIUsedList.empty() && "Must start with an empty phi used list"); CostWorklist.push_back(&RootI); + TargetTransformInfo::TargetCostKind CostKind = + RootI.getFunction()->hasMinSize() ? + TargetTransformInfo::TCK_CodeSize : + TargetTransformInfo::TCK_SizeAndLatency; for (;; --Iteration) { do { Instruction *I = CostWorklist.pop_back_val(); @@ -466,7 +433,7 @@ static Optional analyzeLoopUnrollCost( // First accumulate the cost of this instruction. if (!Cost.IsFree) { - UnrolledCost += TTI.getUserCost(I, TargetTransformInfo::TCK_CodeSize); + UnrolledCost += TTI.getUserCost(I, CostKind); LLVM_DEBUG(dbgs() << "Adding cost of instruction (iteration " << Iteration << "): "); LLVM_DEBUG(I->dump()); @@ -506,6 +473,9 @@ static Optional analyzeLoopUnrollCost( LLVM_DEBUG(dbgs() << "Starting LoopUnroll profitability analysis...\n"); + TargetTransformInfo::TargetCostKind CostKind = + L->getHeader()->getParent()->hasMinSize() ? + TargetTransformInfo::TCK_CodeSize : TargetTransformInfo::TCK_SizeAndLatency; // Simulate execution of each iteration of the loop counting instructions, // which would be simplified. // Since the same load will take different values on different iterations, @@ -559,7 +529,7 @@ static Optional analyzeLoopUnrollCost( // Track this instruction's expected baseline cost when executing the // rolled loop form. - RolledDynamicCost += TTI.getUserCost(&I, TargetTransformInfo::TCK_CodeSize); + RolledDynamicCost += TTI.getUserCost(&I, CostKind); // Visit the instruction to analyze its loop cost after unrolling, // and if the visitor returns true, mark the instruction as free after @@ -881,7 +851,7 @@ bool llvm::computeUnrollCount( } // 4th priority is loop peeling. - computePeelCount(L, LoopSize, UP, PP, TripCount, SE); + computePeelCount(L, LoopSize, PP, TripCount, SE, UP.Threshold); if (PP.PeelCount) { UP.Runtime = false; UP.Count = 1; @@ -1073,7 +1043,7 @@ static LoopUnrollResult tryToUnrollLoop( return LoopUnrollResult::Unmodified; } - // When automtatic unrolling is disabled, do not unroll unless overridden for + // When automatic unrolling is disabled, do not unroll unless overridden for // this loop. if (OnlyWhenForced && !(TM & TM_Enable)) return LoopUnrollResult::Unmodified; @@ -1087,7 +1057,7 @@ static LoopUnrollResult tryToUnrollLoop( ProvidedAllowPartial, ProvidedRuntime, ProvidedUpperBound, ProvidedFullUnrollMaxCount); TargetTransformInfo::PeelingPreferences PP = gatherPeelingPreferences( - L, SE, TTI, ProvidedAllowPeeling, ProvidedAllowProfileBasedPeeling); + L, SE, TTI, ProvidedAllowPeeling, ProvidedAllowProfileBasedPeeling, true); // Exit early if unrolling is disabled. For OptForSize, we pick the loop size // as threshold later on. @@ -1135,7 +1105,7 @@ static LoopUnrollResult tryToUnrollLoop( // If the loop contains a convergent operation, the prelude we'd add // to do the first few instructions before we hit the unrolled loop // is unsafe -- it adds a control-flow dependency to the convergent - // operation. Therefore restrict remainder loop (try unrollig without). + // operation. Therefore restrict remainder loop (try unrolling without). // // TODO: This is quite conservative. In practice, convergent_op() // is likely to be called unconditionally in the loop. In this @@ -1331,7 +1301,7 @@ Pass *llvm::createLoopUnrollPass(int OptLevel, bool OnlyWhenForced, Pass *llvm::createSimpleLoopUnrollPass(int OptLevel, bool OnlyWhenForced, bool ForgetAllSCEV) { return createLoopUnrollPass(OptLevel, OnlyWhenForced, ForgetAllSCEV, -1, -1, - 0, 0, 0, 0); + 0, 0, 0, 1); } PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM, @@ -1359,7 +1329,7 @@ PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM, OnlyWhenForced, ForgetSCEV, /*Count*/ None, /*Threshold*/ None, /*AllowPartial*/ false, /*Runtime*/ false, /*UpperBound*/ false, - /*AllowPeeling*/ false, + /*AllowPeeling*/ true, /*AllowProfileBasedPeeling*/ false, /*FullUnrollMaxCount*/ None) != LoopUnrollResult::Unmodified; @@ -1401,7 +1371,7 @@ PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM, } // Otherwise erase the loop from the list if it was in the old loops. - return OldLoops.count(SibLoop) != 0; + return OldLoops.contains(SibLoop); }); Updater.addSiblingLoops(SibLoops); diff --git a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp index 645a89bbd0ff..18717394d384 100644 --- a/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/LoopUnswitch.cpp @@ -32,6 +32,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/InstructionSimplify.h" +#include "llvm/Analysis/LazyBlockFrequencyInfo.h" #include "llvm/Analysis/LegacyDivergenceAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopIterator.h" @@ -98,6 +99,12 @@ static cl::opt Threshold("loop-unswitch-threshold", cl::desc("Max loop size to unswitch"), cl::init(100), cl::Hidden); +static cl::opt + MSSAThreshold("loop-unswitch-memoryssa-threshold", + cl::desc("Max number of memory uses to explore during " + "partial unswitching analysis"), + cl::init(100), cl::Hidden); + namespace { class LUAnalysisCache { @@ -184,6 +191,7 @@ namespace { Loop *CurrentLoop = nullptr; DominatorTree *DT = nullptr; MemorySSA *MSSA = nullptr; + AAResults *AA = nullptr; std::unique_ptr MSSAU; BasicBlock *LoopHeader = nullptr; BasicBlock *LoopPreheader = nullptr; @@ -217,6 +225,10 @@ namespace { /// loop preheaders be inserted into the CFG. /// void getAnalysisUsage(AnalysisUsage &AU) const override { + // Lazy BFI and BPI are marked as preserved here so Loop Unswitching + // can remain part of the same loop pass as LICM + AU.addPreserved(); + AU.addPreserved(); AU.addRequired(); AU.addRequired(); if (EnableMSSALoopDependency) { @@ -244,19 +256,22 @@ namespace { bool tryTrivialLoopUnswitch(bool &Changed); bool unswitchIfProfitable(Value *LoopCond, Constant *Val, - Instruction *TI = nullptr); + Instruction *TI = nullptr, + ArrayRef ToDuplicate = {}); void unswitchTrivialCondition(Loop *L, Value *Cond, Constant *Val, BasicBlock *ExitBlock, Instruction *TI); void unswitchNontrivialCondition(Value *LIC, Constant *OnVal, Loop *L, - Instruction *TI); + Instruction *TI, + ArrayRef ToDuplicate = {}); void rewriteLoopBodyWithConditionConstant(Loop *L, Value *LIC, Constant *Val, bool IsEqual); - void emitPreheaderBranchOnCondition(Value *LIC, Constant *Val, - BasicBlock *TrueDest, - BasicBlock *FalseDest, - BranchInst *OldBranch, Instruction *TI); + void + emitPreheaderBranchOnCondition(Value *LIC, Constant *Val, + BasicBlock *TrueDest, BasicBlock *FalseDest, + BranchInst *OldBranch, Instruction *TI, + ArrayRef ToDuplicate = {}); void simplifyCode(std::vector &Worklist, Loop *L); @@ -523,6 +538,7 @@ bool LoopUnswitch::runOnLoop(Loop *L, LPPassManager &LPMRef) { LI = &getAnalysis().getLoopInfo(); LPM = &LPMRef; DT = &getAnalysis().getDomTree(); + AA = &getAnalysis().getAAResults(); if (EnableMSSALoopDependency) { MSSA = &getAnalysis().getMSSA(); MSSAU = std::make_unique(MSSA); @@ -624,6 +640,145 @@ static bool equalityPropUnSafe(Value &LoopCond) { return false; } +/// Check if the loop header has a conditional branch that is not +/// loop-invariant, because it involves load instructions. If all paths from +/// either the true or false successor to the header or loop exists do not +/// modify the memory feeding the condition, perform 'partial unswitching'. That +/// is, duplicate the instructions feeding the condition in the pre-header. Then +/// unswitch on the duplicated condition. The condition is now known in the +/// unswitched version for the 'invariant' path through the original loop. +/// +/// If the branch condition of the header is partially invariant, return a pair +/// containing the instructions to duplicate and a boolean Constant to update +/// the condition in the loops created for the true or false successors. +static std::pair, Constant *> +hasPartialIVCondition(Loop *L, MemorySSA &MSSA, AAResults *AA) { + SmallVector ToDuplicate; + + auto *TI = dyn_cast(L->getHeader()->getTerminator()); + if (!TI || !TI->isConditional()) + return {}; + + auto *CondI = dyn_cast(TI->getCondition()); + // The case with the condition outside the loop should already be handled + // earlier. + if (!CondI || !L->contains(CondI)) + return {}; + + ToDuplicate.push_back(CondI); + + SmallVector WorkList; + WorkList.append(CondI->op_begin(), CondI->op_end()); + + SmallVector AccessesToCheck; + SmallVector AccessedLocs; + while (!WorkList.empty()) { + Instruction *I = dyn_cast(WorkList.pop_back_val()); + if (!I || !L->contains(I)) + continue; + + // TODO: support additional instructions. + if (!isa(I) && !isa(I)) + return {}; + + // Do not duplicate volatile and atomic loads. + if (auto *LI = dyn_cast(I)) + if (LI->isVolatile() || LI->isAtomic()) + return {}; + + ToDuplicate.push_back(I); + if (MemoryAccess *MA = MSSA.getMemoryAccess(I)) { + if (auto *MemUse = dyn_cast_or_null(MA)) { + // Queue the defining access to check for alias checks. + AccessesToCheck.push_back(MemUse->getDefiningAccess()); + AccessedLocs.push_back(MemoryLocation::get(I)); + } else { + // MemoryDefs may clobber the location or may be atomic memory + // operations. Bail out. + return {}; + } + } + WorkList.append(I->op_begin(), I->op_end()); + } + + if (ToDuplicate.size() <= 1) + return {}; + + auto HasNoClobbersOnPath = + [L, AA, &AccessedLocs](BasicBlock *Succ, BasicBlock *Header, + SmallVector AccessesToCheck) { + // First, collect all blocks in the loop that are on a patch from Succ + // to the header. + SmallVector WorkList; + WorkList.push_back(Succ); + WorkList.push_back(Header); + SmallPtrSet Seen; + Seen.insert(Header); + while (!WorkList.empty()) { + BasicBlock *Current = WorkList.pop_back_val(); + if (!L->contains(Current)) + continue; + const auto &SeenIns = Seen.insert(Current); + if (!SeenIns.second) + continue; + + WorkList.append(succ_begin(Current), succ_end(Current)); + } + + // Require at least 2 blocks on a path through the loop. This skips + // paths that directly exit the loop. + if (Seen.size() < 2) + return false; + + // Next, check if there are any MemoryDefs that are on the path through + // the loop (in the Seen set) and they may-alias any of the locations in + // AccessedLocs. If that is the case, they may modify the condition and + // partial unswitching is not possible. + SmallPtrSet SeenAccesses; + while (!AccessesToCheck.empty()) { + MemoryAccess *Current = AccessesToCheck.pop_back_val(); + auto SeenI = SeenAccesses.insert(Current); + if (!SeenI.second || !Seen.contains(Current->getBlock())) + continue; + + // Bail out if exceeded the threshold. + if (SeenAccesses.size() >= MSSAThreshold) + return false; + + // MemoryUse are read-only accesses. + if (isa(Current)) + continue; + + // For a MemoryDef, check if is aliases any of the location feeding + // the original condition. + if (auto *CurrentDef = dyn_cast(Current)) { + if (any_of(AccessedLocs, [AA, CurrentDef](MemoryLocation &Loc) { + return isModSet( + AA->getModRefInfo(CurrentDef->getMemoryInst(), Loc)); + })) + return false; + } + + for (Use &U : Current->uses()) + AccessesToCheck.push_back(cast(U.getUser())); + } + + return true; + }; + + // If we branch to the same successor, partial unswitching will not be + // beneficial. + if (TI->getSuccessor(0) == TI->getSuccessor(1)) + return {}; + + if (HasNoClobbersOnPath(TI->getSuccessor(0), L->getHeader(), AccessesToCheck)) + return {ToDuplicate, ConstantInt::getTrue(TI->getContext())}; + if (HasNoClobbersOnPath(TI->getSuccessor(1), L->getHeader(), AccessesToCheck)) + return {ToDuplicate, ConstantInt::getFalse(TI->getContext())}; + + return {}; +} + /// Do actual work and unswitch loop if possible and profitable. bool LoopUnswitch::processCurrentLoop() { bool Changed = false; @@ -661,7 +816,7 @@ bool LoopUnswitch::processCurrentLoop() { // FIXME: Use Function::hasOptSize(). if (OptimizeForSize || LoopHeader->getParent()->hasFnAttribute(Attribute::OptimizeForSize)) - return false; + return Changed; // Run through the instructions in the loop, keeping track of three things: // @@ -685,10 +840,10 @@ bool LoopUnswitch::processCurrentLoop() { if (!CB) continue; if (CB->isConvergent()) - return false; + return Changed; if (auto *II = dyn_cast(&I)) if (!II->getUnwindDest()->canSplitPredecessors()) - return false; + return Changed; if (auto *II = dyn_cast(&I)) if (II->getIntrinsicID() == Intrinsic::experimental_guard) Guards.push_back(II); @@ -823,6 +978,28 @@ bool LoopUnswitch::processCurrentLoop() { } } } + + // Check if there is a header condition that is invariant along the patch from + // either the true or false successors to the header. This allows unswitching + // conditions depending on memory accesses, if there's a path not clobbering + // the memory locations. Check if this transform has been disabled using + // metadata, to avoid unswitching the same loop multiple times. + if (MSSA && + !findOptionMDForLoop(CurrentLoop, "llvm.loop.unswitch.partial.disable")) { + auto ToDuplicate = hasPartialIVCondition(CurrentLoop, *MSSA, AA); + if (!ToDuplicate.first.empty()) { + LLVM_DEBUG(dbgs() << "loop-unswitch: Found partially invariant condition " + << *ToDuplicate.first[0] << "\n"); + ++NumBranches; + unswitchIfProfitable(ToDuplicate.first[0], ToDuplicate.second, + CurrentLoop->getHeader()->getTerminator(), + ToDuplicate.first); + + RedoLoop = false; + return true; + } + } + return Changed; } @@ -880,7 +1057,8 @@ static BasicBlock *isTrivialLoopExitBlock(Loop *L, BasicBlock *BB) { /// simplify the loop. If we decide that this is profitable, /// unswitch the loop, reprocess the pieces, then return true. bool LoopUnswitch::unswitchIfProfitable(Value *LoopCond, Constant *Val, - Instruction *TI) { + Instruction *TI, + ArrayRef ToDuplicate) { // Check to see if it would be profitable to unswitch current loop. if (!BranchesInfo.costAllowsUnswitching()) { LLVM_DEBUG(dbgs() << "NOT unswitching loop %" @@ -900,31 +1078,65 @@ bool LoopUnswitch::unswitchIfProfitable(Value *LoopCond, Constant *Val, return false; } - unswitchNontrivialCondition(LoopCond, Val, CurrentLoop, TI); + unswitchNontrivialCondition(LoopCond, Val, CurrentLoop, TI, ToDuplicate); return true; } /// Emit a conditional branch on two values if LIC == Val, branch to TrueDst, /// otherwise branch to FalseDest. Insert the code immediately before OldBranch /// and remove (but not erase!) it from the function. -void LoopUnswitch::emitPreheaderBranchOnCondition(Value *LIC, Constant *Val, - BasicBlock *TrueDest, - BasicBlock *FalseDest, - BranchInst *OldBranch, - Instruction *TI) { +void LoopUnswitch::emitPreheaderBranchOnCondition( + Value *LIC, Constant *Val, BasicBlock *TrueDest, BasicBlock *FalseDest, + BranchInst *OldBranch, Instruction *TI, + ArrayRef ToDuplicate) { assert(OldBranch->isUnconditional() && "Preheader is not split correctly"); assert(TrueDest != FalseDest && "Branch targets should be different"); + // Insert a conditional branch on LIC to the two preheaders. The original // code is the true version and the new code is the false version. Value *BranchVal = LIC; bool Swapped = false; - if (!isa(Val) || - Val->getType() != Type::getInt1Ty(LIC->getContext())) - BranchVal = new ICmpInst(OldBranch, ICmpInst::ICMP_EQ, LIC, Val); - else if (Val != ConstantInt::getTrue(Val->getContext())) { - // We want to enter the new loop when the condition is true. - std::swap(TrueDest, FalseDest); - Swapped = true; + + if (!ToDuplicate.empty()) { + ValueToValueMapTy Old2New; + for (Instruction *I : reverse(ToDuplicate)) { + auto *New = I->clone(); + New->insertBefore(OldBranch); + RemapInstruction(New, Old2New, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + Old2New[I] = New; + + if (MSSAU) { + MemorySSA *MSSA = MSSAU->getMemorySSA(); + auto *MemA = dyn_cast_or_null(MSSA->getMemoryAccess(I)); + if (!MemA) + continue; + + Loop *L = LI->getLoopFor(I->getParent()); + auto *DefiningAccess = MemA->getDefiningAccess(); + // If the defining access is a MemoryPhi in the header, get the incoming + // value for the pre-header as defining access. + if (DefiningAccess->getBlock() == I->getParent()) { + if (auto *MemPhi = dyn_cast(DefiningAccess)) { + DefiningAccess = + MemPhi->getIncomingValueForBlock(L->getLoopPreheader()); + } + } + MSSAU->createMemoryAccessInBB(New, DefiningAccess, New->getParent(), + MemorySSA::BeforeTerminator); + } + } + BranchVal = Old2New[ToDuplicate[0]]; + } else { + + if (!isa(Val) || + Val->getType() != Type::getInt1Ty(LIC->getContext())) + BranchVal = new ICmpInst(OldBranch, ICmpInst::ICMP_EQ, LIC, Val); + else if (Val != ConstantInt::getTrue(Val->getContext())) { + // We want to enter the new loop when the condition is true. + std::swap(TrueDest, FalseDest); + Swapped = true; + } } // Old branch will be removed, so save its parent and successor to update the @@ -955,10 +1167,11 @@ void LoopUnswitch::emitPreheaderBranchOnCondition(Value *LIC, Constant *Val, if (OldBranchSucc != TrueDest && OldBranchSucc != FalseDest) { Updates.push_back({DominatorTree::Delete, OldBranchParent, OldBranchSucc}); } - DT->applyUpdates(Updates); if (MSSAU) - MSSAU->applyUpdates(Updates, *DT); + MSSAU->applyUpdates(Updates, *DT, /*UpdateDT=*/true); + else + DT->applyUpdates(Updates); } // If either edge is critical, split it. This helps preserve LoopSimplify @@ -1207,8 +1420,9 @@ void LoopUnswitch::splitExitEdges( /// We determined that the loop is profitable to unswitch when LIC equal Val. /// Split it into loop versions and test the condition outside of either loop. /// Return the loops created as Out1/Out2. -void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, - Loop *L, Instruction *TI) { +void LoopUnswitch::unswitchNontrivialCondition( + Value *LIC, Constant *Val, Loop *L, Instruction *TI, + ArrayRef ToDuplicate) { Function *F = LoopHeader->getParent(); LLVM_DEBUG(dbgs() << "loop-unswitch: Unswitching loop %" << LoopHeader->getName() << " [" << L->getBlocks().size() @@ -1233,7 +1447,7 @@ void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, LoopBlocks.push_back(NewPreheader); // We want the loop to come after the preheader, but before the exit blocks. - LoopBlocks.insert(LoopBlocks.end(), L->block_begin(), L->block_end()); + llvm::append_range(LoopBlocks, L->blocks()); SmallVector ExitBlocks; L->getUniqueExitBlocks(ExitBlocks); @@ -1247,7 +1461,7 @@ void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, L->getUniqueExitBlocks(ExitBlocks); // Add exit blocks to the loop blocks. - LoopBlocks.insert(LoopBlocks.end(), ExitBlocks.begin(), ExitBlocks.end()); + llvm::append_range(LoopBlocks, ExitBlocks); // Next step, clone all of the basic blocks that make up the loop (including // the loop preheader and exit blocks), keeping track of the mapping between @@ -1340,7 +1554,7 @@ void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, // Emit the new branch that selects between the two versions of this loop. emitPreheaderBranchOnCondition(LIC, Val, NewBlocks[0], LoopBlocks[0], OldBR, - TI); + TI, ToDuplicate); if (MSSAU) { // Update MemoryPhis in Exit blocks. MSSAU->updateExitBlocksForClonedLoop(ExitBlocks, VMap, *DT); @@ -1362,17 +1576,38 @@ void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, // iteration. WeakTrackingVH LICHandle(LIC); - // Now we rewrite the original code to know that the condition is true and the - // new code to know that the condition is false. - rewriteLoopBodyWithConditionConstant(L, LIC, Val, /*IsEqual=*/false); - - // It's possible that simplifying one loop could cause the other to be - // changed to another value or a constant. If its a constant, don't simplify - // it. - if (!LoopProcessWorklist.empty() && LoopProcessWorklist.back() == NewLoop && - LICHandle && !isa(LICHandle)) - rewriteLoopBodyWithConditionConstant(NewLoop, LICHandle, Val, - /*IsEqual=*/true); + if (ToDuplicate.empty()) { + // Now we rewrite the original code to know that the condition is true and + // the new code to know that the condition is false. + rewriteLoopBodyWithConditionConstant(L, LIC, Val, /*IsEqual=*/false); + + // It's possible that simplifying one loop could cause the other to be + // changed to another value or a constant. If its a constant, don't + // simplify it. + if (!LoopProcessWorklist.empty() && LoopProcessWorklist.back() == NewLoop && + LICHandle && !isa(LICHandle)) + rewriteLoopBodyWithConditionConstant(NewLoop, LICHandle, Val, + /*IsEqual=*/true); + } else { + // Partial unswitching. Update the condition in the right loop with the + // constant. + auto *CC = cast(Val); + if (CC->isOneValue()) { + rewriteLoopBodyWithConditionConstant(NewLoop, VMap[LIC], Val, + /*IsEqual=*/true); + } else + rewriteLoopBodyWithConditionConstant(L, LIC, Val, /*IsEqual=*/true); + + // Mark the new loop as partially unswitched, to avoid unswitching on the + // same condition again. + auto &Context = NewLoop->getHeader()->getContext(); + MDNode *DisableUnswitchMD = MDNode::get( + Context, MDString::get(Context, "llvm.loop.unswitch.partial.disable")); + MDNode *NewLoopID = makePostTransformationMetadata( + Context, L->getLoopID(), {"llvm.loop.unswitch.partial"}, + {DisableUnswitchMD}); + NewLoop->setLoopID(NewLoopID); + } if (MSSA && VerifyMemorySSA) MSSA->verifyMemorySSA(); @@ -1381,9 +1616,7 @@ void LoopUnswitch::unswitchNontrivialCondition(Value *LIC, Constant *Val, /// Remove all instances of I from the worklist vector specified. static void removeFromWorklist(Instruction *I, std::vector &Worklist) { - - Worklist.erase(std::remove(Worklist.begin(), Worklist.end(), I), - Worklist.end()); + llvm::erase_value(Worklist, I); } /// When we find that I really equals V, remove I from the diff --git a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp index 06b684ef1e70..2ff1e8480749 100644 --- a/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp +++ b/llvm/lib/Transforms/Scalar/LoopVersioningLICM.cpp @@ -59,6 +59,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/LoopVersioningLICM.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -114,17 +115,18 @@ static cl::opt LVLoopDepthThreshold( namespace { -struct LoopVersioningLICM : public LoopPass { +struct LoopVersioningLICMLegacyPass : public LoopPass { static char ID; - LoopVersioningLICM() - : LoopPass(ID), LoopDepthThreshold(LVLoopDepthThreshold), - InvariantThreshold(LVInvarThreshold) { - initializeLoopVersioningLICMPass(*PassRegistry::getPassRegistry()); + LoopVersioningLICMLegacyPass() : LoopPass(ID) { + initializeLoopVersioningLICMLegacyPassPass( + *PassRegistry::getPassRegistry()); } bool runOnLoop(Loop *L, LPPassManager &LPM) override; + StringRef getPassName() const override { return "Loop Versioning for LICM"; } + void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); AU.addRequired(); @@ -138,13 +140,25 @@ struct LoopVersioningLICM : public LoopPass { AU.addPreserved(); AU.addRequired(); } +}; - StringRef getPassName() const override { return "Loop Versioning for LICM"; } +struct LoopVersioningLICM { + // We don't explicitly pass in LoopAccessInfo to the constructor since the + // loop versioning might return early due to instructions that are not safe + // for versioning. By passing the proxy instead the construction of + // LoopAccessInfo will take place only when it's necessary. + LoopVersioningLICM(AliasAnalysis *AA, ScalarEvolution *SE, + OptimizationRemarkEmitter *ORE, + function_ref GetLAI) + : AA(AA), SE(SE), GetLAI(GetLAI), + LoopDepthThreshold(LVLoopDepthThreshold), + InvariantThreshold(LVInvarThreshold), ORE(ORE) {} + + bool runOnLoop(Loop *L, LoopInfo *LI, DominatorTree *DT); void reset() { AA = nullptr; SE = nullptr; - LAA = nullptr; CurLoop = nullptr; LoadAndStoreCounter = 0; InvariantCounter = 0; @@ -169,12 +183,12 @@ private: // Current ScalarEvolution ScalarEvolution *SE = nullptr; - // Current LoopAccessAnalysis - LoopAccessLegacyAnalysis *LAA = nullptr; - // Current Loop's LoopAccessInfo const LoopAccessInfo *LAI = nullptr; + // Proxy for retrieving LoopAccessInfo. + function_ref GetLAI; + // The current loop we are working on. Loop *CurLoop = nullptr; @@ -253,7 +267,7 @@ bool LoopVersioningLICM::legalLoopStructure() { // We need to be able to compute the loop trip count in order // to generate the bound checks. const SCEV *ExitCount = SE->getBackedgeTakenCount(CurLoop); - if (ExitCount == SE->getCouldNotCompute()) { + if (isa(ExitCount)) { LLVM_DEBUG(dbgs() << " loop does not has trip count\n"); return false; } @@ -400,8 +414,8 @@ bool LoopVersioningLICM::legalLoopInstructions() { return false; } } - // Get LoopAccessInfo from current loop. - LAI = &LAA->getInfo(CurLoop); + // Get LoopAccessInfo from current loop via the proxy. + LAI = &GetLAI(CurLoop); // Check LoopAccessInfo for need of runtime check. if (LAI->getRuntimePointerChecking()->getChecks().empty()) { LLVM_DEBUG(dbgs() << " LAA: Runtime check not found !!\n"); @@ -539,8 +553,8 @@ void LoopVersioningLICM::setNoAliasToLoop(Loop *VerLoop) { MDBuilder MDB(I->getContext()); MDNode *NewDomain = MDB.createAnonymousAliasScopeDomain("LVDomain"); StringRef Name = "LVAliasScope"; - SmallVector Scopes, NoAliases; MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name); + SmallVector Scopes{NewScope}, NoAliases{NewScope}; // Iterate over each instruction of loop. // set no-alias for all load & store instructions. for (auto *Block : CurLoop->getBlocks()) { @@ -548,8 +562,6 @@ void LoopVersioningLICM::setNoAliasToLoop(Loop *VerLoop) { // Only interested in instruction that may modify or read memory. if (!Inst.mayReadFromMemory() && !Inst.mayWriteToMemory()) continue; - Scopes.push_back(NewScope); - NoAliases.push_back(NewScope); // Set no-alias for current instruction. Inst.setMetadata( LLVMContext::MD_noalias, @@ -564,30 +576,38 @@ void LoopVersioningLICM::setNoAliasToLoop(Loop *VerLoop) { } } -bool LoopVersioningLICM::runOnLoop(Loop *L, LPPassManager &LPM) { +bool LoopVersioningLICMLegacyPass::runOnLoop(Loop *L, LPPassManager &LPM) { + if (skipLoop(L)) + return false; + + AliasAnalysis *AA = &getAnalysis().getAAResults(); + ScalarEvolution *SE = &getAnalysis().getSE(); + OptimizationRemarkEmitter *ORE = + &getAnalysis().getORE(); + LoopInfo *LI = &getAnalysis().getLoopInfo(); + DominatorTree *DT = &getAnalysis().getDomTree(); + + auto GetLAI = [&](Loop *L) -> const LoopAccessInfo & { + return getAnalysis().getInfo(L); + }; + + return LoopVersioningLICM(AA, SE, ORE, GetLAI).runOnLoop(L, LI, DT); +} + +bool LoopVersioningLICM::runOnLoop(Loop *L, LoopInfo *LI, DominatorTree *DT) { // This will automatically release all resources hold by the current // LoopVersioningLICM object. AutoResetter Resetter(*this); - if (skipLoop(L)) - return false; - // Do not do the transformation if disabled by metadata. if (hasLICMVersioningTransformation(L) & TM_Disable) return false; - // Get Analysis information. - AA = &getAnalysis().getAAResults(); - SE = &getAnalysis().getSE(); - LAA = &getAnalysis(); - ORE = &getAnalysis().getORE(); - LAI = nullptr; // Set Current Loop CurLoop = L; CurAST.reset(new AliasSetTracker(*AA)); // Loop over the body of this loop, construct AST. - LoopInfo *LI = &getAnalysis().getLoopInfo(); for (auto *Block : L->getBlocks()) { if (LI->getLoopFor(Block) == L) // Ignore blocks in subloop. CurAST->add(*Block); // Incorporate the specified basic block @@ -602,8 +622,8 @@ bool LoopVersioningLICM::runOnLoop(Loop *L, LPPassManager &LPM) { // Do loop versioning. // Create memcheck for memory accessed inside loop. // Clone original loop, and set blocks properly. - DominatorTree *DT = &getAnalysis().getDomTree(); - LoopVersioning LVer(*LAI, CurLoop, LI, DT, SE, true); + LoopVersioning LVer(*LAI, LAI->getRuntimePointerChecking()->getChecks(), + CurLoop, LI, DT, SE); LVer.versionLoop(); // Set Loop Versioning metaData for original loop. addStringMetadataToLoop(LVer.getNonVersionedLoop(), LICMVersioningMetaData); @@ -621,9 +641,9 @@ bool LoopVersioningLICM::runOnLoop(Loop *L, LPPassManager &LPM) { return Changed; } -char LoopVersioningLICM::ID = 0; +char LoopVersioningLICMLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(LoopVersioningLICM, "loop-versioning-licm", +INITIALIZE_PASS_BEGIN(LoopVersioningLICMLegacyPass, "loop-versioning-licm", "Loop Versioning For LICM", false, false) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) @@ -634,7 +654,31 @@ INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopSimplify) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) INITIALIZE_PASS_DEPENDENCY(OptimizationRemarkEmitterWrapperPass) -INITIALIZE_PASS_END(LoopVersioningLICM, "loop-versioning-licm", +INITIALIZE_PASS_END(LoopVersioningLICMLegacyPass, "loop-versioning-licm", "Loop Versioning For LICM", false, false) -Pass *llvm::createLoopVersioningLICMPass() { return new LoopVersioningLICM(); } +Pass *llvm::createLoopVersioningLICMPass() { + return new LoopVersioningLICMLegacyPass(); +} + +namespace llvm { + +PreservedAnalyses LoopVersioningLICMPass::run(Loop &L, LoopAnalysisManager &AM, + LoopStandardAnalysisResults &LAR, + LPMUpdater &U) { + AliasAnalysis *AA = &LAR.AA; + ScalarEvolution *SE = &LAR.SE; + DominatorTree *DT = &LAR.DT; + LoopInfo *LI = &LAR.LI; + const Function *F = L.getHeader()->getParent(); + OptimizationRemarkEmitter ORE(F); + + auto GetLAI = [&](Loop *L) -> const LoopAccessInfo & { + return AM.getResult(*L, LAR); + }; + + if (!LoopVersioningLICM(AA, SE, &ORE, GetLAI).runOnLoop(&L, LI, DT)) + return PreservedAnalyses::all(); + return getLoopPassPreservedAnalyses(); +} +} // namespace llvm diff --git a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp index fddf28c281fc..bfe8db83b027 100644 --- a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp +++ b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp @@ -78,7 +78,7 @@ static bool replaceConditionalBranchesOnConstant(Instruction *II, Other->removePredecessor(Source); BI->eraseFromParent(); BranchInst::Create(Target, Source); - if (pred_begin(Other) == pred_end(Other)) + if (pred_empty(Other)) HasDeadBlocks = true; } } diff --git a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp index 0fe7dd9cfb39..da13075dfee2 100644 --- a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp +++ b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp @@ -24,10 +24,8 @@ #include "llvm/IR/Metadata.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" -#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/MisExpect.h" using namespace llvm; @@ -48,10 +46,10 @@ STATISTIC(ExpectIntrinsicsHandled, // 'select' instructions. It may be worthwhile to hoist these values to some // shared space, so they can be used directly by other passes. -static cl::opt LikelyBranchWeight( +cl::opt llvm::LikelyBranchWeight( "likely-branch-weight", cl::Hidden, cl::init(2000), cl::desc("Weight of the branch likely to be taken (default = 2000)")); -static cl::opt UnlikelyBranchWeight( +cl::opt llvm::UnlikelyBranchWeight( "unlikely-branch-weight", cl::Hidden, cl::init(1), cl::desc("Weight of the branch unlikely to be taken (default = 1)")); @@ -102,13 +100,7 @@ static bool handleSwitchExpect(SwitchInst &SI) { uint64_t Index = (Case == *SI.case_default()) ? 0 : Case.getCaseIndex() + 1; Weights[Index] = LikelyBranchWeightVal; - SI.setMetadata(LLVMContext::MD_misexpect, - MDBuilder(CI->getContext()) - .createMisExpect(Index, LikelyBranchWeightVal, - UnlikelyBranchWeightVal)); - SI.setCondition(ArgValue); - misexpect::checkFrontendInstrumentation(SI); SI.setMetadata(LLVMContext::MD_prof, MDBuilder(CI->getContext()).createBranchWeights(Weights)); @@ -317,7 +309,6 @@ template static bool handleBrSelExpect(BrSelInst &BSI) { MDBuilder MDB(CI->getContext()); MDNode *Node; - MDNode *ExpNode; uint32_t LikelyBranchWeightVal, UnlikelyBranchWeightVal; std::tie(LikelyBranchWeightVal, UnlikelyBranchWeightVal) = @@ -327,24 +318,16 @@ template static bool handleBrSelExpect(BrSelInst &BSI) { (Predicate == CmpInst::ICMP_EQ)) { Node = MDB.createBranchWeights(LikelyBranchWeightVal, UnlikelyBranchWeightVal); - ExpNode = - MDB.createMisExpect(0, LikelyBranchWeightVal, UnlikelyBranchWeightVal); } else { Node = MDB.createBranchWeights(UnlikelyBranchWeightVal, LikelyBranchWeightVal); - ExpNode = - MDB.createMisExpect(1, LikelyBranchWeightVal, UnlikelyBranchWeightVal); } - BSI.setMetadata(LLVMContext::MD_misexpect, ExpNode); - if (CmpI) CmpI->setOperand(0, ArgValue); else BSI.setCondition(ArgValue); - misexpect::checkFrontendInstrumentation(BSI); - BSI.setMetadata(LLVMContext::MD_prof, Node); return true; diff --git a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp index 90314b17b5e2..8e251ca940a3 100644 --- a/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp +++ b/llvm/lib/Transforms/Scalar/LowerMatrixIntrinsics.cpp @@ -42,6 +42,8 @@ #include "llvm/Support/Debug.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/LoopUtils.h" +#include "llvm/Transforms/Utils/MatrixUtils.h" using namespace llvm; using namespace PatternMatch; @@ -61,6 +63,9 @@ static cl::opt TileSize( "fuse-matrix-tile-size", cl::init(4), cl::Hidden, cl::desc( "Tile size for matrix instruction fusion using square-shaped tiles.")); +static cl::opt TileUseLoops("fuse-matrix-use-loops", cl::init(false), + cl::Hidden, + cl::desc("Generate loop nest for tiling.")); static cl::opt ForceFusion( "force-fuse-matrix", cl::init(false), cl::Hidden, cl::desc("Force matrix instruction fusion even if not profitable.")); @@ -182,10 +187,10 @@ class LowerMatrixIntrinsics { Function &Func; const DataLayout &DL; const TargetTransformInfo &TTI; - AliasAnalysis &AA; - DominatorTree &DT; - LoopInfo &LI; - OptimizationRemarkEmitter &ORE; + AliasAnalysis *AA; + DominatorTree *DT; + LoopInfo *LI; + OptimizationRemarkEmitter *ORE; /// Contains estimates of the number of operations (loads, stores, compute) required to lower a matrix operation. struct OpInfoTy { @@ -241,7 +246,7 @@ class LowerMatrixIntrinsics { void setVector(unsigned i, Value *V) { Vectors[i] = V; } - Type *getElementType() { return getVectorTy()->getElementType(); } + Type *getElementType() const { return getVectorTy()->getElementType(); } unsigned getNumVectors() const { if (isColumnMajor()) @@ -271,7 +276,7 @@ class LowerMatrixIntrinsics { return getVectorTy(); } - VectorType *getVectorTy() { + VectorType *getVectorTy() const { return cast(Vectors[0]->getType()); } @@ -329,9 +334,8 @@ class LowerMatrixIntrinsics { Value *extractVector(unsigned I, unsigned J, unsigned NumElts, IRBuilder<> &Builder) const { Value *Vec = isColumnMajor() ? getColumn(J) : getRow(I); - Value *Undef = UndefValue::get(Vec->getType()); return Builder.CreateShuffleVector( - Vec, Undef, createSequentialMask(isColumnMajor() ? I : J, NumElts, 0), + Vec, createSequentialMask(isColumnMajor() ? I : J, NumElts, 0), "block"); } }; @@ -393,8 +397,8 @@ class LowerMatrixIntrinsics { public: LowerMatrixIntrinsics(Function &F, TargetTransformInfo &TTI, - AliasAnalysis &AA, DominatorTree &DT, LoopInfo &LI, - OptimizationRemarkEmitter &ORE) + AliasAnalysis *AA, DominatorTree *DT, LoopInfo *LI, + OptimizationRemarkEmitter *ORE) : Func(F), DL(F.getParent()->getDataLayout()), TTI(TTI), AA(AA), DT(DT), LI(LI), ORE(ORE) {} @@ -442,12 +446,11 @@ public: // Otherwise split MatrixVal. SmallVector SplitVecs; - Value *Undef = UndefValue::get(VType); for (unsigned MaskStart = 0; MaskStart < cast(VType)->getNumElements(); MaskStart += SI.getStride()) { Value *V = Builder.CreateShuffleVector( - MatrixVal, Undef, createSequentialMask(MaskStart, SI.getStride(), 0), + MatrixVal, createSequentialMask(MaskStart, SI.getStride(), 0), "split"); SplitVecs.push_back(V); } @@ -485,6 +488,7 @@ public: case Instruction::FAdd: case Instruction::FSub: case Instruction::FMul: // Scalar multiply. + case Instruction::FNeg: case Instruction::Add: case Instruction::Mul: case Instruction::Sub: @@ -527,8 +531,7 @@ public: // list. LLVM_DEBUG(dbgs() << "Forward-propagate shapes:\n"); while (!WorkList.empty()) { - Instruction *Inst = WorkList.back(); - WorkList.pop_back(); + Instruction *Inst = WorkList.pop_back_val(); // New entry, set the value and insert operands bool Propagate = false; @@ -598,8 +601,7 @@ public: // worklist. LLVM_DEBUG(dbgs() << "Backward-propagate shapes:\n"); while (!WorkList.empty()) { - Value *V = WorkList.back(); - WorkList.pop_back(); + Value *V = WorkList.pop_back_val(); size_t BeforeProcessingV = WorkList.size(); if (!isa(V)) @@ -721,14 +723,18 @@ public: Value *Op2; if (auto *BinOp = dyn_cast(Inst)) Changed |= VisitBinaryOperator(BinOp); + if (auto *UnOp = dyn_cast(Inst)) + Changed |= VisitUnaryOperator(UnOp); if (match(Inst, m_Load(m_Value(Op1)))) Changed |= VisitLoad(cast(Inst), Op1, Builder); else if (match(Inst, m_Store(m_Value(Op1), m_Value(Op2)))) Changed |= VisitStore(cast(Inst), Op1, Op2, Builder); } - RemarkGenerator RemarkGen(Inst2ColumnMatrix, ORE, Func); - RemarkGen.emitRemarks(); + if (ORE) { + RemarkGenerator RemarkGen(Inst2ColumnMatrix, *ORE, Func); + RemarkGen.emitRemarks(); + } for (Instruction *Inst : reverse(ToRemove)) Inst->eraseFromParent(); @@ -934,10 +940,8 @@ public: unsigned NumElts = cast(Col->getType())->getNumElements(); assert(NumElts >= BlockNumElts && "Too few elements for current block"); - Value *Undef = UndefValue::get(Block->getType()); Block = Builder.CreateShuffleVector( - Block, Undef, - createSequentialMask(0, BlockNumElts, NumElts - BlockNumElts)); + Block, createSequentialMask(0, BlockNumElts, NumElts - BlockNumElts)); // If Col is 7 long and I is 2 and BlockNumElts is 2 the mask is: 0, 1, 7, // 8, 4, 5, 6 @@ -1085,7 +1089,7 @@ public: MemoryLocation StoreLoc = MemoryLocation::get(Store); MemoryLocation LoadLoc = MemoryLocation::get(Load); - AliasResult LdAliased = AA.alias(LoadLoc, StoreLoc); + AliasResult LdAliased = AA->alias(LoadLoc, StoreLoc); // If we can statically determine noalias we're good. if (!LdAliased) @@ -1101,14 +1105,17 @@ public: // as we adjust Check0 and Check1's branches. SmallVector DTUpdates; for (BasicBlock *Succ : successors(Check0)) - DTUpdates.push_back({DT.Delete, Check0, Succ}); + DTUpdates.push_back({DT->Delete, Check0, Succ}); - BasicBlock *Check1 = SplitBlock(MatMul->getParent(), MatMul, nullptr, &LI, - nullptr, "alias_cont"); + BasicBlock *Check1 = + SplitBlock(MatMul->getParent(), MatMul, (DomTreeUpdater *)nullptr, LI, + nullptr, "alias_cont"); BasicBlock *Copy = - SplitBlock(MatMul->getParent(), MatMul, nullptr, &LI, nullptr, "copy"); - BasicBlock *Fusion = SplitBlock(MatMul->getParent(), MatMul, nullptr, &LI, - nullptr, "no_alias"); + SplitBlock(MatMul->getParent(), MatMul, (DomTreeUpdater *)nullptr, LI, + nullptr, "copy"); + BasicBlock *Fusion = + SplitBlock(MatMul->getParent(), MatMul, (DomTreeUpdater *)nullptr, LI, + nullptr, "no_alias"); // Check if the loaded memory location begins before the end of the store // location. If the condition holds, they might overlap, otherwise they are @@ -1152,11 +1159,11 @@ public: PHI->addIncoming(NewLd, Copy); // Adjust DT. - DTUpdates.push_back({DT.Insert, Check0, Check1}); - DTUpdates.push_back({DT.Insert, Check0, Fusion}); - DTUpdates.push_back({DT.Insert, Check1, Copy}); - DTUpdates.push_back({DT.Insert, Check1, Fusion}); - DT.applyUpdates(DTUpdates); + DTUpdates.push_back({DT->Insert, Check0, Check1}); + DTUpdates.push_back({DT->Insert, Check0, Fusion}); + DTUpdates.push_back({DT->Insert, Check1, Copy}); + DTUpdates.push_back({DT->Insert, Check1, Fusion}); + DT->applyUpdates(DTUpdates); return PHI; } @@ -1202,6 +1209,63 @@ public: return Res; } + void createTiledLoops(CallInst *MatMul, Value *LPtr, ShapeInfo LShape, + Value *RPtr, ShapeInfo RShape, StoreInst *Store, + bool AllowContract) { + auto *EltType = cast(MatMul->getType())->getElementType(); + + // Create the main tiling loop nest. + TileInfo TI(LShape.NumRows, RShape.NumColumns, LShape.NumColumns, TileSize); + DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); + Instruction *InsertI = cast(MatMul); + BasicBlock *Start = InsertI->getParent(); + BasicBlock *End = + SplitBlock(InsertI->getParent(), InsertI, DT, LI, nullptr, "continue"); + IRBuilder<> Builder(MatMul); + BasicBlock *InnerBody = TI.CreateTiledLoops(Start, End, Builder, DTU, *LI); + + Type *TileVecTy = + FixedVectorType::get(MatMul->getType()->getScalarType(), TileSize); + MatrixTy TileResult; + // Insert in the inner loop header. + Builder.SetInsertPoint(TI.InnerLoopHeader->getTerminator()); + // Create PHI nodes for the result columns to accumulate across iterations. + SmallVector ColumnPhis; + for (unsigned I = 0; I < TileSize; I++) { + auto *Phi = Builder.CreatePHI(TileVecTy, 2, "result.vec." + Twine(I)); + Phi->addIncoming(ConstantAggregateZero::get(TileVecTy), + TI.RowLoopHeader->getSingleSuccessor()); + TileResult.addVector(Phi); + ColumnPhis.push_back(Phi); + } + + // Insert in the inner loop body, which computes + // Res += Load(CurrentRow, K) * Load(K, CurrentColumn) + Builder.SetInsertPoint(InnerBody->getTerminator()); + // Load tiles of the operands. + MatrixTy A = loadMatrix(LPtr, {}, false, LShape, TI.CurrentRow, TI.CurrentK, + {TileSize, TileSize}, EltType, Builder); + MatrixTy B = loadMatrix(RPtr, {}, false, RShape, TI.CurrentK, TI.CurrentCol, + {TileSize, TileSize}, EltType, Builder); + emitMatrixMultiply(TileResult, A, B, AllowContract, Builder, true); + // Store result after the inner loop is done. + Builder.SetInsertPoint(TI.RowLoopLatch->getTerminator()); + storeMatrix(TileResult, Store->getPointerOperand(), Store->getAlign(), + Store->isVolatile(), {LShape.NumRows, RShape.NumColumns}, + TI.CurrentRow, TI.CurrentCol, EltType, Builder); + + for (unsigned I = 0; I < TileResult.getNumVectors(); I++) + ColumnPhis[I]->addIncoming(TileResult.getVector(I), TI.InnerLoopLatch); + + // Force unrolling of a few iterations of the inner loop, to make sure there + // is enough work per iteration. + // FIXME: The unroller should make this decision directly instead, but + // currently the cost-model is not up to the task. + unsigned InnerLoopUnrollCount = std::min(10u, LShape.NumColumns / TileSize); + addStringMetadataToLoop(LI->getLoopFor(TI.InnerLoopHeader), + "llvm.loop.unroll.count", InnerLoopUnrollCount); + } + void emitSIMDTiling(CallInst *MatMul, LoadInst *LoadOp0, LoadInst *LoadOp1, StoreInst *Store, SmallPtrSetImpl &FusedInsts) { @@ -1224,28 +1288,34 @@ public: bool AllowContract = AllowContractEnabled || (isa(MatMul) && MatMul->hasAllowContract()); - IRBuilder<> Builder(Store); - for (unsigned J = 0; J < C; J += TileSize) - for (unsigned I = 0; I < R; I += TileSize) { - const unsigned TileR = std::min(R - I, unsigned(TileSize)); - const unsigned TileC = std::min(C - J, unsigned(TileSize)); - MatrixTy Res = getZeroMatrix(EltType, TileR, TileC); - - for (unsigned K = 0; K < M; K += TileSize) { - const unsigned TileM = std::min(M - K, unsigned(TileSize)); - MatrixTy A = - loadMatrix(APtr, LoadOp0->getAlign(), LoadOp0->isVolatile(), - LShape, Builder.getInt64(I), Builder.getInt64(K), - {TileR, TileM}, EltType, Builder); - MatrixTy B = - loadMatrix(BPtr, LoadOp1->getAlign(), LoadOp1->isVolatile(), - RShape, Builder.getInt64(K), Builder.getInt64(J), - {TileM, TileC}, EltType, Builder); - emitMatrixMultiply(Res, A, B, AllowContract, Builder, true); + if (TileUseLoops && (R % TileSize == 0 && C % TileSize == 0)) + createTiledLoops(MatMul, APtr, LShape, BPtr, RShape, Store, + AllowContract); + else { + IRBuilder<> Builder(Store); + for (unsigned J = 0; J < C; J += TileSize) + for (unsigned I = 0; I < R; I += TileSize) { + const unsigned TileR = std::min(R - I, unsigned(TileSize)); + const unsigned TileC = std::min(C - J, unsigned(TileSize)); + MatrixTy Res = getZeroMatrix(EltType, TileR, TileC); + + for (unsigned K = 0; K < M; K += TileSize) { + const unsigned TileM = std::min(M - K, unsigned(TileSize)); + MatrixTy A = + loadMatrix(APtr, LoadOp0->getAlign(), LoadOp0->isVolatile(), + LShape, Builder.getInt64(I), Builder.getInt64(K), + {TileR, TileM}, EltType, Builder); + MatrixTy B = + loadMatrix(BPtr, LoadOp1->getAlign(), LoadOp1->isVolatile(), + RShape, Builder.getInt64(K), Builder.getInt64(J), + {TileM, TileC}, EltType, Builder); + emitMatrixMultiply(Res, A, B, AllowContract, Builder, true); + } + storeMatrix(Res, CPtr, Store->getAlign(), Store->isVolatile(), {R, M}, + Builder.getInt64(I), Builder.getInt64(J), EltType, + Builder); } - storeMatrix(Res, CPtr, Store->getAlign(), Store->isVolatile(), {R, M}, - Builder.getInt64(I), Builder.getInt64(J), EltType, Builder); - } + } // Mark eliminated instructions as fused and remove them. FusedInsts.insert(Store); @@ -1272,9 +1342,11 @@ public: void LowerMatrixMultiplyFused(CallInst *MatMul, SmallPtrSetImpl &FusedInsts) { if (!FuseMatrix || !MatMul->hasOneUse() || - MatrixLayout != MatrixLayoutTy::ColumnMajor) + MatrixLayout != MatrixLayoutTy::ColumnMajor || !DT) return; + assert(AA && LI && "Analyses should be available"); + auto *LoadOp0 = dyn_cast(MatMul->getOperand(0)); auto *LoadOp1 = dyn_cast(MatMul->getOperand(1)); auto *Store = dyn_cast(*MatMul->user_begin()); @@ -1283,7 +1355,7 @@ public: // we create invalid IR. // FIXME: See if we can hoist the store address computation. auto *AddrI = dyn_cast(Store->getOperand(1)); - if (AddrI && (!DT.dominates(AddrI, MatMul))) + if (AddrI && (!DT->dominates(AddrI, MatMul))) return; emitSIMDTiling(MatMul, LoadOp0, LoadOp1, Store, FusedInsts); @@ -1300,6 +1372,8 @@ public: const MatrixTy &Lhs = getMatrix(MatMul->getArgOperand(0), LShape, Builder); const MatrixTy &Rhs = getMatrix(MatMul->getArgOperand(1), RShape, Builder); + assert(Lhs.getElementType() == Rhs.getElementType() && + "Matrix multiply argument element types do not match."); const unsigned R = LShape.NumRows; const unsigned C = RShape.NumColumns; @@ -1307,6 +1381,8 @@ public: // Initialize the output MatrixTy Result(R, C, EltType); + assert(Lhs.getElementType() == Result.getElementType() && + "Matrix multiply result element type does not match arguments."); bool AllowContract = AllowContractEnabled || (isa(MatMul) && MatMul->hasAllowContract()); @@ -1424,6 +1500,40 @@ public: return true; } + /// Lower unary operators, if shape information is available. + bool VisitUnaryOperator(UnaryOperator *Inst) { + auto I = ShapeMap.find(Inst); + if (I == ShapeMap.end()) + return false; + + Value *Op = Inst->getOperand(0); + + IRBuilder<> Builder(Inst); + ShapeInfo &Shape = I->second; + + MatrixTy Result; + MatrixTy M = getMatrix(Op, Shape, Builder); + + // Helper to perform unary op on vectors. + auto BuildVectorOp = [&Builder, Inst](Value *Op) { + switch (Inst->getOpcode()) { + case Instruction::FNeg: + return Builder.CreateFNeg(Op); + default: + llvm_unreachable("Unsupported unary operator for matrix"); + } + }; + + for (unsigned I = 0; I < Shape.getNumVectors(); ++I) + Result.addVector(BuildVectorOp(M.getVector(I))); + + finalizeLowering(Inst, + Result.addNumComputeOps(getNumOps(Result.getVectorTy()) * + Result.getNumVectors()), + Builder); + return true; + } + /// Helper to linearize a matrix expression tree into a string. Currently /// matrix expressions are linarized by starting at an expression leaf and /// linearizing bottom up. @@ -1488,7 +1598,7 @@ public: if (Value *Ptr = getPointerOperand(V)) return getUnderlyingObjectThroughLoads(Ptr); else if (V->getType()->isPointerTy()) - return GetUnderlyingObject(V, DL); + return getUnderlyingObject(V); return V; } @@ -1524,7 +1634,7 @@ public: write(StringRef(Intrinsic::getName(II->getIntrinsicID(), {})) .drop_front(StringRef("llvm.matrix.").size())); write("."); - std::string Tmp = ""; + std::string Tmp; raw_string_ostream SS(Tmp); switch (II->getIntrinsicID()) { @@ -1737,7 +1847,6 @@ public: for (Value *Op : cast(V)->operand_values()) collectSharedInfo(Leaf, Op, ExprsInSubprogram, Shared); - return; } /// Calculate the number of exclusive and shared op counts for expression @@ -1863,15 +1972,25 @@ public: PreservedAnalyses LowerMatrixIntrinsicsPass::run(Function &F, FunctionAnalysisManager &AM) { auto &TTI = AM.getResult(F); - auto &ORE = AM.getResult(F); - auto &AA = AM.getResult(F); - auto &DT = AM.getResult(F); - auto &LI = AM.getResult(F); + OptimizationRemarkEmitter *ORE = nullptr; + AAResults *AA = nullptr; + DominatorTree *DT = nullptr; + LoopInfo *LI = nullptr; + + if (!Minimal) { + ORE = &AM.getResult(F); + AA = &AM.getResult(F); + DT = &AM.getResult(F); + LI = &AM.getResult(F); + } LowerMatrixIntrinsics LMT(F, TTI, AA, DT, LI, ORE); if (LMT.Visit()) { PreservedAnalyses PA; - PA.preserveSet(); + if (!Minimal) { + PA.preserve(); + PA.preserve(); + } return PA; } return PreservedAnalyses::all(); @@ -1894,7 +2013,7 @@ public: auto &AA = getAnalysis().getAAResults(); auto &DT = getAnalysis().getDomTree(); auto &LI = getAnalysis().getLoopInfo(); - LowerMatrixIntrinsics LMT(F, TTI, AA, DT, LI, ORE); + LowerMatrixIntrinsics LMT(F, TTI, &AA, &DT, &LI, &ORE); bool C = LMT.Visit(); return C; } @@ -1925,3 +2044,45 @@ INITIALIZE_PASS_END(LowerMatrixIntrinsicsLegacyPass, DEBUG_TYPE, pass_name, Pass *llvm::createLowerMatrixIntrinsicsPass() { return new LowerMatrixIntrinsicsLegacyPass(); } + +namespace { + +/// A lightweight version of the matrix lowering pass that only requires TTI. +/// Advanced features that require DT, AA or ORE like tiling are disabled. This +/// is used to lower matrix intrinsics if the main lowering pass is not run, for +/// example with -O0. +class LowerMatrixIntrinsicsMinimalLegacyPass : public FunctionPass { +public: + static char ID; + + LowerMatrixIntrinsicsMinimalLegacyPass() : FunctionPass(ID) { + initializeLowerMatrixIntrinsicsMinimalLegacyPassPass( + *PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override { + auto &TTI = getAnalysis().getTTI(F); + LowerMatrixIntrinsics LMT(F, TTI, nullptr, nullptr, nullptr, nullptr); + bool C = LMT.Visit(); + return C; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.setPreservesCFG(); + } +}; +} // namespace + +static const char pass_name_minimal[] = "Lower the matrix intrinsics (minimal)"; +char LowerMatrixIntrinsicsMinimalLegacyPass::ID = 0; +INITIALIZE_PASS_BEGIN(LowerMatrixIntrinsicsMinimalLegacyPass, + "lower-matrix-intrinsics-minimal", pass_name_minimal, + false, false) +INITIALIZE_PASS_END(LowerMatrixIntrinsicsMinimalLegacyPass, + "lower-matrix-intrinsics-minimal", pass_name_minimal, false, + false) + +Pass *llvm::createLowerMatrixIntrinsicsMinimalPass() { + return new LowerMatrixIntrinsicsMinimalLegacyPass(); +} diff --git a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp index 4b4196edc12b..a4e695497f30 100644 --- a/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp +++ b/llvm/lib/Transforms/Scalar/MemCpyOptimizer.cpp @@ -21,8 +21,11 @@ #include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/MemoryDependenceAnalysis.h" #include "llvm/Analysis/MemoryLocation.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/MemorySSAUpdater.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Argument.h" @@ -64,10 +67,15 @@ using namespace llvm; #define DEBUG_TYPE "memcpyopt" +static cl::opt + EnableMemorySSA("enable-memcpyopt-memoryssa", cl::init(false), cl::Hidden, + cl::desc("Use MemorySSA-backed MemCpyOpt.")); + STATISTIC(NumMemCpyInstr, "Number of memcpy instructions deleted"); STATISTIC(NumMemSetInfer, "Number of memsets inferred"); STATISTIC(NumMoveToCpy, "Number of memmoves converted to memcpy"); STATISTIC(NumCpyToSet, "Number of memcpys converted to memset"); +STATISTIC(NumCallSlot, "Number of call slot optimizations performed"); namespace { @@ -271,11 +279,17 @@ private: AU.setPreservesCFG(); AU.addRequired(); AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); + AU.addPreserved(); AU.addPreserved(); + AU.addRequired(); + if (!EnableMemorySSA) + AU.addRequired(); AU.addPreserved(); + AU.addRequired(); + AU.addPreserved(); + if (EnableMemorySSA) + AU.addRequired(); + AU.addPreserved(); } }; @@ -297,6 +311,56 @@ INITIALIZE_PASS_DEPENDENCY(GlobalsAAWrapperPass) INITIALIZE_PASS_END(MemCpyOptLegacyPass, "memcpyopt", "MemCpy Optimization", false, false) +// Check that V is either not accessible by the caller, or unwinding cannot +// occur between Start and End. +static bool mayBeVisibleThroughUnwinding(Value *V, Instruction *Start, + Instruction *End) { + assert(Start->getParent() == End->getParent() && "Must be in same block"); + if (!Start->getFunction()->doesNotThrow() && + !isa(getUnderlyingObject(V))) { + for (const Instruction &I : + make_range(Start->getIterator(), End->getIterator())) { + if (I.mayThrow()) + return true; + } + } + return false; +} + +void MemCpyOptPass::eraseInstruction(Instruction *I) { + if (MSSAU) + MSSAU->removeMemoryAccess(I); + if (MD) + MD->removeInstruction(I); + I->eraseFromParent(); +} + +// Check for mod or ref of Loc between Start and End, excluding both boundaries. +// Start and End must be in the same block +static bool accessedBetween(AliasAnalysis &AA, MemoryLocation Loc, + const MemoryUseOrDef *Start, + const MemoryUseOrDef *End) { + assert(Start->getBlock() == End->getBlock() && "Only local supported"); + for (const MemoryAccess &MA : + make_range(++Start->getIterator(), End->getIterator())) { + if (isModOrRefSet(AA.getModRefInfo(cast(MA).getMemoryInst(), + Loc))) + return true; + } + return false; +} + +// Check for mod of Loc between Start and End, excluding both boundaries. +// Start and End can be in different blocks. +static bool writtenBetween(MemorySSA *MSSA, MemoryLocation Loc, + const MemoryUseOrDef *Start, + const MemoryUseOrDef *End) { + // TODO: Only walk until we hit Start. + MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess( + End->getDefiningAccess(), Loc); + return !MSSA->dominates(Clobber, Start); +} + /// When scanning forward over instructions, we look for some other patterns to /// fold away. In particular, this looks for stores to neighboring locations of /// memory. If it sees enough consecutive ones, it attempts to merge them @@ -313,7 +377,27 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, MemsetRanges Ranges(DL); BasicBlock::iterator BI(StartInst); + + // Keeps track of the last memory use or def before the insertion point for + // the new memset. The new MemoryDef for the inserted memsets will be inserted + // after MemInsertPoint. It points to either LastMemDef or to the last user + // before the insertion point of the memset, if there are any such users. + MemoryUseOrDef *MemInsertPoint = nullptr; + // Keeps track of the last MemoryDef between StartInst and the insertion point + // for the new memset. This will become the defining access of the inserted + // memsets. + MemoryDef *LastMemDef = nullptr; for (++BI; !BI->isTerminator(); ++BI) { + if (MSSAU) { + auto *CurrentAcc = cast_or_null( + MSSAU->getMemorySSA()->getMemoryAccess(&*BI)); + if (CurrentAcc) { + MemInsertPoint = CurrentAcc; + if (auto *CurrentDef = dyn_cast(CurrentAcc)) + LastMemDef = CurrentDef; + } + } + if (!isa(BI) && !isa(BI)) { // If the instruction is readnone, ignore it, otherwise bail out. We // don't even allow readonly here because we don't want something like: @@ -327,8 +411,15 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, // If this is a store, see if we can merge it in. if (!NextStore->isSimple()) break; + Value *StoredVal = NextStore->getValueOperand(); + + // Don't convert stores of non-integral pointer types to memsets (which + // stores integers). + if (DL.isNonIntegralPointerType(StoredVal->getType()->getScalarType())) + break; + // Check to see if this stored value is of the same byte-splattable value. - Value *StoredByte = isBytewiseValue(NextStore->getOperand(0), DL); + Value *StoredByte = isBytewiseValue(StoredVal, DL); if (isa(ByteVal) && StoredByte) ByteVal = StoredByte; if (ByteVal != StoredByte) @@ -392,15 +483,27 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, : Range.TheStores) dbgs() << *SI << '\n'; dbgs() << "With: " << *AMemSet << '\n'); - if (!Range.TheStores.empty()) AMemSet->setDebugLoc(Range.TheStores[0]->getDebugLoc()); - // Zap all the stores. - for (Instruction *SI : Range.TheStores) { - MD->removeInstruction(SI); - SI->eraseFromParent(); + if (MSSAU) { + assert(LastMemDef && MemInsertPoint && + "Both LastMemDef and MemInsertPoint need to be set"); + auto *NewDef = + cast(MemInsertPoint->getMemoryInst() == &*BI + ? MSSAU->createMemoryAccessBefore( + AMemSet, LastMemDef, MemInsertPoint) + : MSSAU->createMemoryAccessAfter( + AMemSet, LastMemDef, MemInsertPoint)); + MSSAU->insertDef(NewDef, /*RenameUses=*/true); + LastMemDef = NewDef; + MemInsertPoint = NewDef; } + + // Zap all the stores. + for (Instruction *SI : Range.TheStores) + eraseInstruction(SI); + ++NumMemSetInfer; } @@ -411,11 +514,10 @@ Instruction *MemCpyOptPass::tryMergingIntoMemset(Instruction *StartInst, // It will lift the store and its argument + that anything that // may alias with these. // The method returns true if it was successful. -static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P, - const LoadInst *LI) { +bool MemCpyOptPass::moveUp(StoreInst *SI, Instruction *P, const LoadInst *LI) { // If the store alias this position, early bail out. MemoryLocation StoreLoc = MemoryLocation::get(SI); - if (isModOrRefSet(AA.getModRefInfo(P, StoreLoc))) + if (isModOrRefSet(AA->getModRefInfo(P, StoreLoc))) return false; // Keep track of the arguments of all instruction we plan to lift @@ -426,7 +528,7 @@ static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P, Args.insert(Ptr); // Instruction to lift before P. - SmallVector ToLift; + SmallVector ToLift{SI}; // Memory locations of lifted instructions. SmallVector MemLocs{StoreLoc}; @@ -439,19 +541,24 @@ static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P, for (auto I = --SI->getIterator(), E = P->getIterator(); I != E; --I) { auto *C = &*I; - bool MayAlias = isModOrRefSet(AA.getModRefInfo(C, None)); + // Make sure hoisting does not perform a store that was not guaranteed to + // happen. + if (!isGuaranteedToTransferExecutionToSuccessor(C)) + return false; + + bool MayAlias = isModOrRefSet(AA->getModRefInfo(C, None)); bool NeedLift = false; if (Args.erase(C)) NeedLift = true; else if (MayAlias) { - NeedLift = llvm::any_of(MemLocs, [C, &AA](const MemoryLocation &ML) { - return isModOrRefSet(AA.getModRefInfo(C, ML)); + NeedLift = llvm::any_of(MemLocs, [C, this](const MemoryLocation &ML) { + return isModOrRefSet(AA->getModRefInfo(C, ML)); }); if (!NeedLift) - NeedLift = llvm::any_of(Calls, [C, &AA](const CallBase *Call) { - return isModOrRefSet(AA.getModRefInfo(C, Call)); + NeedLift = llvm::any_of(Calls, [C, this](const CallBase *Call) { + return isModOrRefSet(AA->getModRefInfo(C, Call)); }); } @@ -461,18 +568,18 @@ static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P, if (MayAlias) { // Since LI is implicitly moved downwards past the lifted instructions, // none of them may modify its source. - if (isModSet(AA.getModRefInfo(C, LoadLoc))) + if (isModSet(AA->getModRefInfo(C, LoadLoc))) return false; else if (const auto *Call = dyn_cast(C)) { // If we can't lift this before P, it's game over. - if (isModOrRefSet(AA.getModRefInfo(P, Call))) + if (isModOrRefSet(AA->getModRefInfo(P, Call))) return false; Calls.push_back(Call); } else if (isa(C) || isa(C) || isa(C)) { // If we can't lift this before P, it's game over. auto ML = MemoryLocation::get(C); - if (isModOrRefSet(AA.getModRefInfo(P, ML))) + if (isModOrRefSet(AA->getModRefInfo(P, ML))) return false; MemLocs.push_back(ML); @@ -492,10 +599,40 @@ static bool moveUp(AliasAnalysis &AA, StoreInst *SI, Instruction *P, } } - // We made it, we need to lift + // Find MSSA insertion point. Normally P will always have a corresponding + // memory access before which we can insert. However, with non-standard AA + // pipelines, there may be a mismatch between AA and MSSA, in which case we + // will scan for a memory access before P. In either case, we know for sure + // that at least the load will have a memory access. + // TODO: Simplify this once P will be determined by MSSA, in which case the + // discrepancy can no longer occur. + MemoryUseOrDef *MemInsertPoint = nullptr; + if (MSSAU) { + if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(P)) { + MemInsertPoint = cast(--MA->getIterator()); + } else { + const Instruction *ConstP = P; + for (const Instruction &I : make_range(++ConstP->getReverseIterator(), + ++LI->getReverseIterator())) { + if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(&I)) { + MemInsertPoint = MA; + break; + } + } + } + } + + // We made it, we need to lift. for (auto *I : llvm::reverse(ToLift)) { LLVM_DEBUG(dbgs() << "Lifting " << *I << " before " << *P << "\n"); I->moveBefore(P); + if (MSSAU) { + assert(MemInsertPoint && "Must have found insert point"); + if (MemoryUseOrDef *MA = MSSAU->getMemorySSA()->getMemoryAccess(I)) { + MSSAU->moveAfter(MA, MemInsertPoint); + MemInsertPoint = MA; + } + } } return true; @@ -515,23 +652,30 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { const DataLayout &DL = SI->getModule()->getDataLayout(); + Value *StoredVal = SI->getValueOperand(); + + // Not all the transforms below are correct for non-integral pointers, bail + // until we've audited the individual pieces. + if (DL.isNonIntegralPointerType(StoredVal->getType()->getScalarType())) + return false; + // Load to store forwarding can be interpreted as memcpy. - if (LoadInst *LI = dyn_cast(SI->getOperand(0))) { + if (LoadInst *LI = dyn_cast(StoredVal)) { if (LI->isSimple() && LI->hasOneUse() && LI->getParent() == SI->getParent()) { auto *T = LI->getType(); if (T->isAggregateType()) { - AliasAnalysis &AA = LookupAliasAnalysis(); MemoryLocation LoadLoc = MemoryLocation::get(LI); // We use alias analysis to check if an instruction may store to // the memory we load from in between the load and the store. If // such an instruction is found, we try to promote there instead // of at the store position. + // TODO: Can use MSSA for this. Instruction *P = SI; for (auto &I : make_range(++LI->getIterator(), SI->getIterator())) { - if (isModSet(AA.getModRefInfo(&I, LoadLoc))) { + if (isModSet(AA->getModRefInfo(&I, LoadLoc))) { P = &I; break; } @@ -542,7 +686,7 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { // position if nothing alias the store memory after this and the store // destination is not in the range. if (P && P != SI) { - if (!moveUp(AA, SI, P, LI)) + if (!moveUp(SI, P, LI)) P = nullptr; } @@ -553,7 +697,7 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { // memmove must be used to preserve semantic. If not, memcpy can // be used. bool UseMemMove = false; - if (!AA.isNoAlias(MemoryLocation::get(SI), LoadLoc)) + if (!AA->isNoAlias(MemoryLocation::get(SI), LoadLoc)) UseMemMove = true; uint64_t Size = DL.getTypeStoreSize(T); @@ -572,10 +716,16 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { LLVM_DEBUG(dbgs() << "Promoting " << *LI << " to " << *SI << " => " << *M << "\n"); - MD->removeInstruction(SI); - SI->eraseFromParent(); - MD->removeInstruction(LI); - LI->eraseFromParent(); + if (MSSAU) { + auto *LastDef = + cast(MSSAU->getMemorySSA()->getMemoryAccess(SI)); + auto *NewAccess = + MSSAU->createMemoryAccessAfter(M, LastDef, LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } + + eraseInstruction(SI); + eraseInstruction(LI); ++NumMemCpyInstr; // Make sure we do not invalidate the iterator. @@ -587,44 +737,50 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { // Detect cases where we're performing call slot forwarding, but // happen to be using a load-store pair to implement it, rather than // a memcpy. - MemDepResult ldep = MD->getDependency(LI); CallInst *C = nullptr; - if (ldep.isClobber() && !isa(ldep.getInst())) - C = dyn_cast(ldep.getInst()); + if (EnableMemorySSA) { + if (auto *LoadClobber = dyn_cast( + MSSA->getWalker()->getClobberingMemoryAccess(LI))) { + // The load most post-dom the call. Limit to the same block for now. + // TODO: Support non-local call-slot optimization? + if (LoadClobber->getBlock() == SI->getParent()) + C = dyn_cast_or_null(LoadClobber->getMemoryInst()); + } + } else { + MemDepResult ldep = MD->getDependency(LI); + if (ldep.isClobber() && !isa(ldep.getInst())) + C = dyn_cast(ldep.getInst()); + } if (C) { // Check that nothing touches the dest of the "copy" between // the call and the store. - Value *CpyDest = SI->getPointerOperand()->stripPointerCasts(); - bool CpyDestIsLocal = isa(CpyDest); - AliasAnalysis &AA = LookupAliasAnalysis(); MemoryLocation StoreLoc = MemoryLocation::get(SI); - for (BasicBlock::iterator I = --SI->getIterator(), E = C->getIterator(); - I != E; --I) { - if (isModOrRefSet(AA.getModRefInfo(&*I, StoreLoc))) { + if (EnableMemorySSA) { + if (accessedBetween(*AA, StoreLoc, MSSA->getMemoryAccess(C), + MSSA->getMemoryAccess(SI))) C = nullptr; - break; - } - // The store to dest may never happen if an exception can be thrown - // between the load and the store. - if (I->mayThrow() && !CpyDestIsLocal) { - C = nullptr; - break; + } else { + for (BasicBlock::iterator I = --SI->getIterator(), + E = C->getIterator(); + I != E; --I) { + if (isModOrRefSet(AA->getModRefInfo(&*I, StoreLoc))) { + C = nullptr; + break; + } } } } if (C) { bool changed = performCallSlotOptzn( - LI, SI->getPointerOperand()->stripPointerCasts(), + LI, SI, SI->getPointerOperand()->stripPointerCasts(), LI->getPointerOperand()->stripPointerCasts(), DL.getTypeStoreSize(SI->getOperand(0)->getType()), commonAlignment(SI->getAlign(), LI->getAlign()), C); if (changed) { - MD->removeInstruction(SI); - SI->eraseFromParent(); - MD->removeInstruction(LI); - LI->eraseFromParent(); + eraseInstruction(SI); + eraseInstruction(LI); ++NumMemCpyInstr; return true; } @@ -658,8 +814,15 @@ bool MemCpyOptPass::processStore(StoreInst *SI, BasicBlock::iterator &BBI) { LLVM_DEBUG(dbgs() << "Promoting " << *SI << " to " << *M << "\n"); - MD->removeInstruction(SI); - SI->eraseFromParent(); + if (MSSAU) { + assert(isa(MSSAU->getMemorySSA()->getMemoryAccess(SI))); + auto *LastDef = + cast(MSSAU->getMemorySSA()->getMemoryAccess(SI)); + auto *NewAccess = MSSAU->createMemoryAccessAfter(M, LastDef, LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } + + eraseInstruction(SI); NumMemSetInfer++; // Make sure we do not invalidate the iterator. @@ -686,7 +849,8 @@ bool MemCpyOptPass::processMemSet(MemSetInst *MSI, BasicBlock::iterator &BBI) { /// Takes a memcpy and a call that it depends on, /// and checks for the possibility of a call slot optimization by having /// the call write its result directly into the destination of the memcpy. -bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, +bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpyLoad, + Instruction *cpyStore, Value *cpyDest, Value *cpySrc, uint64_t cpyLen, Align cpyAlign, CallInst *C) { // The general transformation to keep in mind is @@ -717,7 +881,7 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, if (!srcArraySize) return false; - const DataLayout &DL = cpy->getModule()->getDataLayout(); + const DataLayout &DL = cpyLoad->getModule()->getDataLayout(); uint64_t srcSize = DL.getTypeAllocSize(srcAlloca->getAllocatedType()) * srcArraySize->getZExtValue(); @@ -727,43 +891,26 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, // Check that accessing the first srcSize bytes of dest will not cause a // trap. Otherwise the transform is invalid since it might cause a trap // to occur earlier than it otherwise would. - if (AllocaInst *A = dyn_cast(cpyDest)) { - // The destination is an alloca. Check it is larger than srcSize. - ConstantInt *destArraySize = dyn_cast(A->getArraySize()); - if (!destArraySize) - return false; - - uint64_t destSize = DL.getTypeAllocSize(A->getAllocatedType()) * - destArraySize->getZExtValue(); - - if (destSize < srcSize) - return false; - } else if (Argument *A = dyn_cast(cpyDest)) { - // The store to dest may never happen if the call can throw. - if (C->mayThrow()) - return false; - - if (A->getDereferenceableBytes() < srcSize) { - // If the destination is an sret parameter then only accesses that are - // outside of the returned struct type can trap. - if (!A->hasStructRetAttr()) - return false; - - Type *StructTy = cast(A->getType())->getElementType(); - if (!StructTy->isSized()) { - // The call may never return and hence the copy-instruction may never - // be executed, and therefore it's not safe to say "the destination - // has at least bytes, as implied by the copy-instruction", - return false; - } + if (!isDereferenceableAndAlignedPointer(cpyDest, Align(1), APInt(64, cpyLen), + DL, C, DT)) + return false; - uint64_t destSize = DL.getTypeAllocSize(StructTy); - if (destSize < srcSize) - return false; - } - } else { + // Make sure that nothing can observe cpyDest being written early. There are + // a number of cases to consider: + // 1. cpyDest cannot be accessed between C and cpyStore as a precondition of + // the transform. + // 2. C itself may not access cpyDest (prior to the transform). This is + // checked further below. + // 3. If cpyDest is accessible to the caller of this function (potentially + // captured and not based on an alloca), we need to ensure that we cannot + // unwind between C and cpyStore. This is checked here. + // 4. If cpyDest is potentially captured, there may be accesses to it from + // another thread. In this case, we need to check that cpyStore is + // guaranteed to be executed if C is. As it is a non-atomic access, it + // renders accesses from other threads undefined. + // TODO: This is currently not checked. + if (mayBeVisibleThroughUnwinding(cpyDest, C, cpyStore)) return false; - } // Check that dest points to memory that is at least as aligned as src. Align srcAlign = srcAlloca->getAlign(); @@ -777,29 +924,26 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, // guarantees that it holds only undefined values when passed in (so the final // memcpy can be dropped), that it is not read or written between the call and // the memcpy, and that writing beyond the end of it is undefined. - SmallVector srcUseList(srcAlloca->user_begin(), - srcAlloca->user_end()); + SmallVector srcUseList(srcAlloca->users()); while (!srcUseList.empty()) { User *U = srcUseList.pop_back_val(); if (isa(U) || isa(U)) { - for (User *UU : U->users()) - srcUseList.push_back(UU); + append_range(srcUseList, U->users()); continue; } if (GetElementPtrInst *G = dyn_cast(U)) { if (!G->hasAllZeroIndices()) return false; - for (User *UU : U->users()) - srcUseList.push_back(UU); + append_range(srcUseList, U->users()); continue; } if (const IntrinsicInst *IT = dyn_cast(U)) if (IT->isLifetimeStartOrEnd()) continue; - if (U != C && U != cpy) + if (U != C && U != cpyLoad) return false; } @@ -811,20 +955,24 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, // Since we're changing the parameter to the callsite, we need to make sure // that what would be the new parameter dominates the callsite. - DominatorTree &DT = LookupDomTree(); - if (Instruction *cpyDestInst = dyn_cast(cpyDest)) - if (!DT.dominates(cpyDestInst, C)) + if (!DT->dominates(cpyDest, C)) { + // Support moving a constant index GEP before the call. + auto *GEP = dyn_cast(cpyDest); + if (GEP && GEP->hasAllConstantIndices() && + DT->dominates(GEP->getPointerOperand(), C)) + GEP->moveBefore(C); + else return false; + } // In addition to knowing that the call does not access src in some // unexpected manner, for example via a global, which we deduce from // the use analysis, we also need to know that it does not sneakily // access dest. We rely on AA to figure this out for us. - AliasAnalysis &AA = LookupAliasAnalysis(); - ModRefInfo MR = AA.getModRefInfo(C, cpyDest, LocationSize::precise(srcSize)); + ModRefInfo MR = AA->getModRefInfo(C, cpyDest, LocationSize::precise(srcSize)); // If necessary, perform additional analysis. if (isModOrRefSet(MR)) - MR = AA.callCapturesBefore(C, cpyDest, LocationSize::precise(srcSize), &DT); + MR = AA->callCapturesBefore(C, cpyDest, LocationSize::precise(srcSize), DT); if (isModOrRefSet(MR)) return false; @@ -866,7 +1014,8 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, // Drop any cached information about the call, because we may have changed // its dependence information by changing its parameter. - MD->removeInstruction(C); + if (MD) + MD->removeInstruction(C); // Update AA metadata // FIXME: MD_tbaa_struct and MD_mem_parallel_loop_access should also be @@ -875,12 +1024,9 @@ bool MemCpyOptPass::performCallSlotOptzn(Instruction *cpy, Value *cpyDest, LLVMContext::MD_noalias, LLVMContext::MD_invariant_group, LLVMContext::MD_access_group}; - combineMetadata(C, cpy, KnownIDs, true); - - // Remove the memcpy. - MD->removeInstruction(cpy); - ++NumMemCpyInstr; + combineMetadata(C, cpyLoad, KnownIDs, true); + ++NumCallSlot; return true; } @@ -908,8 +1054,6 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M, if (!MDepLen || !MLen || MDepLen->getZExtValue() < MLen->getZExtValue()) return false; - AliasAnalysis &AA = LookupAliasAnalysis(); - // Verify that the copied-from memory doesn't change in between the two // transfers. For example, in: // memcpy(a <- b) @@ -919,21 +1063,28 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M, // // TODO: If the code between M and MDep is transparent to the destination "c", // then we could still perform the xform by moving M up to the first memcpy. - // - // NOTE: This is conservative, it will stop on any read from the source loc, - // not just the defining memcpy. - MemDepResult SourceDep = - MD->getPointerDependencyFrom(MemoryLocation::getForSource(MDep), false, - M->getIterator(), M->getParent()); - if (!SourceDep.isClobber() || SourceDep.getInst() != MDep) - return false; + if (EnableMemorySSA) { + // TODO: It would be sufficient to check the MDep source up to the memcpy + // size of M, rather than MDep. + if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep), + MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(M))) + return false; + } else { + // NOTE: This is conservative, it will stop on any read from the source loc, + // not just the defining memcpy. + MemDepResult SourceDep = + MD->getPointerDependencyFrom(MemoryLocation::getForSource(MDep), false, + M->getIterator(), M->getParent()); + if (!SourceDep.isClobber() || SourceDep.getInst() != MDep) + return false; + } // If the dest of the second might alias the source of the first, then the // source and dest might overlap. We still want to eliminate the intermediate // value, but we have to generate a memmove instead of memcpy. bool UseMemMove = false; - if (!AA.isNoAlias(MemoryLocation::getForDest(M), - MemoryLocation::getForSource(MDep))) + if (!AA->isNoAlias(MemoryLocation::getForDest(M), + MemoryLocation::getForSource(MDep))) UseMemMove = true; // If all checks passed, then we can transform M. @@ -943,18 +1094,25 @@ bool MemCpyOptPass::processMemCpyMemCpyDependence(MemCpyInst *M, // TODO: Is this worth it if we're creating a less aligned memcpy? For // example we could be moving from movaps -> movq on x86. IRBuilder<> Builder(M); + Instruction *NewM; if (UseMemMove) - Builder.CreateMemMove(M->getRawDest(), M->getDestAlign(), - MDep->getRawSource(), MDep->getSourceAlign(), - M->getLength(), M->isVolatile()); + NewM = Builder.CreateMemMove(M->getRawDest(), M->getDestAlign(), + MDep->getRawSource(), MDep->getSourceAlign(), + M->getLength(), M->isVolatile()); else - Builder.CreateMemCpy(M->getRawDest(), M->getDestAlign(), - MDep->getRawSource(), MDep->getSourceAlign(), - M->getLength(), M->isVolatile()); + NewM = Builder.CreateMemCpy(M->getRawDest(), M->getDestAlign(), + MDep->getRawSource(), MDep->getSourceAlign(), + M->getLength(), M->isVolatile()); + + if (MSSAU) { + assert(isa(MSSAU->getMemorySSA()->getMemoryAccess(M))); + auto *LastDef = cast(MSSAU->getMemorySSA()->getMemoryAccess(M)); + auto *NewAccess = MSSAU->createMemoryAccessAfter(NewM, LastDef, LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } // Remove the instruction we're replacing. - MD->removeInstruction(M); - M->eraseFromParent(); + eraseInstruction(M); ++NumMemCpyInstr; return true; } @@ -979,18 +1137,41 @@ bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy, if (MemSet->getDest() != MemCpy->getDest()) return false; - // Check that there are no other dependencies on the memset destination. - MemDepResult DstDepInfo = - MD->getPointerDependencyFrom(MemoryLocation::getForDest(MemSet), false, - MemCpy->getIterator(), MemCpy->getParent()); - if (DstDepInfo.getInst() != MemSet) + // Check that src and dst of the memcpy aren't the same. While memcpy + // operands cannot partially overlap, exact equality is allowed. + if (!AA->isNoAlias(MemoryLocation(MemCpy->getSource(), + LocationSize::precise(1)), + MemoryLocation(MemCpy->getDest(), + LocationSize::precise(1)))) return false; + if (EnableMemorySSA) { + // We know that dst up to src_size is not written. We now need to make sure + // that dst up to dst_size is not accessed. (If we did not move the memset, + // checking for reads would be sufficient.) + if (accessedBetween(*AA, MemoryLocation::getForDest(MemSet), + MSSA->getMemoryAccess(MemSet), + MSSA->getMemoryAccess(MemCpy))) { + return false; + } + } else { + // We have already checked that dst up to src_size is not accessed. We + // need to make sure that there are no accesses up to dst_size either. + MemDepResult DstDepInfo = MD->getPointerDependencyFrom( + MemoryLocation::getForDest(MemSet), false, MemCpy->getIterator(), + MemCpy->getParent()); + if (DstDepInfo.getInst() != MemSet) + return false; + } + // Use the same i8* dest as the memcpy, killing the memset dest if different. Value *Dest = MemCpy->getRawDest(); Value *DestSize = MemSet->getLength(); Value *SrcSize = MemCpy->getLength(); + if (mayBeVisibleThroughUnwinding(Dest, MemSet, MemCpy)) + return false; + // By default, create an unaligned memset. unsigned Align = 1; // If Dest is aligned, and SrcSize is constant, use the minimum alignment @@ -1016,13 +1197,25 @@ bool MemCpyOptPass::processMemSetMemCpyDependence(MemCpyInst *MemCpy, Value *SizeDiff = Builder.CreateSub(DestSize, SrcSize); Value *MemsetLen = Builder.CreateSelect( Ule, ConstantInt::getNullValue(DestSize->getType()), SizeDiff); - Builder.CreateMemSet( + Instruction *NewMemSet = Builder.CreateMemSet( Builder.CreateGEP(Dest->getType()->getPointerElementType(), Dest, SrcSize), MemSet->getOperand(1), MemsetLen, MaybeAlign(Align)); - MD->removeInstruction(MemSet); - MemSet->eraseFromParent(); + if (MSSAU) { + assert(isa(MSSAU->getMemorySSA()->getMemoryAccess(MemCpy)) && + "MemCpy must be a MemoryDef"); + // The new memset is inserted after the memcpy, but it is known that its + // defining access is the memset about to be removed which immediately + // precedes the memcpy. + auto *LastDef = + cast(MSSAU->getMemorySSA()->getMemoryAccess(MemCpy)); + auto *NewAccess = MSSAU->createMemoryAccessBefore( + NewMemSet, LastDef->getDefiningAccess(), LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } + + eraseInstruction(MemSet); return true; } @@ -1041,6 +1234,24 @@ static bool hasUndefContents(Instruction *I, ConstantInt *Size) { return false; } +static bool hasUndefContentsMSSA(MemorySSA *MSSA, AliasAnalysis *AA, Value *V, + MemoryDef *Def, ConstantInt *Size) { + if (MSSA->isLiveOnEntryDef(Def)) + return isa(getUnderlyingObject(V)); + + if (IntrinsicInst *II = + dyn_cast_or_null(Def->getMemoryInst())) { + if (II->getIntrinsicID() == Intrinsic::lifetime_start) { + ConstantInt *LTSize = cast(II->getArgOperand(0)); + if (AA->isMustAlias(V, II->getArgOperand(1)) && + LTSize->getZExtValue() >= Size->getZExtValue()) + return true; + } + } + + return false; +} + /// Transform memcpy to memset when its source was just memset. /// In other words, turn: /// \code @@ -1057,11 +1268,9 @@ static bool hasUndefContents(Instruction *I, ConstantInt *Size) { /// The \p MemCpy must have a Constant length. bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy, MemSetInst *MemSet) { - AliasAnalysis &AA = LookupAliasAnalysis(); - // Make sure that memcpy(..., memset(...), ...), that is we are memsetting and // memcpying from the same address. Otherwise it is hard to reason about. - if (!AA.isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource())) + if (!AA->isMustAlias(MemSet->getRawDest(), MemCpy->getRawSource())) return false; // A known memset size is required. @@ -1078,17 +1287,37 @@ bool MemCpyOptPass::performMemCpyToMemSetOptzn(MemCpyInst *MemCpy, // interested in the bytes from MemSetSize..CopySize here, but as we can't // easily represent this location, we use the full 0..CopySize range. MemoryLocation MemCpyLoc = MemoryLocation::getForSource(MemCpy); - MemDepResult DepInfo = MD->getPointerDependencyFrom( - MemCpyLoc, true, MemSet->getIterator(), MemSet->getParent()); - if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize)) - CopySize = MemSetSize; - else + bool CanReduceSize = false; + if (EnableMemorySSA) { + MemoryUseOrDef *MemSetAccess = MSSA->getMemoryAccess(MemSet); + MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess( + MemSetAccess->getDefiningAccess(), MemCpyLoc); + if (auto *MD = dyn_cast(Clobber)) + if (hasUndefContentsMSSA(MSSA, AA, MemCpy->getSource(), MD, CopySize)) + CanReduceSize = true; + } else { + MemDepResult DepInfo = MD->getPointerDependencyFrom( + MemCpyLoc, true, MemSet->getIterator(), MemSet->getParent()); + if (DepInfo.isDef() && hasUndefContents(DepInfo.getInst(), CopySize)) + CanReduceSize = true; + } + + if (!CanReduceSize) return false; + CopySize = MemSetSize; } IRBuilder<> Builder(MemCpy); - Builder.CreateMemSet(MemCpy->getRawDest(), MemSet->getOperand(1), CopySize, - MaybeAlign(MemCpy->getDestAlignment())); + Instruction *NewM = + Builder.CreateMemSet(MemCpy->getRawDest(), MemSet->getOperand(1), + CopySize, MaybeAlign(MemCpy->getDestAlignment())); + if (MSSAU) { + auto *LastDef = + cast(MSSAU->getMemorySSA()->getMemoryAccess(MemCpy)); + auto *NewAccess = MSSAU->createMemoryAccessAfter(NewM, LastDef, LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } + return true; } @@ -1104,8 +1333,7 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) { // If the source and destination of the memcpy are the same, then zap it. if (M->getSource() == M->getDest()) { ++BBI; - MD->removeInstruction(M); - M->eraseFromParent(); + eraseInstruction(M); return true; } @@ -1115,73 +1343,156 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) { if (Value *ByteVal = isBytewiseValue(GV->getInitializer(), M->getModule()->getDataLayout())) { IRBuilder<> Builder(M); - Builder.CreateMemSet(M->getRawDest(), ByteVal, M->getLength(), - MaybeAlign(M->getDestAlignment()), false); - MD->removeInstruction(M); - M->eraseFromParent(); + Instruction *NewM = + Builder.CreateMemSet(M->getRawDest(), ByteVal, M->getLength(), + MaybeAlign(M->getDestAlignment()), false); + if (MSSAU) { + auto *LastDef = + cast(MSSAU->getMemorySSA()->getMemoryAccess(M)); + auto *NewAccess = + MSSAU->createMemoryAccessAfter(NewM, LastDef, LastDef); + MSSAU->insertDef(cast(NewAccess), /*RenameUses=*/true); + } + + eraseInstruction(M); ++NumCpyToSet; return true; } - MemDepResult DepInfo = MD->getDependency(M); - - // Try to turn a partially redundant memset + memcpy into - // memcpy + smaller memset. We don't need the memcpy size for this. - if (DepInfo.isClobber()) - if (MemSetInst *MDep = dyn_cast(DepInfo.getInst())) - if (processMemSetMemCpyDependence(M, MDep)) - return true; + if (EnableMemorySSA) { + MemoryUseOrDef *MA = MSSA->getMemoryAccess(M); + MemoryAccess *AnyClobber = MSSA->getWalker()->getClobberingMemoryAccess(MA); + MemoryLocation DestLoc = MemoryLocation::getForDest(M); + const MemoryAccess *DestClobber = + MSSA->getWalker()->getClobberingMemoryAccess(AnyClobber, DestLoc); + + // Try to turn a partially redundant memset + memcpy into + // memcpy + smaller memset. We don't need the memcpy size for this. + // The memcpy most post-dom the memset, so limit this to the same basic + // block. A non-local generalization is likely not worthwhile. + if (auto *MD = dyn_cast(DestClobber)) + if (auto *MDep = dyn_cast_or_null(MD->getMemoryInst())) + if (DestClobber->getBlock() == M->getParent()) + if (processMemSetMemCpyDependence(M, MDep)) + return true; + + // The optimizations after this point require the memcpy size. + ConstantInt *CopySize = dyn_cast(M->getLength()); + if (!CopySize) return false; + + MemoryAccess *SrcClobber = MSSA->getWalker()->getClobberingMemoryAccess( + AnyClobber, MemoryLocation::getForSource(M)); + + // There are four possible optimizations we can do for memcpy: + // a) memcpy-memcpy xform which exposes redundance for DSE. + // b) call-memcpy xform for return slot optimization. + // c) memcpy from freshly alloca'd space or space that has just started + // its lifetime copies undefined data, and we can therefore eliminate + // the memcpy in favor of the data that was already at the destination. + // d) memcpy from a just-memset'd source can be turned into memset. + if (auto *MD = dyn_cast(SrcClobber)) { + if (Instruction *MI = MD->getMemoryInst()) { + if (auto *C = dyn_cast(MI)) { + // The memcpy must post-dom the call. Limit to the same block for now. + // Additionally, we need to ensure that there are no accesses to dest + // between the call and the memcpy. Accesses to src will be checked + // by performCallSlotOptzn(). + // TODO: Support non-local call-slot optimization? + if (C->getParent() == M->getParent() && + !accessedBetween(*AA, DestLoc, MD, MA)) { + // FIXME: Can we pass in either of dest/src alignment here instead + // of conservatively taking the minimum? + Align Alignment = std::min(M->getDestAlign().valueOrOne(), + M->getSourceAlign().valueOrOne()); + if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(), + CopySize->getZExtValue(), Alignment, C)) { + LLVM_DEBUG(dbgs() << "Performed call slot optimization:\n" + << " call: " << *C << "\n" + << " memcpy: " << *M << "\n"); + eraseInstruction(M); + ++NumMemCpyInstr; + return true; + } + } + } + if (auto *MDep = dyn_cast(MI)) + return processMemCpyMemCpyDependence(M, MDep); + if (auto *MDep = dyn_cast(MI)) { + if (performMemCpyToMemSetOptzn(M, MDep)) { + LLVM_DEBUG(dbgs() << "Converted memcpy to memset\n"); + eraseInstruction(M); + ++NumCpyToSet; + return true; + } + } + } - // The optimizations after this point require the memcpy size. - ConstantInt *CopySize = dyn_cast(M->getLength()); - if (!CopySize) return false; - - // There are four possible optimizations we can do for memcpy: - // a) memcpy-memcpy xform which exposes redundance for DSE. - // b) call-memcpy xform for return slot optimization. - // c) memcpy from freshly alloca'd space or space that has just started its - // lifetime copies undefined data, and we can therefore eliminate the - // memcpy in favor of the data that was already at the destination. - // d) memcpy from a just-memset'd source can be turned into memset. - if (DepInfo.isClobber()) { - if (CallInst *C = dyn_cast(DepInfo.getInst())) { - // FIXME: Can we pass in either of dest/src alignment here instead - // of conservatively taking the minimum? - Align Alignment = std::min(M->getDestAlign().valueOrOne(), - M->getSourceAlign().valueOrOne()); - if (performCallSlotOptzn(M, M->getDest(), M->getSource(), - CopySize->getZExtValue(), Alignment, C)) { - MD->removeInstruction(M); - M->eraseFromParent(); + if (hasUndefContentsMSSA(MSSA, AA, M->getSource(), MD, CopySize)) { + LLVM_DEBUG(dbgs() << "Removed memcpy from undef\n"); + eraseInstruction(M); + ++NumMemCpyInstr; return true; } } - } + } else { + MemDepResult DepInfo = MD->getDependency(M); - MemoryLocation SrcLoc = MemoryLocation::getForSource(M); - MemDepResult SrcDepInfo = MD->getPointerDependencyFrom( - SrcLoc, true, M->getIterator(), M->getParent()); - - if (SrcDepInfo.isClobber()) { - if (MemCpyInst *MDep = dyn_cast(SrcDepInfo.getInst())) - return processMemCpyMemCpyDependence(M, MDep); - } else if (SrcDepInfo.isDef()) { - if (hasUndefContents(SrcDepInfo.getInst(), CopySize)) { - MD->removeInstruction(M); - M->eraseFromParent(); - ++NumMemCpyInstr; - return true; + // Try to turn a partially redundant memset + memcpy into + // memcpy + smaller memset. We don't need the memcpy size for this. + if (DepInfo.isClobber()) + if (MemSetInst *MDep = dyn_cast(DepInfo.getInst())) + if (processMemSetMemCpyDependence(M, MDep)) + return true; + + // The optimizations after this point require the memcpy size. + ConstantInt *CopySize = dyn_cast(M->getLength()); + if (!CopySize) return false; + + // There are four possible optimizations we can do for memcpy: + // a) memcpy-memcpy xform which exposes redundance for DSE. + // b) call-memcpy xform for return slot optimization. + // c) memcpy from freshly alloca'd space or space that has just started + // its lifetime copies undefined data, and we can therefore eliminate + // the memcpy in favor of the data that was already at the destination. + // d) memcpy from a just-memset'd source can be turned into memset. + if (DepInfo.isClobber()) { + if (CallInst *C = dyn_cast(DepInfo.getInst())) { + // FIXME: Can we pass in either of dest/src alignment here instead + // of conservatively taking the minimum? + Align Alignment = std::min(M->getDestAlign().valueOrOne(), + M->getSourceAlign().valueOrOne()); + if (performCallSlotOptzn(M, M, M->getDest(), M->getSource(), + CopySize->getZExtValue(), Alignment, C)) { + eraseInstruction(M); + ++NumMemCpyInstr; + return true; + } + } } - } - if (SrcDepInfo.isClobber()) - if (MemSetInst *MDep = dyn_cast(SrcDepInfo.getInst())) - if (performMemCpyToMemSetOptzn(M, MDep)) { - MD->removeInstruction(M); - M->eraseFromParent(); - ++NumCpyToSet; + MemoryLocation SrcLoc = MemoryLocation::getForSource(M); + MemDepResult SrcDepInfo = MD->getPointerDependencyFrom( + SrcLoc, true, M->getIterator(), M->getParent()); + + if (SrcDepInfo.isClobber()) { + if (MemCpyInst *MDep = dyn_cast(SrcDepInfo.getInst())) + return processMemCpyMemCpyDependence(M, MDep); + } else if (SrcDepInfo.isDef()) { + if (hasUndefContents(SrcDepInfo.getInst(), CopySize)) { + eraseInstruction(M); + ++NumMemCpyInstr; return true; } + } + + if (SrcDepInfo.isClobber()) + if (MemSetInst *MDep = dyn_cast(SrcDepInfo.getInst())) + if (performMemCpyToMemSetOptzn(M, MDep)) { + eraseInstruction(M); + ++NumCpyToSet; + return true; + } + } return false; } @@ -1189,14 +1500,12 @@ bool MemCpyOptPass::processMemCpy(MemCpyInst *M, BasicBlock::iterator &BBI) { /// Transforms memmove calls to memcpy calls when the src/dst are guaranteed /// not to alias. bool MemCpyOptPass::processMemMove(MemMoveInst *M) { - AliasAnalysis &AA = LookupAliasAnalysis(); - if (!TLI->has(LibFunc_memmove)) return false; // See if the pointers alias. - if (!AA.isNoAlias(MemoryLocation::getForDest(M), - MemoryLocation::getForSource(M))) + if (!AA->isNoAlias(MemoryLocation::getForDest(M), + MemoryLocation::getForSource(M))) return false; LLVM_DEBUG(dbgs() << "MemCpyOptPass: Optimizing memmove -> memcpy: " << *M @@ -1209,9 +1518,13 @@ bool MemCpyOptPass::processMemMove(MemMoveInst *M) { M->setCalledFunction(Intrinsic::getDeclaration(M->getModule(), Intrinsic::memcpy, ArgTys)); + // For MemorySSA nothing really changes (except that memcpy may imply stricter + // aliasing guarantees). + // MemDep may have over conservative information about this instruction, just // conservatively flush it from the cache. - MD->removeInstruction(M); + if (MD) + MD->removeInstruction(M); ++NumMoveToCpy; return true; @@ -1224,16 +1537,25 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) { Value *ByValArg = CB.getArgOperand(ArgNo); Type *ByValTy = cast(ByValArg->getType())->getElementType(); uint64_t ByValSize = DL.getTypeAllocSize(ByValTy); - MemDepResult DepInfo = MD->getPointerDependencyFrom( - MemoryLocation(ByValArg, LocationSize::precise(ByValSize)), true, - CB.getIterator(), CB.getParent()); - if (!DepInfo.isClobber()) - return false; + MemoryLocation Loc(ByValArg, LocationSize::precise(ByValSize)); + MemCpyInst *MDep = nullptr; + if (EnableMemorySSA) { + MemoryUseOrDef *CallAccess = MSSA->getMemoryAccess(&CB); + MemoryAccess *Clobber = MSSA->getWalker()->getClobberingMemoryAccess( + CallAccess->getDefiningAccess(), Loc); + if (auto *MD = dyn_cast(Clobber)) + MDep = dyn_cast_or_null(MD->getMemoryInst()); + } else { + MemDepResult DepInfo = MD->getPointerDependencyFrom( + Loc, true, CB.getIterator(), CB.getParent()); + if (!DepInfo.isClobber()) + return false; + MDep = dyn_cast(DepInfo.getInst()); + } // If the byval argument isn't fed by a memcpy, ignore it. If it is fed by // a memcpy, see if we can byval from the source of the memcpy instead of the // result. - MemCpyInst *MDep = dyn_cast(DepInfo.getInst()); if (!MDep || MDep->isVolatile() || ByValArg->stripPointerCasts() != MDep->getDest()) return false; @@ -1250,12 +1572,10 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) { // If it is greater than the memcpy, then we check to see if we can force the // source of the memcpy to the alignment we need. If we fail, we bail out. - AssumptionCache &AC = LookupAssumptionCache(); - DominatorTree &DT = LookupDomTree(); MaybeAlign MemDepAlign = MDep->getSourceAlign(); if ((!MemDepAlign || *MemDepAlign < *ByValAlign) && - getOrEnforceKnownAlignment(MDep->getSource(), ByValAlign, DL, &CB, &AC, - &DT) < *ByValAlign) + getOrEnforceKnownAlignment(MDep->getSource(), ByValAlign, DL, &CB, AC, + DT) < *ByValAlign) return false; // The address space of the memcpy source must match the byval argument @@ -1269,14 +1589,19 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) { // *b = 42; // foo(*a) // It would be invalid to transform the second memcpy into foo(*b). - // - // NOTE: This is conservative, it will stop on any read from the source loc, - // not just the defining memcpy. - MemDepResult SourceDep = MD->getPointerDependencyFrom( - MemoryLocation::getForSource(MDep), false, - CB.getIterator(), MDep->getParent()); - if (!SourceDep.isClobber() || SourceDep.getInst() != MDep) - return false; + if (EnableMemorySSA) { + if (writtenBetween(MSSA, MemoryLocation::getForSource(MDep), + MSSA->getMemoryAccess(MDep), MSSA->getMemoryAccess(&CB))) + return false; + } else { + // NOTE: This is conservative, it will stop on any read from the source loc, + // not just the defining memcpy. + MemDepResult SourceDep = MD->getPointerDependencyFrom( + MemoryLocation::getForSource(MDep), false, + CB.getIterator(), MDep->getParent()); + if (!SourceDep.isClobber() || SourceDep.getInst() != MDep) + return false; + } Value *TmpCast = MDep->getSource(); if (MDep->getSource()->getType() != ByValArg->getType()) { @@ -1301,15 +1626,13 @@ bool MemCpyOptPass::processByValArgument(CallBase &CB, unsigned ArgNo) { bool MemCpyOptPass::iterateOnFunction(Function &F) { bool MadeChange = false; - DominatorTree &DT = LookupDomTree(); - // Walk all instruction in the function. for (BasicBlock &BB : F) { // Skip unreachable blocks. For example processStore assumes that an // instruction in a BB can't be dominated by a later instruction in the // same BB (which is a scenario that can happen for an unreachable BB that // has itself as a predecessor). - if (!DT.isReachableFromEntry(&BB)) + if (!DT->isReachableFromEntry(&BB)) continue; for (BasicBlock::iterator BI = BB.begin(), BE = BB.end(); BI != BE;) { @@ -1345,43 +1668,43 @@ bool MemCpyOptPass::iterateOnFunction(Function &F) { } PreservedAnalyses MemCpyOptPass::run(Function &F, FunctionAnalysisManager &AM) { - auto &MD = AM.getResult(F); + auto *MD = !EnableMemorySSA ? &AM.getResult(F) + : AM.getCachedResult(F); auto &TLI = AM.getResult(F); - - auto LookupAliasAnalysis = [&]() -> AliasAnalysis & { - return AM.getResult(F); - }; - auto LookupAssumptionCache = [&]() -> AssumptionCache & { - return AM.getResult(F); - }; - auto LookupDomTree = [&]() -> DominatorTree & { - return AM.getResult(F); - }; - - bool MadeChange = runImpl(F, &MD, &TLI, LookupAliasAnalysis, - LookupAssumptionCache, LookupDomTree); + auto *AA = &AM.getResult(F); + auto *AC = &AM.getResult(F); + auto *DT = &AM.getResult(F); + auto *MSSA = EnableMemorySSA ? &AM.getResult(F) + : AM.getCachedResult(F); + + bool MadeChange = + runImpl(F, MD, &TLI, AA, AC, DT, MSSA ? &MSSA->getMSSA() : nullptr); if (!MadeChange) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserveSet(); PA.preserve(); - PA.preserve(); + if (MD) + PA.preserve(); + if (MSSA) + PA.preserve(); return PA; } -bool MemCpyOptPass::runImpl( - Function &F, MemoryDependenceResults *MD_, TargetLibraryInfo *TLI_, - std::function LookupAliasAnalysis_, - std::function LookupAssumptionCache_, - std::function LookupDomTree_) { +bool MemCpyOptPass::runImpl(Function &F, MemoryDependenceResults *MD_, + TargetLibraryInfo *TLI_, AliasAnalysis *AA_, + AssumptionCache *AC_, DominatorTree *DT_, + MemorySSA *MSSA_) { bool MadeChange = false; MD = MD_; TLI = TLI_; - LookupAliasAnalysis = std::move(LookupAliasAnalysis_); - LookupAssumptionCache = std::move(LookupAssumptionCache_); - LookupDomTree = std::move(LookupDomTree_); - + AA = AA_; + AC = AC_; + DT = DT_; + MSSA = MSSA_; + MemorySSAUpdater MSSAU_(MSSA_); + MSSAU = MSSA_ ? &MSSAU_ : nullptr; // If we don't have at least memset and memcpy, there is little point of doing // anything here. These are required by a freestanding implementation, so if // even they are disabled, there is no point in trying hard. @@ -1394,6 +1717,9 @@ bool MemCpyOptPass::runImpl( MadeChange = true; } + if (MSSA_ && VerifyMemorySSA) + MSSA_->verifyMemorySSA(); + MD = nullptr; return MadeChange; } @@ -1403,19 +1729,17 @@ bool MemCpyOptLegacyPass::runOnFunction(Function &F) { if (skipFunction(F)) return false; - auto *MD = &getAnalysis().getMemDep(); + auto *MDWP = !EnableMemorySSA + ? &getAnalysis() + : getAnalysisIfAvailable(); auto *TLI = &getAnalysis().getTLI(F); - - auto LookupAliasAnalysis = [this]() -> AliasAnalysis & { - return getAnalysis().getAAResults(); - }; - auto LookupAssumptionCache = [this, &F]() -> AssumptionCache & { - return getAnalysis().getAssumptionCache(F); - }; - auto LookupDomTree = [this]() -> DominatorTree & { - return getAnalysis().getDomTree(); - }; - - return Impl.runImpl(F, MD, TLI, LookupAliasAnalysis, LookupAssumptionCache, - LookupDomTree); + auto *AA = &getAnalysis().getAAResults(); + auto *AC = &getAnalysis().getAssumptionCache(F); + auto *DT = &getAnalysis().getDomTree(); + auto *MSSAWP = EnableMemorySSA + ? &getAnalysis() + : getAnalysisIfAvailable(); + + return Impl.runImpl(F, MDWP ? & MDWP->getMemDep() : nullptr, TLI, AA, AC, DT, + MSSAWP ? &MSSAWP->getMSSA() : nullptr); } diff --git a/llvm/lib/Transforms/Scalar/MergeICmps.cpp b/llvm/lib/Transforms/Scalar/MergeICmps.cpp index ce1e142101b8..7f8b75ac8806 100644 --- a/llvm/lib/Transforms/Scalar/MergeICmps.cpp +++ b/llvm/lib/Transforms/Scalar/MergeICmps.cpp @@ -372,7 +372,7 @@ BCECmpBlock visitCmpBlock(Value *const Val, BasicBlock *const Block, } else { // In this case, we expect a constant incoming value (the comparison is // chained). - const auto *const Const = dyn_cast(Val); + const auto *const Const = cast(Val); LLVM_DEBUG(dbgs() << "const\n"); if (!Const->isZero()) return {}; LLVM_DEBUG(dbgs() << "false\n"); @@ -624,6 +624,17 @@ static BasicBlock *mergeComparisons(ArrayRef Comparisons, Value *IsEqual = nullptr; LLVM_DEBUG(dbgs() << "Merging " << Comparisons.size() << " comparisons -> " << BB->getName() << "\n"); + + // If there is one block that requires splitting, we do it now, i.e. + // just before we know we will collapse the chain. The instructions + // can be executed before any of the instructions in the chain. + const auto ToSplit = llvm::find_if( + Comparisons, [](const BCECmpBlock &B) { return B.RequireSplit; }); + if (ToSplit != Comparisons.end()) { + LLVM_DEBUG(dbgs() << "Splitting non_BCE work to header\n"); + ToSplit->split(BB, AA); + } + if (Comparisons.size() == 1) { LLVM_DEBUG(dbgs() << "Only one comparison, updating branches\n"); Value *const LhsLoad = @@ -633,17 +644,6 @@ static BasicBlock *mergeComparisons(ArrayRef Comparisons, // There are no blocks to merge, just do the comparison. IsEqual = Builder.CreateICmpEQ(LhsLoad, RhsLoad); } else { - // If there is one block that requires splitting, we do it now, i.e. - // just before we know we will collapse the chain. The instructions - // can be executed before any of the instructions in the chain. - const auto ToSplit = - std::find_if(Comparisons.begin(), Comparisons.end(), - [](const BCECmpBlock &B) { return B.RequireSplit; }); - if (ToSplit != Comparisons.end()) { - LLVM_DEBUG(dbgs() << "Splitting non_BCE work to header\n"); - ToSplit->split(BB, AA); - } - const unsigned TotalSizeBits = std::accumulate( Comparisons.begin(), Comparisons.end(), 0u, [](int Size, const BCECmpBlock &C) { return Size + C.SizeBits(); }); diff --git a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp index 4e010f8704d0..32bb62129e8f 100644 --- a/llvm/lib/Transforms/Scalar/NaryReassociate.cpp +++ b/llvm/lib/Transforms/Scalar/NaryReassociate.cpp @@ -213,54 +213,33 @@ bool NaryReassociatePass::runImpl(Function &F, AssumptionCache *AC_, return Changed; } -// Explicitly list the instruction types NaryReassociate handles for now. -static bool isPotentiallyNaryReassociable(Instruction *I) { - switch (I->getOpcode()) { - case Instruction::Add: - case Instruction::GetElementPtr: - case Instruction::Mul: - return true; - default: - return false; - } -} - bool NaryReassociatePass::doOneIteration(Function &F) { bool Changed = false; SeenExprs.clear(); // Process the basic blocks in a depth first traversal of the dominator // tree. This order ensures that all bases of a candidate are in Candidates // when we process it. + SmallVector DeadInsts; for (const auto Node : depth_first(DT)) { BasicBlock *BB = Node->getBlock(); for (auto I = BB->begin(); I != BB->end(); ++I) { - if (SE->isSCEVable(I->getType()) && isPotentiallyNaryReassociable(&*I)) { - const SCEV *OldSCEV = SE->getSCEV(&*I); - if (Instruction *NewI = tryReassociate(&*I)) { - Changed = true; - SE->forgetValue(&*I); - I->replaceAllUsesWith(NewI); - WeakVH NewIExist = NewI; - // If SeenExprs/NewIExist contains I's WeakTrackingVH/WeakVH, that - // entry will be replaced with nullptr if deleted. - RecursivelyDeleteTriviallyDeadInstructions(&*I, TLI); - if (!NewIExist) { - // Rare occation where the new instruction (NewI) have been removed, - // probably due to parts of the input code was dead from the - // beginning, reset the iterator and start over from the beginning - I = BB->begin(); - continue; - } - I = NewI->getIterator(); - } - // Add the rewritten instruction to SeenExprs; the original instruction - // is deleted. - const SCEV *NewSCEV = SE->getSCEV(&*I); - SeenExprs[NewSCEV].push_back(WeakTrackingVH(&*I)); + Instruction *OrigI = &*I; + const SCEV *OrigSCEV = nullptr; + if (Instruction *NewI = tryReassociate(OrigI, OrigSCEV)) { + Changed = true; + OrigI->replaceAllUsesWith(NewI); + + // Add 'OrigI' to the list of dead instructions. + DeadInsts.push_back(WeakTrackingVH(OrigI)); + // Add the rewritten instruction to SeenExprs; the original + // instruction is deleted. + const SCEV *NewSCEV = SE->getSCEV(NewI); + SeenExprs[NewSCEV].push_back(WeakTrackingVH(NewI)); + // Ideally, NewSCEV should equal OldSCEV because tryReassociate(I) // is equivalent to I. However, ScalarEvolution::getSCEV may - // weaken nsw causing NewSCEV not to equal OldSCEV. For example, suppose - // we reassociate + // weaken nsw causing NewSCEV not to equal OldSCEV. For example, + // suppose we reassociate // I = &a[sext(i +nsw j)] // assuming sizeof(a[0]) = 4 // to // NewI = &a[sext(i)] + sext(j). @@ -274,32 +253,47 @@ bool NaryReassociatePass::doOneIteration(Function &F) { // equivalence, we add I to SeenExprs[OldSCEV] as well so that we can // map both SCEV before and after tryReassociate(I) to I. // - // This improvement is exercised in @reassociate_gep_nsw in nary-gep.ll. - if (NewSCEV != OldSCEV) - SeenExprs[OldSCEV].push_back(WeakTrackingVH(&*I)); - } + // This improvement is exercised in @reassociate_gep_nsw in + // nary-gep.ll. + if (NewSCEV != OrigSCEV) + SeenExprs[OrigSCEV].push_back(WeakTrackingVH(NewI)); + } else if (OrigSCEV) + SeenExprs[OrigSCEV].push_back(WeakTrackingVH(OrigI)); } } + // Delete all dead instructions from 'DeadInsts'. + // Please note ScalarEvolution is updated along the way. + RecursivelyDeleteTriviallyDeadInstructionsPermissive( + DeadInsts, TLI, nullptr, [this](Value *V) { SE->forgetValue(V); }); + return Changed; } -Instruction *NaryReassociatePass::tryReassociate(Instruction *I) { +Instruction *NaryReassociatePass::tryReassociate(Instruction * I, + const SCEV *&OrigSCEV) { + + if (!SE->isSCEVable(I->getType())) + return nullptr; + switch (I->getOpcode()) { case Instruction::Add: case Instruction::Mul: + OrigSCEV = SE->getSCEV(I); return tryReassociateBinaryOp(cast(I)); case Instruction::GetElementPtr: + OrigSCEV = SE->getSCEV(I); return tryReassociateGEP(cast(I)); default: - llvm_unreachable("should be filtered out by isPotentiallyNaryReassociable"); + return nullptr; } + + llvm_unreachable("should not be reached"); + return nullptr; } static bool isGEPFoldable(GetElementPtrInst *GEP, const TargetTransformInfo *TTI) { - SmallVector Indices; - for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I) - Indices.push_back(*I); + SmallVector Indices(GEP->indices()); return TTI->getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(), Indices) == TargetTransformInfo::TCC_Free; } @@ -375,8 +369,8 @@ NaryReassociatePass::tryReassociateGEPAtIndex(GetElementPtrInst *GEP, // Replace the I-th index with LHS. IndexExprs[I] = SE->getSCEV(LHS); if (isKnownNonNegative(LHS, *DL, 0, AC, GEP, DT) && - DL->getTypeSizeInBits(LHS->getType()) < - DL->getTypeSizeInBits(GEP->getOperand(I)->getType())) { + DL->getTypeSizeInBits(LHS->getType()).getFixedSize() < + DL->getTypeSizeInBits(GEP->getOperand(I)->getType()).getFixedSize()) { // Zero-extend LHS if it is non-negative. InstCombine canonicalizes sext to // zext if the source operand is proved non-negative. We should do that // consistently so that CandidateExpr more likely appears before. See diff --git a/llvm/lib/Transforms/Scalar/NewGVN.cpp b/llvm/lib/Transforms/Scalar/NewGVN.cpp index 0ed1773373a7..281d47c8625f 100644 --- a/llvm/lib/Transforms/Scalar/NewGVN.cpp +++ b/llvm/lib/Transforms/Scalar/NewGVN.cpp @@ -662,7 +662,8 @@ public: const DataLayout &DL) : F(F), DT(DT), TLI(TLI), AA(AA), MSSA(MSSA), AC(AC), DL(DL), PredInfo(std::make_unique(F, *DT, *AC)), - SQ(DL, TLI, DT, AC, /*CtxI=*/nullptr, /*UseInstrInfo=*/false) {} + SQ(DL, TLI, DT, AC, /*CtxI=*/nullptr, /*UseInstrInfo=*/false, + /*CanUseUndef=*/false) {} bool runGVN(); @@ -800,12 +801,7 @@ private: Value *findPHIOfOpsLeader(const Expression *, const Instruction *, const BasicBlock *) const; - // New instruction creation. - void handleNewInstruction(Instruction *) {} - // Various instruction touch utilities - template - void for_each_found(Map &, const KeyType &, Func); template void touchAndErase(Map &, const KeyType &); void markUsersTouched(Value *); @@ -834,7 +830,6 @@ private: BasicBlock *getBlockForValue(Value *V) const; void deleteExpression(const Expression *E) const; MemoryUseOrDef *getMemoryAccess(const Instruction *) const; - MemoryAccess *getDefiningAccess(const MemoryAccess *) const; MemoryPhi *getMemoryAccess(const BasicBlock *) const; template T *getMinDFSOfRange(const Range &) const; @@ -1253,6 +1248,7 @@ const UnknownExpression *NewGVN::createUnknownExpression(Instruction *I) const { const CallExpression * NewGVN::createCallExpression(CallInst *CI, const MemoryAccess *MA) const { // FIXME: Add operand bundles for calls. + // FIXME: Allow commutative matching for intrinsics. auto *E = new (ExpressionAllocator) CallExpression(CI->getNumOperands(), CI, MA); setBasicExpressionInfo(CI, E); @@ -1539,90 +1535,39 @@ NewGVN::performSymbolicPredicateInfoEvaluation(Instruction *I) const { LLVM_DEBUG(dbgs() << "Found predicate info from instruction !\n"); - auto *PWC = dyn_cast(PI); - if (!PWC) + const Optional &Constraint = PI->getConstraint(); + if (!Constraint) return nullptr; - auto *CopyOf = I->getOperand(0); - auto *Cond = PWC->Condition; - - // If this a copy of the condition, it must be either true or false depending - // on the predicate info type and edge. - if (CopyOf == Cond) { - // We should not need to add predicate users because the predicate info is - // already a use of this operand. - if (isa(PI)) - return createConstantExpression(ConstantInt::getTrue(Cond->getType())); - if (auto *PBranch = dyn_cast(PI)) { - if (PBranch->TrueEdge) - return createConstantExpression(ConstantInt::getTrue(Cond->getType())); - return createConstantExpression(ConstantInt::getFalse(Cond->getType())); - } - if (auto *PSwitch = dyn_cast(PI)) - return createConstantExpression(cast(PSwitch->CaseValue)); - } + CmpInst::Predicate Predicate = Constraint->Predicate; + Value *CmpOp0 = I->getOperand(0); + Value *CmpOp1 = Constraint->OtherOp; - // Not a copy of the condition, so see what the predicates tell us about this - // value. First, though, we check to make sure the value is actually a copy - // of one of the condition operands. It's possible, in certain cases, for it - // to be a copy of a predicateinfo copy. In particular, if two branch - // operations use the same condition, and one branch dominates the other, we - // will end up with a copy of a copy. This is currently a small deficiency in - // predicateinfo. What will end up happening here is that we will value - // number both copies the same anyway. - - // Everything below relies on the condition being a comparison. - auto *Cmp = dyn_cast(Cond); - if (!Cmp) - return nullptr; + Value *FirstOp = lookupOperandLeader(CmpOp0); + Value *SecondOp = lookupOperandLeader(CmpOp1); + Value *AdditionallyUsedValue = CmpOp0; - if (CopyOf != Cmp->getOperand(0) && CopyOf != Cmp->getOperand(1)) { - LLVM_DEBUG(dbgs() << "Copy is not of any condition operands!\n"); - return nullptr; - } - Value *FirstOp = lookupOperandLeader(Cmp->getOperand(0)); - Value *SecondOp = lookupOperandLeader(Cmp->getOperand(1)); - bool SwappedOps = false; // Sort the ops. if (shouldSwapOperands(FirstOp, SecondOp)) { std::swap(FirstOp, SecondOp); - SwappedOps = true; + Predicate = CmpInst::getSwappedPredicate(Predicate); + AdditionallyUsedValue = CmpOp1; } - CmpInst::Predicate Predicate = - SwappedOps ? Cmp->getSwappedPredicate() : Cmp->getPredicate(); - - if (isa(PI)) { - // If we assume the operands are equal, then they are equal. - if (Predicate == CmpInst::ICMP_EQ) { - addPredicateUsers(PI, I); - addAdditionalUsers(SwappedOps ? Cmp->getOperand(1) : Cmp->getOperand(0), - I); - return createVariableOrConstant(FirstOp); - } + + if (Predicate == CmpInst::ICMP_EQ) { + addPredicateUsers(PI, I); + addAdditionalUsers(AdditionallyUsedValue, I); + return createVariableOrConstant(FirstOp); } - if (const auto *PBranch = dyn_cast(PI)) { - // If we are *not* a copy of the comparison, we may equal to the other - // operand when the predicate implies something about equality of - // operations. In particular, if the comparison is true/false when the - // operands are equal, and we are on the right edge, we know this operation - // is equal to something. - if ((PBranch->TrueEdge && Predicate == CmpInst::ICMP_EQ) || - (!PBranch->TrueEdge && Predicate == CmpInst::ICMP_NE)) { - addPredicateUsers(PI, I); - addAdditionalUsers(SwappedOps ? Cmp->getOperand(1) : Cmp->getOperand(0), - I); - return createVariableOrConstant(FirstOp); - } - // Handle the special case of floating point. - if (((PBranch->TrueEdge && Predicate == CmpInst::FCMP_OEQ) || - (!PBranch->TrueEdge && Predicate == CmpInst::FCMP_UNE)) && - isa(FirstOp) && !cast(FirstOp)->isZero()) { - addPredicateUsers(PI, I); - addAdditionalUsers(SwappedOps ? Cmp->getOperand(1) : Cmp->getOperand(0), - I); - return createConstantExpression(cast(FirstOp)); - } + + // Handle the special case of floating point. + if (Predicate == CmpInst::FCMP_OEQ && isa(FirstOp) && + !cast(FirstOp)->isZero()) { + addPredicateUsers(PI, I); + addAdditionalUsers(AdditionallyUsedValue, I); + return createConstantExpression(cast(FirstOp)); } + return nullptr; } @@ -2044,16 +1989,6 @@ NewGVN::performSymbolicEvaluation(Value *V, return E; } -// Look up a container in a map, and then call a function for each thing in the -// found container. -template -void NewGVN::for_each_found(Map &M, const KeyType &Key, Func F) { - const auto Result = M.find_as(Key); - if (Result != M.end()) - for (typename Map::mapped_type::value_type Mapped : Result->second) - F(Mapped); -} - // Look up a container of values/instructions in a map, and touch all the // instructions in the container. Then erase value from the map. template @@ -2941,8 +2876,7 @@ void NewGVN::cleanupTables() { } while (!TempInst.empty()) { - auto *I = TempInst.back(); - TempInst.pop_back(); + auto *I = TempInst.pop_back_val(); I->deleteValue(); } @@ -3437,10 +3371,9 @@ bool NewGVN::runGVN() { for (auto &B : RPOT) { auto *Node = DT->getNode(B); if (Node->getNumChildren() > 1) - llvm::sort(Node->begin(), Node->end(), - [&](const DomTreeNode *A, const DomTreeNode *B) { - return RPOOrdering[A] < RPOOrdering[B]; - }); + llvm::sort(*Node, [&](const DomTreeNode *A, const DomTreeNode *B) { + return RPOOrdering[A] < RPOOrdering[B]; + }); } // Now a standard depth first ordering of the domtree is equivalent to RPO. diff --git a/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp b/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp index 4553b23532f2..a110f7d5c241 100644 --- a/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp +++ b/llvm/lib/Transforms/Scalar/PlaceSafepoints.cpp @@ -243,7 +243,7 @@ static bool mustBeFiniteCountedLoop(Loop *L, ScalarEvolution *SE, BasicBlock *Pred) { // A conservative bound on the loop as a whole. const SCEV *MaxTrips = SE->getConstantMaxBackedgeTakenCount(L); - if (MaxTrips != SE->getCouldNotCompute() && + if (!isa(MaxTrips) && SE->getUnsignedRange(MaxTrips).getUnsignedMax().isIntN( CountedLoopTripWidth)) return true; @@ -255,7 +255,7 @@ static bool mustBeFiniteCountedLoop(Loop *L, ScalarEvolution *SE, // This returns an exact expression only. TODO: We really only need an // upper bound here, but SE doesn't expose that. const SCEV *MaxExec = SE->getExitCount(L, Pred); - if (MaxExec != SE->getCouldNotCompute() && + if (!isa(MaxExec) && SE->getUnsignedRange(MaxExec).getUnsignedMax().isIntN( CountedLoopTripWidth)) return true; @@ -435,7 +435,7 @@ static Instruction *findLocationForEntrySafepoint(Function &F, return Cursor; } -static const char *const GCSafepointPollName = "gc.safepoint_poll"; +const char GCSafepointPollName[] = "gc.safepoint_poll"; static bool isGCSafepointPoll(Function &F) { return F.getName().equals(GCSafepointPollName); @@ -589,8 +589,7 @@ bool PlaceSafepoints::runOnFunction(Function &F) { for (Instruction *PollLocation : PollsNeeded) { std::vector RuntimeCalls; InsertSafepointPoll(PollLocation, RuntimeCalls, TLI); - ParsePointNeeded.insert(ParsePointNeeded.end(), RuntimeCalls.begin(), - RuntimeCalls.end()); + llvm::append_range(ParsePointNeeded, RuntimeCalls); } return Modified; diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index ba7f367267fe..dffeb7cc227b 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -920,6 +920,100 @@ static Value *NegateValue(Value *V, Instruction *BI, return NewNeg; } +// See if this `or` looks like an load widening reduction, i.e. that it +// consists of an `or`/`shl`/`zext`/`load` nodes only. Note that we don't +// ensure that the pattern is *really* a load widening reduction, +// we do not ensure that it can really be replaced with a widened load, +// only that it mostly looks like one. +static bool isLoadCombineCandidate(Instruction *Or) { + SmallVector Worklist; + SmallSet Visited; + + auto Enqueue = [&](Value *V) { + auto *I = dyn_cast(V); + // Each node of an `or` reduction must be an instruction, + if (!I) + return false; // Node is certainly not part of an `or` load reduction. + // Only process instructions we have never processed before. + if (Visited.insert(I).second) + Worklist.emplace_back(I); + return true; // Will need to look at parent nodes. + }; + + if (!Enqueue(Or)) + return false; // Not an `or` reduction pattern. + + while (!Worklist.empty()) { + auto *I = Worklist.pop_back_val(); + + // Okay, which instruction is this node? + switch (I->getOpcode()) { + case Instruction::Or: + // Got an `or` node. That's fine, just recurse into it's operands. + for (Value *Op : I->operands()) + if (!Enqueue(Op)) + return false; // Not an `or` reduction pattern. + continue; + + case Instruction::Shl: + case Instruction::ZExt: + // `shl`/`zext` nodes are fine, just recurse into their base operand. + if (!Enqueue(I->getOperand(0))) + return false; // Not an `or` reduction pattern. + continue; + + case Instruction::Load: + // Perfect, `load` node means we've reached an edge of the graph. + continue; + + default: // Unknown node. + return false; // Not an `or` reduction pattern. + } + } + + return true; +} + +/// Return true if it may be profitable to convert this (X|Y) into (X+Y). +static bool ShouldConvertOrWithNoCommonBitsToAdd(Instruction *Or) { + // Don't bother to convert this up unless either the LHS is an associable add + // or subtract or mul or if this is only used by one of the above. + // This is only a compile-time improvement, it is not needed for correctness! + auto isInteresting = [](Value *V) { + for (auto Op : {Instruction::Add, Instruction::Sub, Instruction::Mul}) + if (isReassociableOp(V, Op)) + return true; + return false; + }; + + if (any_of(Or->operands(), isInteresting)) + return true; + + Value *VB = Or->user_back(); + if (Or->hasOneUse() && isInteresting(VB)) + return true; + + return false; +} + +/// If we have (X|Y), and iff X and Y have no common bits set, +/// transform this into (X+Y) to allow arithmetics reassociation. +static BinaryOperator *ConvertOrWithNoCommonBitsToAdd(Instruction *Or) { + // Convert an or into an add. + BinaryOperator *New = + CreateAdd(Or->getOperand(0), Or->getOperand(1), "", Or, Or); + New->setHasNoSignedWrap(); + New->setHasNoUnsignedWrap(); + New->takeName(Or); + + // Everyone now refers to the add instruction. + Or->replaceAllUsesWith(New); + New->setDebugLoc(Or->getDebugLoc()); + + LLVM_DEBUG(dbgs() << "Converted or into an add: " << *New << '\n'); + return New; +} + /// Return true if we should break up this subtract of X-Y into (X + -Y). static bool ShouldBreakUpSubtract(Instruction *Sub) { // If this is a negation, we can't split it up! @@ -1034,8 +1128,7 @@ static Value *EmitAddTreeOfValues(Instruction *I, SmallVectorImpl &Ops) { if (Ops.size() == 1) return Ops.back(); - Value *V1 = Ops.back(); - Ops.pop_back(); + Value *V1 = Ops.pop_back_val(); Value *V2 = EmitAddTreeOfValues(I, Ops); return CreateAdd(V2, V1, "reass.add", I, I); } @@ -1899,7 +1992,7 @@ Value *ReassociatePass::OptimizeExpression(BinaryOperator *I, void ReassociatePass::RecursivelyEraseDeadInsts(Instruction *I, OrderedSet &Insts) { assert(isInstructionTriviallyDead(I) && "Trivially dead instructions only!"); - SmallVector Ops(I->op_begin(), I->op_end()); + SmallVector Ops(I->operands()); ValueRankMap.erase(I); Insts.remove(I); RedoInsts.remove(I); @@ -1916,7 +2009,7 @@ void ReassociatePass::EraseInst(Instruction *I) { assert(isInstructionTriviallyDead(I) && "Trivially dead instructions only!"); LLVM_DEBUG(dbgs() << "Erasing dead inst: "; I->dump()); - SmallVector Ops(I->op_begin(), I->op_end()); + SmallVector Ops(I->operands()); // Erase the dead instruction. ValueRankMap.erase(I); RedoInsts.remove(I); @@ -2116,6 +2209,19 @@ void ReassociatePass::OptimizeInst(Instruction *I) { if (I->getType()->isIntegerTy(1)) return; + // If this is a bitwise or instruction of operands + // with no common bits set, convert it to X+Y. + if (I->getOpcode() == Instruction::Or && + ShouldConvertOrWithNoCommonBitsToAdd(I) && !isLoadCombineCandidate(I) && + haveNoCommonBitsSet(I->getOperand(0), I->getOperand(1), + I->getModule()->getDataLayout(), /*AC=*/nullptr, I, + /*DT=*/nullptr)) { + Instruction *NI = ConvertOrWithNoCommonBitsToAdd(I); + RedoInsts.insert(I); + MadeChange = true; + I = NI; + } + // If this is a subtract instruction which is not already in negate form, // see if we can convert it to X+-Y. if (I->getOpcode() == Instruction::Sub) { diff --git a/llvm/lib/Transforms/Scalar/Reg2Mem.cpp b/llvm/lib/Transforms/Scalar/Reg2Mem.cpp index 0716c1320982..a49b9ad3f62b 100644 --- a/llvm/lib/Transforms/Scalar/Reg2Mem.cpp +++ b/llvm/lib/Transforms/Scalar/Reg2Mem.cpp @@ -15,17 +15,23 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/Reg2Mem.h" #include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Utils.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" #include using namespace llvm; @@ -35,43 +41,17 @@ using namespace llvm; STATISTIC(NumRegsDemoted, "Number of registers demoted"); STATISTIC(NumPhisDemoted, "Number of phi-nodes demoted"); -namespace { - struct RegToMem : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - RegToMem() : FunctionPass(ID) { - initializeRegToMemPass(*PassRegistry::getPassRegistry()); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequiredID(BreakCriticalEdgesID); - AU.addPreservedID(BreakCriticalEdgesID); - } - - bool valueEscapes(const Instruction *Inst) const { - const BasicBlock *BB = Inst->getParent(); - for (const User *U : Inst->users()) { - const Instruction *UI = cast(U); - if (UI->getParent() != BB || isa(UI)) - return true; - } - return false; - } - - bool runOnFunction(Function &F) override; - }; +static bool valueEscapes(const Instruction &Inst) { + const BasicBlock *BB = Inst.getParent(); + for (const User *U : Inst.users()) { + const Instruction *UI = cast(U); + if (UI->getParent() != BB || isa(UI)) + return true; + } + return false; } -char RegToMem::ID = 0; -INITIALIZE_PASS_BEGIN(RegToMem, "reg2mem", "Demote all values to stack slots", - false, false) -INITIALIZE_PASS_DEPENDENCY(BreakCriticalEdges) -INITIALIZE_PASS_END(RegToMem, "reg2mem", "Demote all values to stack slots", - false, false) - -bool RegToMem::runOnFunction(Function &F) { - if (F.isDeclaration() || skipFunction(F)) - return false; - +static bool runPass(Function &F) { // Insert all new allocas into entry block. BasicBlock *BBEntry = &F.getEntryBlock(); assert(pred_empty(BBEntry) && @@ -90,40 +70,72 @@ bool RegToMem::runOnFunction(Function &F) { // Find the escaped instructions. But don't create stack slots for // allocas in entry block. std::list WorkList; - for (BasicBlock &ibb : F) - for (BasicBlock::iterator iib = ibb.begin(), iie = ibb.end(); iib != iie; - ++iib) { - if (!(isa(iib) && iib->getParent() == BBEntry) && - valueEscapes(&*iib)) { - WorkList.push_front(&*iib); - } - } + for (Instruction &I : instructions(F)) + if (!(isa(I) && I.getParent() == BBEntry) && valueEscapes(I)) + WorkList.push_front(&I); // Demote escaped instructions NumRegsDemoted += WorkList.size(); - for (Instruction *ilb : WorkList) - DemoteRegToStack(*ilb, false, AllocaInsertionPoint); + for (Instruction *I : WorkList) + DemoteRegToStack(*I, false, AllocaInsertionPoint); WorkList.clear(); // Find all phi's - for (BasicBlock &ibb : F) - for (BasicBlock::iterator iib = ibb.begin(), iie = ibb.end(); iib != iie; - ++iib) - if (isa(iib)) - WorkList.push_front(&*iib); + for (BasicBlock &BB : F) + for (auto &Phi : BB.phis()) + WorkList.push_front(&Phi); // Demote phi nodes NumPhisDemoted += WorkList.size(); - for (Instruction *ilb : WorkList) - DemotePHIToStack(cast(ilb), AllocaInsertionPoint); + for (Instruction *I : WorkList) + DemotePHIToStack(cast(I), AllocaInsertionPoint); return true; } +PreservedAnalyses RegToMemPass::run(Function &F, FunctionAnalysisManager &AM) { + auto *DT = &AM.getResult(F); + auto *LI = &AM.getResult(F); + unsigned N = SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions(DT, LI)); + bool Changed = runPass(F); + if (N == 0 && !Changed) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + return PA; +} + +namespace { +struct RegToMemLegacy : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + RegToMemLegacy() : FunctionPass(ID) { + initializeRegToMemLegacyPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequiredID(BreakCriticalEdgesID); + AU.addPreservedID(BreakCriticalEdgesID); + } + + bool runOnFunction(Function &F) override { + if (F.isDeclaration() || skipFunction(F)) + return false; + return runPass(F); + } +}; +} // namespace + +char RegToMemLegacy::ID = 0; +INITIALIZE_PASS_BEGIN(RegToMemLegacy, "reg2mem", + "Demote all values to stack slots", false, false) +INITIALIZE_PASS_DEPENDENCY(BreakCriticalEdges) +INITIALIZE_PASS_END(RegToMemLegacy, "reg2mem", + "Demote all values to stack slots", false, false) // createDemoteRegisterToMemory - Provide an entry point to create this pass. -char &llvm::DemoteRegisterToMemoryID = RegToMem::ID; +char &llvm::DemoteRegisterToMemoryID = RegToMemLegacy::ID; FunctionPass *llvm::createDemoteRegisterToMemoryPass() { - return new RegToMem(); + return new RegToMemLegacy(); } diff --git a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp index dc2ad14ae61e..b7830555bf73 100644 --- a/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp +++ b/llvm/lib/Transforms/Scalar/RewriteStatepointsForGC.cpp @@ -1487,7 +1487,7 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */ uint32_t NumPatchBytes = 0; uint32_t Flags = uint32_t(StatepointFlags::None); - ArrayRef CallArgs(Call->arg_begin(), Call->arg_end()); + SmallVector CallArgs(Call->args()); Optional> DeoptArgs; if (auto Bundle = Call->getOperandBundle(LLVMContext::OB_deopt)) DeoptArgs = Bundle->Inputs; @@ -1520,7 +1520,8 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */ Value *CallTarget = Call->getCalledOperand(); if (Function *F = dyn_cast(CallTarget)) { - if (F->getIntrinsicID() == Intrinsic::experimental_deoptimize) { + auto IID = F->getIntrinsicID(); + if (IID == Intrinsic::experimental_deoptimize) { // Calls to llvm.experimental.deoptimize are lowered to calls to the // __llvm_deoptimize symbol. We want to resolve this now, since the // verifier does not allow taking the address of an intrinsic function. @@ -1540,6 +1541,101 @@ makeStatepointExplicitImpl(CallBase *Call, /* to replace */ .getCallee(); IsDeoptimize = true; + } else if (IID == Intrinsic::memcpy_element_unordered_atomic || + IID == Intrinsic::memmove_element_unordered_atomic) { + // Unordered atomic memcpy and memmove intrinsics which are not explicitly + // marked as "gc-leaf-function" should be lowered in a GC parseable way. + // Specifically, these calls should be lowered to the + // __llvm_{memcpy|memmove}_element_unordered_atomic_safepoint symbols. + // Similarly to __llvm_deoptimize we want to resolve this now, since the + // verifier does not allow taking the address of an intrinsic function. + // + // Moreover we need to shuffle the arguments for the call in order to + // accommodate GC. The underlying source and destination objects might be + // relocated during copy operation should the GC occur. To relocate the + // derived source and destination pointers the implementation of the + // intrinsic should know the corresponding base pointers. + // + // To make the base pointers available pass them explicitly as arguments: + // memcpy(dest_derived, source_derived, ...) => + // memcpy(dest_base, dest_offset, source_base, source_offset, ...) + auto &Context = Call->getContext(); + auto &DL = Call->getModule()->getDataLayout(); + auto GetBaseAndOffset = [&](Value *Derived) { + assert(Result.PointerToBase.count(Derived)); + unsigned AddressSpace = Derived->getType()->getPointerAddressSpace(); + unsigned IntPtrSize = DL.getPointerSizeInBits(AddressSpace); + Value *Base = Result.PointerToBase.find(Derived)->second; + Value *Base_int = Builder.CreatePtrToInt( + Base, Type::getIntNTy(Context, IntPtrSize)); + Value *Derived_int = Builder.CreatePtrToInt( + Derived, Type::getIntNTy(Context, IntPtrSize)); + return std::make_pair(Base, Builder.CreateSub(Derived_int, Base_int)); + }; + + auto *Dest = CallArgs[0]; + Value *DestBase, *DestOffset; + std::tie(DestBase, DestOffset) = GetBaseAndOffset(Dest); + + auto *Source = CallArgs[1]; + Value *SourceBase, *SourceOffset; + std::tie(SourceBase, SourceOffset) = GetBaseAndOffset(Source); + + auto *LengthInBytes = CallArgs[2]; + auto *ElementSizeCI = cast(CallArgs[3]); + + CallArgs.clear(); + CallArgs.push_back(DestBase); + CallArgs.push_back(DestOffset); + CallArgs.push_back(SourceBase); + CallArgs.push_back(SourceOffset); + CallArgs.push_back(LengthInBytes); + + SmallVector DomainTy; + for (Value *Arg : CallArgs) + DomainTy.push_back(Arg->getType()); + auto *FTy = FunctionType::get(Type::getVoidTy(F->getContext()), DomainTy, + /* isVarArg = */ false); + + auto GetFunctionName = [](Intrinsic::ID IID, ConstantInt *ElementSizeCI) { + uint64_t ElementSize = ElementSizeCI->getZExtValue(); + if (IID == Intrinsic::memcpy_element_unordered_atomic) { + switch (ElementSize) { + case 1: + return "__llvm_memcpy_element_unordered_atomic_safepoint_1"; + case 2: + return "__llvm_memcpy_element_unordered_atomic_safepoint_2"; + case 4: + return "__llvm_memcpy_element_unordered_atomic_safepoint_4"; + case 8: + return "__llvm_memcpy_element_unordered_atomic_safepoint_8"; + case 16: + return "__llvm_memcpy_element_unordered_atomic_safepoint_16"; + default: + llvm_unreachable("unexpected element size!"); + } + } + assert(IID == Intrinsic::memmove_element_unordered_atomic); + switch (ElementSize) { + case 1: + return "__llvm_memmove_element_unordered_atomic_safepoint_1"; + case 2: + return "__llvm_memmove_element_unordered_atomic_safepoint_2"; + case 4: + return "__llvm_memmove_element_unordered_atomic_safepoint_4"; + case 8: + return "__llvm_memmove_element_unordered_atomic_safepoint_8"; + case 16: + return "__llvm_memmove_element_unordered_atomic_safepoint_16"; + default: + llvm_unreachable("unexpected element size!"); + } + }; + + CallTarget = + F->getParent() + ->getOrInsertFunction(GetFunctionName(IID, ElementSizeCI), FTy) + .getCallee(); } } @@ -1940,8 +2036,7 @@ static void relocationViaAlloca( /// tests in ways which make them less useful in testing fused safepoints. template static void unique_unsorted(SmallVectorImpl &Vec) { SmallSet Seen; - Vec.erase(remove_if(Vec, [&](const T &V) { return !Seen.insert(V).second; }), - Vec.end()); + erase_if(Vec, [&](const T &V) { return !Seen.insert(V).second; }); } /// Insert holders so that each Value is obviously live through the entire @@ -2013,10 +2108,10 @@ static Value* findRematerializableChainToBasePointer( // Helper function for the "rematerializeLiveValues". Compute cost of the use // chain we are going to rematerialize. -static unsigned -chainToBasePointerCost(SmallVectorImpl &Chain, +static InstructionCost +chainToBasePointerCost(SmallVectorImpl &Chain, TargetTransformInfo &TTI) { - unsigned Cost = 0; + InstructionCost Cost = 0; for (Instruction *Instr : Chain) { if (CastInst *CI = dyn_cast(Instr)) { @@ -2025,8 +2120,8 @@ chainToBasePointerCost(SmallVectorImpl &Chain, Type *SrcTy = CI->getOperand(0)->getType(); Cost += TTI.getCastInstrCost(CI->getOpcode(), CI->getType(), SrcTy, - TargetTransformInfo::TCK_SizeAndLatency, - CI); + TTI::getCastContextHint(CI), + TargetTransformInfo::TCK_SizeAndLatency, CI); } else if (GetElementPtrInst *GEP = dyn_cast(Instr)) { // Cost of the address calculation @@ -2123,7 +2218,7 @@ static void rematerializeLiveValues(CallBase *Call, assert(Info.LiveSet.count(AlternateRootPhi)); } // Compute cost of this chain - unsigned Cost = chainToBasePointerCost(ChainToBase, TTI); + InstructionCost Cost = chainToBasePointerCost(ChainToBase, TTI); // TODO: We can also account for cases when we will be able to remove some // of the rematerialized values by later optimization passes. I.e if // we rematerialized several intersecting chains. Or if original values @@ -2404,8 +2499,7 @@ static bool insertParsePoints(Function &F, DominatorTree &DT, // That Value* no longer exists and we need to use the new gc_result. // Thankfully, the live set is embedded in the statepoint (and updated), so // we just grab that. - Live.insert(Live.end(), Info.StatepointToken->gc_args_begin(), - Info.StatepointToken->gc_args_end()); + llvm::append_range(Live, Info.StatepointToken->gc_args()); #ifndef NDEBUG // Do some basic sanity checks on our liveness results before performing // relocation. Relocation can and will turn mistakes in liveness results @@ -2581,8 +2675,27 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, assert(shouldRewriteStatepointsIn(F) && "mismatch in rewrite decision"); auto NeedsRewrite = [&TLI](Instruction &I) { - if (const auto *Call = dyn_cast(&I)) - return !callsGCLeafFunction(Call, TLI) && !isa(Call); + if (const auto *Call = dyn_cast(&I)) { + if (isa(Call)) + return false; + if (callsGCLeafFunction(Call, TLI)) + return false; + + // Normally it's up to the frontend to make sure that non-leaf calls also + // have proper deopt state if it is required. We make an exception for + // element atomic memcpy/memmove intrinsics here. Unlike other intrinsics + // these are non-leaf by default. They might be generated by the optimizer + // which doesn't know how to produce a proper deopt state. So if we see a + // non-leaf memcpy/memmove without deopt state just treat it as a leaf + // copy and don't produce a statepoint. + if (!AllowStatepointWithNoDeoptInfo && + !Call->getOperandBundle(LLVMContext::OB_deopt)) { + assert((isa(Call) || isa(Call)) && + "Don't expect any other calls here!"); + return false; + } + return true; + } return false; }; @@ -2620,10 +2733,8 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT, // of liveness sets for no good reason. It may be harder to do this post // insertion since relocations and base phis can confuse things. for (BasicBlock &BB : F) - if (BB.getUniquePredecessor()) { - MadeChange = true; - FoldSingleEntryPHINodes(&BB); - } + if (BB.getUniquePredecessor()) + MadeChange |= FoldSingleEntryPHINodes(&BB); // Before we start introducing relocations, we want to tweak the IR a bit to // avoid unfortunate code generation effects. The main example is that we diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 5ebd3b71fe78..de6be52adf21 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -23,6 +23,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Statistic.h" @@ -33,6 +34,7 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueLattice.h" #include "llvm/Analysis/ValueLatticeUtils.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" @@ -103,8 +105,7 @@ bool isConstant(const ValueLatticeElement &LV) { // ValueLatticeElement::isOverdefined() and is intended to be used in the // transition to ValueLatticeElement. bool isOverdefined(const ValueLatticeElement &LV) { - return LV.isOverdefined() || - (LV.isConstantRange() && !LV.getConstantRange().isSingleElement()); + return !LV.isUnknownOrUndef() && !isConstant(LV); } //===----------------------------------------------------------------------===// @@ -233,7 +234,7 @@ public: for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) TrackedMultipleRetVals.insert( std::make_pair(std::make_pair(F, i), ValueLatticeElement())); - } else + } else if (!F->getReturnType()->isVoidTy()) TrackedRetVals.insert(std::make_pair(F, ValueLatticeElement())); } @@ -275,7 +276,7 @@ public: // isEdgeFeasible - Return true if the control flow edge from the 'From' basic // block to the 'To' basic block is currently feasible. - bool isEdgeFeasible(BasicBlock *From, BasicBlock *To); + bool isEdgeFeasible(BasicBlock *From, BasicBlock *To) const; std::vector getStructLatticeValueFor(Value *V) const { std::vector StructValues; @@ -648,17 +649,30 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI, Succs[0] = true; return; } - ValueLatticeElement SCValue = getValueState(SI->getCondition()); - ConstantInt *CI = getConstantInt(SCValue); + const ValueLatticeElement &SCValue = getValueState(SI->getCondition()); + if (ConstantInt *CI = getConstantInt(SCValue)) { + Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true; + return; + } - if (!CI) { // Overdefined or unknown condition? - // All destinations are executable! - if (!SCValue.isUnknownOrUndef()) - Succs.assign(TI.getNumSuccessors(), true); + // TODO: Switch on undef is UB. Stop passing false once the rest of LLVM + // is ready. + if (SCValue.isConstantRange(/*UndefAllowed=*/false)) { + const ConstantRange &Range = SCValue.getConstantRange(); + for (const auto &Case : SI->cases()) { + const APInt &CaseValue = Case.getCaseValue()->getValue(); + if (Range.contains(CaseValue)) + Succs[Case.getSuccessorIndex()] = true; + } + + // TODO: Determine whether default case is reachable. + Succs[SI->case_default()->getSuccessorIndex()] = true; return; } - Succs[SI->findCaseValue(CI)->getSuccessorIndex()] = true; + // Overdefined or unknown condition? All destinations are executable! + if (!SCValue.isUnknownOrUndef()) + Succs.assign(TI.getNumSuccessors(), true); return; } @@ -704,7 +718,7 @@ void SCCPSolver::getFeasibleSuccessors(Instruction &TI, // isEdgeFeasible - Return true if the control flow edge from the 'From' basic // block to the 'To' basic block is currently feasible. -bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) { +bool SCCPSolver::isEdgeFeasible(BasicBlock *From, BasicBlock *To) const { // Check if we've called markEdgeExecutable on the edge yet. (We could // be more aggressive and try to consider edges which haven't been marked // yet, but there isn't any need.) @@ -829,6 +843,16 @@ void SCCPSolver::visitCastInst(CastInst &I) { auto &LV = getValueState(&I); ConstantRange OpRange = OpSt.getConstantRange(); Type *DestTy = I.getDestTy(); + // Vectors where all elements have the same known constant range are treated + // as a single constant range in the lattice. When bitcasting such vectors, + // there is a mis-match between the width of the lattice value (single + // constant range) and the original operands (vector). Go to overdefined in + // that case. + if (I.getOpcode() == Instruction::BitCast && + I.getOperand(0)->getType()->isVectorTy() && + OpRange.getBitWidth() < DL.getTypeSizeInBits(DestTy)) + return (void)markOverdefined(&I); + ConstantRange Res = OpRange.castOp(I.getOpcode(), DL.getTypeSizeInBits(DestTy)); mergeInValue(LV, &I, ValueLatticeElement::getRange(Res)); @@ -1109,7 +1133,9 @@ static ValueLatticeElement getValueFromMetadata(const Instruction *I) { if (I->getType()->isIntegerTy()) return ValueLatticeElement::getRange( getConstantRangeFromMetadata(*Ranges)); - // TODO: Also handle MD_nonnull. + if (I->hasMetadata(LLVMContext::MD_nonnull)) + return ValueLatticeElement::getNot( + ConstantPointerNull::get(cast(I->getType()))); return ValueLatticeElement::getOverdefined(); } @@ -1262,55 +1288,33 @@ void SCCPSolver::handleCallResult(CallBase &CB) { auto *PI = getPredicateInfoFor(&CB); assert(PI && "Missing predicate info for ssa.copy"); - CmpInst *Cmp; - bool TrueEdge; - if (auto *PBranch = dyn_cast(PI)) { - Cmp = dyn_cast(PBranch->Condition); - TrueEdge = PBranch->TrueEdge; - } else if (auto *PAssume = dyn_cast(PI)) { - Cmp = dyn_cast(PAssume->Condition); - TrueEdge = true; - } else { - mergeInValue(ValueState[&CB], &CB, CopyOfVal); - return; - } - - // Everything below relies on the condition being a comparison. - if (!Cmp) { + const Optional &Constraint = PI->getConstraint(); + if (!Constraint) { mergeInValue(ValueState[&CB], &CB, CopyOfVal); return; } - Value *RenamedOp = PI->RenamedOp; - Value *CmpOp0 = Cmp->getOperand(0); - Value *CmpOp1 = Cmp->getOperand(1); - // Bail out if neither of the operands matches RenamedOp. - if (CmpOp0 != RenamedOp && CmpOp1 != RenamedOp) { - mergeInValue(ValueState[&CB], &CB, getValueState(CopyOf)); - return; - } + CmpInst::Predicate Pred = Constraint->Predicate; + Value *OtherOp = Constraint->OtherOp; - auto Pred = Cmp->getPredicate(); - if (CmpOp1 == RenamedOp) { - std::swap(CmpOp0, CmpOp1); - Pred = Cmp->getSwappedPredicate(); - } - - // Wait until CmpOp1 is resolved. - if (getValueState(CmpOp1).isUnknown()) { - addAdditionalUser(CmpOp1, &CB); + // Wait until OtherOp is resolved. + if (getValueState(OtherOp).isUnknown()) { + addAdditionalUser(OtherOp, &CB); return; } - // The code below relies on PredicateInfo only inserting copies for the - // true branch when the branch condition is an AND and only inserting - // copies for the false branch when the branch condition is an OR. This - // ensures we can intersect the range from the condition with the range of - // CopyOf. - if (!TrueEdge) - Pred = CmpInst::getInversePredicate(Pred); - - ValueLatticeElement CondVal = getValueState(CmpOp1); + // TODO: Actually filp MayIncludeUndef for the created range to false, + // once most places in the optimizer respect the branches on + // undef/poison are UB rule. The reason why the new range cannot be + // undef is as follows below: + // The new range is based on a branch condition. That guarantees that + // neither of the compare operands can be undef in the branch targets, + // unless we have conditions that are always true/false (e.g. icmp ule + // i32, %a, i32_max). For the latter overdefined/empty range will be + // inferred, but the branch will get folded accordingly anyways. + bool MayIncludeUndef = !isa(PI); + + ValueLatticeElement CondVal = getValueState(OtherOp); ValueLatticeElement &IV = ValueState[&CB]; if (CondVal.isConstantRange() || CopyOfVal.isConstantRange()) { auto ImposedCR = @@ -1334,30 +1338,47 @@ void SCCPSolver::handleCallResult(CallBase &CB) { if (!CopyOfCR.contains(NewCR) && CopyOfCR.getSingleMissingElement()) NewCR = CopyOfCR; - addAdditionalUser(CmpOp1, &CB); - // TODO: Actually filp MayIncludeUndef for the created range to false, - // once most places in the optimizer respect the branches on - // undef/poison are UB rule. The reason why the new range cannot be - // undef is as follows below: - // The new range is based on a branch condition. That guarantees that - // neither of the compare operands can be undef in the branch targets, - // unless we have conditions that are always true/false (e.g. icmp ule - // i32, %a, i32_max). For the latter overdefined/empty range will be - // inferred, but the branch will get folded accordingly anyways. + addAdditionalUser(OtherOp, &CB); mergeInValue( IV, &CB, - ValueLatticeElement::getRange(NewCR, /*MayIncludeUndef=*/true)); + ValueLatticeElement::getRange(NewCR, MayIncludeUndef)); return; } else if (Pred == CmpInst::ICMP_EQ && CondVal.isConstant()) { // For non-integer values or integer constant expressions, only // propagate equal constants. - addAdditionalUser(CmpOp1, &CB); + addAdditionalUser(OtherOp, &CB); mergeInValue(IV, &CB, CondVal); return; + } else if (Pred == CmpInst::ICMP_NE && CondVal.isConstant() && + !MayIncludeUndef) { + // Propagate inequalities. + addAdditionalUser(OtherOp, &CB); + mergeInValue(IV, &CB, + ValueLatticeElement::getNot(CondVal.getConstant())); + return; } return (void)mergeInValue(IV, &CB, CopyOfVal); } + + if (ConstantRange::isIntrinsicSupported(II->getIntrinsicID())) { + // Compute result range for intrinsics supported by ConstantRange. + // Do this even if we don't know a range for all operands, as we may + // still know something about the result range, e.g. of abs(x). + SmallVector OpRanges; + for (Value *Op : II->args()) { + const ValueLatticeElement &State = getValueState(Op); + if (State.isConstantRange()) + OpRanges.push_back(State.getConstantRange()); + else + OpRanges.push_back( + ConstantRange::getFull(Op->getType()->getScalarSizeInBits())); + } + + ConstantRange Result = + ConstantRange::intrinsic(II->getIntrinsicID(), OpRanges); + return (void)mergeInValue(II, ValueLatticeElement::getRange(Result)); + } } // The common case is that we aren't tracking the callee, either because we @@ -1427,8 +1448,7 @@ void SCCPSolver::Solve() { // Process the basic block work list. while (!BBWorkList.empty()) { - BasicBlock *BB = BBWorkList.back(); - BBWorkList.pop_back(); + BasicBlock *BB = BBWorkList.pop_back_val(); LLVM_DEBUG(dbgs() << "\nPopped off BBWL: " << *BB << '\n'); @@ -1456,6 +1476,7 @@ void SCCPSolver::Solve() { /// This scan also checks for values that use undefs. It conservatively marks /// them as overdefined. bool SCCPSolver::ResolvedUndefsIn(Function &F) { + bool MadeChange = false; for (BasicBlock &BB : F) { if (!BBExecutable.count(&BB)) continue; @@ -1481,8 +1502,10 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { // more precise than this but it isn't worth bothering. for (unsigned i = 0, e = STy->getNumElements(); i != e; ++i) { ValueLatticeElement &LV = getStructValueState(&I, i); - if (LV.isUnknownOrUndef()) + if (LV.isUnknownOrUndef()) { markOverdefined(LV, &I); + MadeChange = true; + } } continue; } @@ -1509,7 +1532,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { } markOverdefined(&I); - return true; + MadeChange = true; } // Check to see if we have a branch or switch on an undefined value. If so @@ -1526,7 +1549,8 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { if (isa(BI->getCondition())) { BI->setCondition(ConstantInt::getFalse(BI->getContext())); markEdgeExecutable(&BB, TI->getSuccessor(1)); - return true; + MadeChange = true; + continue; } // Otherwise, it is a branch on a symbolic value which is currently @@ -1535,7 +1559,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { // FIXME: Distinguish between dead code and an LLVM "undef" value. BasicBlock *DefaultSuccessor = TI->getSuccessor(1); if (markEdgeExecutable(&BB, DefaultSuccessor)) - return true; + MadeChange = true; continue; } @@ -1554,7 +1578,8 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { if (isa(IBR->getAddress())) { IBR->setAddress(BlockAddress::get(IBR->getSuccessor(0))); markEdgeExecutable(&BB, IBR->getSuccessor(0)); - return true; + MadeChange = true; + continue; } // Otherwise, it is a branch on a symbolic value which is currently @@ -1564,7 +1589,7 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { // we can assume the branch has undefined behavior instead. BasicBlock *DefaultSuccessor = IBR->getSuccessor(0); if (markEdgeExecutable(&BB, DefaultSuccessor)) - return true; + MadeChange = true; continue; } @@ -1579,7 +1604,8 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { if (isa(SI->getCondition())) { SI->setCondition(SI->case_begin()->getCaseValue()); markEdgeExecutable(&BB, SI->case_begin()->getCaseSuccessor()); - return true; + MadeChange = true; + continue; } // Otherwise, it is a branch on a symbolic value which is currently @@ -1588,13 +1614,13 @@ bool SCCPSolver::ResolvedUndefsIn(Function &F) { // FIXME: Distinguish between dead code and an LLVM "undef" value. BasicBlock *DefaultSuccessor = SI->case_begin()->getCaseSuccessor(); if (markEdgeExecutable(&BB, DefaultSuccessor)) - return true; + MadeChange = true; continue; } } - return false; + return MadeChange; } static bool tryToReplaceWithConstant(SCCPSolver &Solver, Value *V) { @@ -1716,7 +1742,7 @@ static bool runSCCP(Function &F, const DataLayout &DL, LLVM_DEBUG(dbgs() << " BasicBlock Dead:" << BB); ++NumDeadBlocks; - NumInstRemoved += removeAllNonTerminatorAndEHPadInstructions(&BB); + NumInstRemoved += removeAllNonTerminatorAndEHPadInstructions(&BB).first; MadeChanges = true; continue; @@ -1839,39 +1865,68 @@ static void findReturnsToZap(Function &F, } } -// Update the condition for terminators that are branching on indeterminate -// values, forcing them to use a specific edge. -static void forceIndeterminateEdge(Instruction* I, SCCPSolver &Solver) { - BasicBlock *Dest = nullptr; - Constant *C = nullptr; - if (SwitchInst *SI = dyn_cast(I)) { - if (!isa(SI->getCondition())) { - // Indeterminate switch; use first case value. - Dest = SI->case_begin()->getCaseSuccessor(); - C = SI->case_begin()->getCaseValue(); - } - } else if (BranchInst *BI = dyn_cast(I)) { - if (!isa(BI->getCondition())) { - // Indeterminate branch; use false. - Dest = BI->getSuccessor(1); - C = ConstantInt::getFalse(BI->getContext()); +static bool removeNonFeasibleEdges(const SCCPSolver &Solver, BasicBlock *BB, + DomTreeUpdater &DTU) { + SmallPtrSet FeasibleSuccessors; + bool HasNonFeasibleEdges = false; + for (BasicBlock *Succ : successors(BB)) { + if (Solver.isEdgeFeasible(BB, Succ)) + FeasibleSuccessors.insert(Succ); + else + HasNonFeasibleEdges = true; + } + + // All edges feasible, nothing to do. + if (!HasNonFeasibleEdges) + return false; + + // SCCP can only determine non-feasible edges for br, switch and indirectbr. + Instruction *TI = BB->getTerminator(); + assert((isa(TI) || isa(TI) || + isa(TI)) && + "Terminator must be a br, switch or indirectbr"); + + if (FeasibleSuccessors.size() == 1) { + // Replace with an unconditional branch to the only feasible successor. + BasicBlock *OnlyFeasibleSuccessor = *FeasibleSuccessors.begin(); + SmallVector Updates; + bool HaveSeenOnlyFeasibleSuccessor = false; + for (BasicBlock *Succ : successors(BB)) { + if (Succ == OnlyFeasibleSuccessor && !HaveSeenOnlyFeasibleSuccessor) { + // Don't remove the edge to the only feasible successor the first time + // we see it. We still do need to remove any multi-edges to it though. + HaveSeenOnlyFeasibleSuccessor = true; + continue; + } + + Succ->removePredecessor(BB); + Updates.push_back({DominatorTree::Delete, BB, Succ}); } - } else if (IndirectBrInst *IBR = dyn_cast(I)) { - if (!isa(IBR->getAddress()->stripPointerCasts())) { - // Indeterminate indirectbr; use successor 0. - Dest = IBR->getSuccessor(0); - C = BlockAddress::get(IBR->getSuccessor(0)); + + BranchInst::Create(OnlyFeasibleSuccessor, BB); + TI->eraseFromParent(); + DTU.applyUpdatesPermissive(Updates); + } else if (FeasibleSuccessors.size() > 1) { + SwitchInstProfUpdateWrapper SI(*cast(TI)); + SmallVector Updates; + for (auto CI = SI->case_begin(); CI != SI->case_end();) { + if (FeasibleSuccessors.contains(CI->getCaseSuccessor())) { + ++CI; + continue; + } + + BasicBlock *Succ = CI->getCaseSuccessor(); + Succ->removePredecessor(BB); + Updates.push_back({DominatorTree::Delete, BB, Succ}); + SI.removeCase(CI); + // Don't increment CI, as we removed a case. } - } else { - llvm_unreachable("Unexpected terminator instruction"); - } - if (C) { - assert(Solver.isEdgeFeasible(I->getParent(), Dest) && - "Didn't find feasible edge?"); - (void)Dest; - I->setOperand(0, C); + DTU.applyUpdatesPermissive(Updates); + } else { + llvm_unreachable("Must have at least one feasible successor"); } + return true; } bool llvm::runIPSCCP( @@ -1923,13 +1978,12 @@ bool llvm::runIPSCCP( while (ResolvedUndefs) { LLVM_DEBUG(dbgs() << "RESOLVING UNDEFS\n"); ResolvedUndefs = false; - for (Function &F : M) - if (Solver.ResolvedUndefsIn(F)) { - // We run Solve() after we resolved an undef in a function, because - // we might deduce a fact that eliminates an undef in another function. - Solver.Solve(); + for (Function &F : M) { + if (Solver.ResolvedUndefsIn(F)) ResolvedUndefs = true; - } + } + if (ResolvedUndefs) + Solver.Solve(); } bool MadeChanges = false; @@ -1943,15 +1997,35 @@ bool llvm::runIPSCCP( SmallVector BlocksToErase; - if (Solver.isBlockExecutable(&F.front())) - for (Function::arg_iterator AI = F.arg_begin(), E = F.arg_end(); AI != E; - ++AI) { - if (!AI->use_empty() && tryToReplaceWithConstant(Solver, &*AI)) { + if (Solver.isBlockExecutable(&F.front())) { + bool ReplacedPointerArg = false; + for (Argument &Arg : F.args()) { + if (!Arg.use_empty() && tryToReplaceWithConstant(Solver, &Arg)) { + ReplacedPointerArg |= Arg.getType()->isPointerTy(); ++IPNumArgsElimed; - continue; } } + // If we replaced an argument, the argmemonly and + // inaccessiblemem_or_argmemonly attributes do not hold any longer. Remove + // them from both the function and callsites. + if (ReplacedPointerArg) { + AttrBuilder AttributesToRemove; + AttributesToRemove.addAttribute(Attribute::ArgMemOnly); + AttributesToRemove.addAttribute(Attribute::InaccessibleMemOrArgMemOnly); + F.removeAttributes(AttributeList::FunctionIndex, AttributesToRemove); + + for (User *U : F.users()) { + auto *CB = dyn_cast(U); + if (!CB || CB->getCalledFunction() != &F) + continue; + + CB->removeAttributes(AttributeList::FunctionIndex, + AttributesToRemove); + } + } + } + SmallPtrSet InsertedValues; for (BasicBlock &BB : F) { if (!Solver.isBlockExecutable(&BB)) { @@ -1984,45 +2058,11 @@ bool llvm::runIPSCCP( /*UseLLVMTrap=*/false, /*PreserveLCSSA=*/false, &DTU); - // Now that all instructions in the function are constant folded, - // use ConstantFoldTerminator to get rid of in-edges, record DT updates and - // delete dead BBs. - for (BasicBlock *DeadBB : BlocksToErase) { - // If there are any PHI nodes in this successor, drop entries for BB now. - for (Value::user_iterator UI = DeadBB->user_begin(), - UE = DeadBB->user_end(); - UI != UE;) { - // Grab the user and then increment the iterator early, as the user - // will be deleted. Step past all adjacent uses from the same user. - auto *I = dyn_cast(*UI); - do { ++UI; } while (UI != UE && *UI == I); - - // Ignore blockaddress users; BasicBlock's dtor will handle them. - if (!I) continue; - - // If we have forced an edge for an indeterminate value, then force the - // terminator to fold to that edge. - forceIndeterminateEdge(I, Solver); - BasicBlock *InstBB = I->getParent(); - bool Folded = ConstantFoldTerminator(InstBB, - /*DeleteDeadConditions=*/false, - /*TLI=*/nullptr, &DTU); - assert(Folded && - "Expect TermInst on constantint or blockaddress to be folded"); - (void) Folded; - // If we folded the terminator to an unconditional branch to another - // dead block, replace it with Unreachable, to avoid trying to fold that - // branch again. - BranchInst *BI = cast(InstBB->getTerminator()); - if (BI && BI->isUnconditional() && - !Solver.isBlockExecutable(BI->getSuccessor(0))) { - InstBB->getTerminator()->eraseFromParent(); - new UnreachableInst(InstBB->getContext(), InstBB); - } - } - // Mark dead BB for deletion. + for (BasicBlock &BB : F) + MadeChanges |= removeNonFeasibleEdges(Solver, &BB, DTU); + + for (BasicBlock *DeadBB : BlocksToErase) DTU.deleteBB(DeadBB); - } for (BasicBlock &BB : F) { for (BasicBlock::iterator BI = BB.begin(), E = BB.end(); BI != E;) { @@ -2054,9 +2094,47 @@ bool llvm::runIPSCCP( for (const auto &I : Solver.getTrackedRetVals()) { Function *F = I.first; - if (isOverdefined(I.second) || F->getReturnType()->isVoidTy()) + const ValueLatticeElement &ReturnValue = I.second; + + // If there is a known constant range for the return value, add !range + // metadata to the function's call sites. + if (ReturnValue.isConstantRange() && + !ReturnValue.getConstantRange().isSingleElement()) { + // Do not add range metadata if the return value may include undef. + if (ReturnValue.isConstantRangeIncludingUndef()) + continue; + + auto &CR = ReturnValue.getConstantRange(); + for (User *User : F->users()) { + auto *CB = dyn_cast(User); + if (!CB || CB->getCalledFunction() != F) + continue; + + // Limit to cases where the return value is guaranteed to be neither + // poison nor undef. Poison will be outside any range and currently + // values outside of the specified range cause immediate undefined + // behavior. + if (!isGuaranteedNotToBeUndefOrPoison(CB, nullptr, CB)) + continue; + + // Do not touch existing metadata for now. + // TODO: We should be able to take the intersection of the existing + // metadata and the inferred range. + if (CB->getMetadata(LLVMContext::MD_range)) + continue; + + LLVMContext &Context = CB->getParent()->getContext(); + Metadata *RangeMD[] = { + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getLower())), + ConstantAsMetadata::get(ConstantInt::get(Context, CR.getUpper()))}; + CB->setMetadata(LLVMContext::MD_range, MDNode::get(Context, RangeMD)); + } continue; - findReturnsToZap(*F, ReturnsToZap, Solver); + } + if (F->getReturnType()->isVoidTy()) + continue; + if (isConstant(ReturnValue) || ReturnValue.isUnknownOrUndef()) + findReturnsToZap(*F, ReturnsToZap, Solver); } for (auto F : Solver.getMRVFunctionsTracked()) { @@ -2068,9 +2146,27 @@ bool llvm::runIPSCCP( } // Zap all returns which we've identified as zap to change. + SmallSetVector FuncZappedReturn; for (unsigned i = 0, e = ReturnsToZap.size(); i != e; ++i) { Function *F = ReturnsToZap[i]->getParent()->getParent(); ReturnsToZap[i]->setOperand(0, UndefValue::get(F->getReturnType())); + // Record all functions that are zapped. + FuncZappedReturn.insert(F); + } + + // Remove the returned attribute for zapped functions and the + // corresponding call sites. + for (Function *F : FuncZappedReturn) { + for (Argument &A : F->args()) + F->removeParamAttr(A.getArgNo(), Attribute::Returned); + for (Use &U : F->uses()) { + // Skip over blockaddr users. + if (isa(U.getUser())) + continue; + CallBase *CB = cast(U.getUser()); + for (Use &Arg : CB->args()) + CB->removeParamAttr(CB->getArgOperandNo(&Arg), Attribute::Returned); + } } // If we inferred constant or undef values for globals variables, we can diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp index 89f324deef9f..d111a6ba4241 100644 --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -268,6 +268,11 @@ public: /// Access the dead users for this alloca. ArrayRef getDeadUsers() const { return DeadUsers; } + /// Access Uses that should be dropped if the alloca is promotable. + ArrayRef getDeadUsesIfPromotable() const { + return DeadUseIfPromotable; + } + /// Access the dead operands referring to this alloca. /// /// These are operands which have cannot actually be used to refer to the @@ -322,6 +327,9 @@ private: /// they come from outside of the allocated space. SmallVector DeadUsers; + /// Uses which will become dead if can promote the alloca. + SmallVector DeadUseIfPromotable; + /// Operands which will become dead if we rewrite the alloca. /// /// These are operands that in their particular use can be replaced with @@ -459,12 +467,8 @@ class AllocaSlices::partition_iterator // Remove the uses which have ended in the prior partition. This // cannot change the max split slice end because we just checked that // the prior partition ended prior to that max. - P.SplitTails.erase(llvm::remove_if(P.SplitTails, - [&](Slice *S) { - return S->endOffset() <= - P.EndOffset; - }), - P.SplitTails.end()); + llvm::erase_if(P.SplitTails, + [&](Slice *S) { return S->endOffset() <= P.EndOffset; }); assert(llvm::any_of(P.SplitTails, [&](Slice *S) { return S->endOffset() == MaxSplitSliceEndOffset; @@ -780,6 +784,9 @@ private: LI.getPointerAddressSpace() != DL.getAllocaAddrSpace()) return PI.setAborted(&LI); + if (isa(LI.getType())) + return PI.setAborted(&LI); + uint64_t Size = DL.getTypeStoreSize(LI.getType()).getFixedSize(); return handleLoadOrStore(LI.getType(), LI, Offset, Size, LI.isVolatile()); } @@ -795,6 +802,9 @@ private: SI.getPointerAddressSpace() != DL.getAllocaAddrSpace()) return PI.setAborted(&SI); + if (isa(ValOp->getType())) + return PI.setAborted(&SI); + uint64_t Size = DL.getTypeStoreSize(ValOp->getType()).getFixedSize(); // If this memory access can be shown to *statically* extend outside the @@ -920,6 +930,11 @@ private: // FIXME: What about debug intrinsics? This matches old behavior, but // doesn't make sense. void visitIntrinsicInst(IntrinsicInst &II) { + if (II.isDroppable()) { + AS.DeadUseIfPromotable.push_back(U); + return; + } + if (!IsOffsetKnown) return PI.setAborted(&II); @@ -1057,13 +1072,11 @@ AllocaSlices::AllocaSlices(const DataLayout &DL, AllocaInst &AI) return; } - Slices.erase( - llvm::remove_if(Slices, [](const Slice &S) { return S.isDead(); }), - Slices.end()); + llvm::erase_if(Slices, [](const Slice &S) { return S.isDead(); }); // Sort the uses. This arranges for the offsets to be in ascending order, // and the sizes to be in descending order. - std::stable_sort(Slices.begin(), Slices.end()); + llvm::stable_sort(Slices); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) @@ -1109,9 +1122,9 @@ LLVM_DUMP_METHOD void AllocaSlices::dump() const { print(dbgs()); } /// Walk the range of a partitioning looking for a common type to cover this /// sequence of slices. -static Type *findCommonType(AllocaSlices::const_iterator B, - AllocaSlices::const_iterator E, - uint64_t EndOffset) { +static std::pair +findCommonType(AllocaSlices::const_iterator B, AllocaSlices::const_iterator E, + uint64_t EndOffset) { Type *Ty = nullptr; bool TyIsCommon = true; IntegerType *ITy = nullptr; @@ -1155,7 +1168,7 @@ static Type *findCommonType(AllocaSlices::const_iterator B, Ty = UserTy; } - return TyIsCommon ? Ty : ITy; + return {TyIsCommon ? Ty : nullptr, ITy}; } /// PHI instructions that use an alloca and are subsequently loaded can be @@ -1379,7 +1392,8 @@ static void speculateSelectInstLoads(SelectInst &SI) { /// This will return the BasePtr if that is valid, or build a new GEP /// instruction using the IRBuilder if GEP-ing is needed. static Value *buildGEP(IRBuilderTy &IRB, Value *BasePtr, - SmallVectorImpl &Indices, Twine NamePrefix) { + SmallVectorImpl &Indices, + const Twine &NamePrefix) { if (Indices.empty()) return BasePtr; @@ -1404,7 +1418,7 @@ static Value *buildGEP(IRBuilderTy &IRB, Value *BasePtr, static Value *getNaturalGEPWithType(IRBuilderTy &IRB, const DataLayout &DL, Value *BasePtr, Type *Ty, Type *TargetTy, SmallVectorImpl &Indices, - Twine NamePrefix) { + const Twine &NamePrefix) { if (Ty == TargetTy) return buildGEP(IRB, BasePtr, Indices, NamePrefix); @@ -1449,7 +1463,7 @@ static Value *getNaturalGEPRecursively(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, Type *Ty, APInt &Offset, Type *TargetTy, SmallVectorImpl &Indices, - Twine NamePrefix) { + const Twine &NamePrefix) { if (Offset == 0) return getNaturalGEPWithType(IRB, DL, Ptr, Ty, TargetTy, Indices, NamePrefix); @@ -1524,7 +1538,7 @@ static Value *getNaturalGEPRecursively(IRBuilderTy &IRB, const DataLayout &DL, static Value *getNaturalGEPWithOffset(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, APInt Offset, Type *TargetTy, SmallVectorImpl &Indices, - Twine NamePrefix) { + const Twine &NamePrefix) { PointerType *Ty = cast(Ptr->getType()); // Don't consider any GEPs through an i8* as natural unless the TargetTy is @@ -1535,6 +1549,8 @@ static Value *getNaturalGEPWithOffset(IRBuilderTy &IRB, const DataLayout &DL, Type *ElementTy = Ty->getElementType(); if (!ElementTy->isSized()) return nullptr; // We can't GEP through an unsized element. + if (isa(ElementTy)) + return nullptr; APInt ElementSize(Offset.getBitWidth(), DL.getTypeAllocSize(ElementTy).getFixedSize()); if (ElementSize == 0) @@ -1563,7 +1579,8 @@ static Value *getNaturalGEPWithOffset(IRBuilderTy &IRB, const DataLayout &DL, /// a single GEP as possible, thus making each GEP more independent of the /// surrounding code. static Value *getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr, - APInt Offset, Type *PointerTy, Twine NamePrefix) { + APInt Offset, Type *PointerTy, + const Twine &NamePrefix) { // Even though we don't look through PHI nodes, we could be called on an // instruction in an unreachable block, which may be on a cycle. SmallPtrSet Visited; @@ -1825,7 +1842,7 @@ static bool isVectorPromotionViableForSlice(Partition &P, const Slice &S, if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { - if (!II->isLifetimeStartOrEnd()) + if (!II->isLifetimeStartOrEnd() && !II->isDroppable()) return false; } else if (U->get()->getType()->getPointerElementType()->isStructTy()) { // Disable vector promotion when there are loads or stores of an FCA. @@ -1909,12 +1926,9 @@ static VectorType *isVectorPromotionViable(Partition &P, const DataLayout &DL) { // do that until all the backends are known to produce good code for all // integer vector types. if (!HaveCommonEltTy) { - CandidateTys.erase( - llvm::remove_if(CandidateTys, - [](VectorType *VTy) { - return !VTy->getElementType()->isIntegerTy(); - }), - CandidateTys.end()); + llvm::erase_if(CandidateTys, [](VectorType *VTy) { + return !VTy->getElementType()->isIntegerTy(); + }); // If there were no integer vector types, give up. if (CandidateTys.empty()) @@ -2058,7 +2072,7 @@ static bool isIntegerWideningViableForSlice(const Slice &S, if (!S.isSplittable()) return false; // Skip any unsplittable intrinsics. } else if (IntrinsicInst *II = dyn_cast(U->getUser())) { - if (!II->isLifetimeStartOrEnd()) + if (!II->isLifetimeStartOrEnd() && !II->isDroppable()) return false; } else { return false; @@ -2099,8 +2113,7 @@ static bool isIntegerWideningViable(Partition &P, Type *AllocaTy, // that we cover the alloca. // FIXME: We shouldn't consider split slices that happen to start in the // partition here... - bool WholeAllocaOp = - P.begin() != P.end() ? false : DL.isLegalInteger(SizeInBits); + bool WholeAllocaOp = P.empty() && DL.isLegalInteger(SizeInBits); for (const Slice &S : P) if (!isIntegerWideningViableForSlice(S, P.beginOffset(), AllocaTy, DL, @@ -2193,8 +2206,7 @@ static Value *extractVector(IRBuilderTy &IRB, Value *V, unsigned BeginIndex, Mask.reserve(NumElements); for (unsigned i = BeginIndex; i != EndIndex; ++i) Mask.push_back(i); - V = IRB.CreateShuffleVector(V, UndefValue::get(V->getType()), Mask, - Name + ".extract"); + V = IRB.CreateShuffleVector(V, Mask, Name + ".extract"); LLVM_DEBUG(dbgs() << " shuffle: " << *V << "\n"); return V; } @@ -2227,22 +2239,22 @@ static Value *insertVector(IRBuilderTy &IRB, Value *Old, Value *V, // use a shuffle vector to widen it with undef elements, and then // a second shuffle vector to select between the loaded vector and the // incoming vector. - SmallVector Mask; + SmallVector Mask; Mask.reserve(cast(VecTy)->getNumElements()); for (unsigned i = 0; i != cast(VecTy)->getNumElements(); ++i) if (i >= BeginIndex && i < EndIndex) - Mask.push_back(IRB.getInt32(i - BeginIndex)); + Mask.push_back(i - BeginIndex); else - Mask.push_back(UndefValue::get(IRB.getInt32Ty())); - V = IRB.CreateShuffleVector(V, UndefValue::get(V->getType()), - ConstantVector::get(Mask), Name + ".expand"); + Mask.push_back(-1); + V = IRB.CreateShuffleVector(V, Mask, Name + ".expand"); LLVM_DEBUG(dbgs() << " shuffle: " << *V << "\n"); - Mask.clear(); + SmallVector Mask2; + Mask2.reserve(cast(VecTy)->getNumElements()); for (unsigned i = 0; i != cast(VecTy)->getNumElements(); ++i) - Mask.push_back(IRB.getInt1(i >= BeginIndex && i < EndIndex)); + Mask2.push_back(IRB.getInt1(i >= BeginIndex && i < EndIndex)); - V = IRB.CreateSelect(ConstantVector::get(Mask), V, Old, Name + "blend"); + V = IRB.CreateSelect(ConstantVector::get(Mask2), V, Old, Name + "blend"); LLVM_DEBUG(dbgs() << " blend: " << *V << "\n"); return V; @@ -2446,7 +2458,7 @@ private: void deleteIfTriviallyDead(Value *V) { Instruction *I = cast(V); if (isInstructionTriviallyDead(I)) - Pass.DeadInsts.insert(I); + Pass.DeadInsts.push_back(I); } Value *rewriteVectorizedLoadInst() { @@ -2586,7 +2598,7 @@ private: LI.replaceAllUsesWith(V); } - Pass.DeadInsts.insert(&LI); + Pass.DeadInsts.push_back(&LI); deleteIfTriviallyDead(OldOp); LLVM_DEBUG(dbgs() << " to: " << *V << "\n"); return !LI.isVolatile() && !IsPtrAdjusted; @@ -2615,7 +2627,7 @@ private: StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlign()); if (AATags) Store->setAAMetadata(AATags); - Pass.DeadInsts.insert(&SI); + Pass.DeadInsts.push_back(&SI); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); return true; @@ -2639,7 +2651,7 @@ private: LLVMContext::MD_access_group}); if (AATags) Store->setAAMetadata(AATags); - Pass.DeadInsts.insert(&SI); + Pass.DeadInsts.push_back(&SI); LLVM_DEBUG(dbgs() << " to: " << *Store << "\n"); return true; } @@ -2713,7 +2725,7 @@ private: NewSI->setAtomic(SI.getOrdering(), SI.getSyncScopeID()); if (NewSI->isAtomic()) NewSI->setAlignment(SI.getAlign()); - Pass.DeadInsts.insert(&SI); + Pass.DeadInsts.push_back(&SI); deleteIfTriviallyDead(OldOp); LLVM_DEBUG(dbgs() << " to: " << *NewSI << "\n"); @@ -2774,11 +2786,11 @@ private: } // Record this instruction for deletion. - Pass.DeadInsts.insert(&II); + Pass.DeadInsts.push_back(&II); Type *AllocaTy = NewAI.getAllocatedType(); Type *ScalarTy = AllocaTy->getScalarType(); - + const bool CanContinue = [&]() { if (VecTy || IntTy) return true; @@ -2944,7 +2956,7 @@ private: return false; } // Record this instruction for deletion. - Pass.DeadInsts.insert(&II); + Pass.DeadInsts.push_back(&II); // Strip all inbounds GEPs and pointer casts to try to dig out any root // alloca that should be re-examined after rewriting this instruction. @@ -3074,13 +3086,21 @@ private: } bool visitIntrinsicInst(IntrinsicInst &II) { - assert(II.isLifetimeStartOrEnd()); + assert((II.isLifetimeStartOrEnd() || II.isDroppable()) && + "Unexpected intrinsic!"); LLVM_DEBUG(dbgs() << " original: " << II << "\n"); - assert(II.getArgOperand(1) == OldPtr); // Record this instruction for deletion. - Pass.DeadInsts.insert(&II); + Pass.DeadInsts.push_back(&II); + + if (II.isDroppable()) { + assert(II.getIntrinsicID() == Intrinsic::assume && "Expected assume"); + // TODO For now we forget assumed information, this can be improved. + OldPtr->dropDroppableUsesIn(II); + return true; + } + assert(II.getArgOperand(1) == OldPtr); // Lifetime intrinsics are only promotable if they cover the whole alloca. // Therefore, we drop lifetime intrinsics which don't cover the whole // alloca. @@ -3455,7 +3475,7 @@ private: << "\n " << GEPI); IRBuilderTy Builder(&GEPI); - SmallVector Index(GEPI.idx_begin(), GEPI.idx_end()); + SmallVector Index(GEPI.indices()); bool IsInBounds = GEPI.isInBounds(); Value *True = Sel->getTrueValue(); @@ -3509,20 +3529,27 @@ private: << "\n " << GEPI << "\n to: "); - SmallVector Index(GEPI.idx_begin(), GEPI.idx_end()); + SmallVector Index(GEPI.indices()); bool IsInBounds = GEPI.isInBounds(); IRBuilderTy PHIBuilder(GEPI.getParent()->getFirstNonPHI()); PHINode *NewPN = PHIBuilder.CreatePHI(GEPI.getType(), PHI->getNumIncomingValues(), PHI->getName() + ".sroa.phi"); for (unsigned I = 0, E = PHI->getNumIncomingValues(); I != E; ++I) { - Instruction *In = cast(PHI->getIncomingValue(I)); + BasicBlock *B = PHI->getIncomingBlock(I); + Value *NewVal = nullptr; + int Idx = NewPN->getBasicBlockIndex(B); + if (Idx >= 0) { + NewVal = NewPN->getIncomingValue(Idx); + } else { + Instruction *In = cast(PHI->getIncomingValue(I)); - IRBuilderTy B(In->getParent(), std::next(In->getIterator())); - Value *NewVal = IsInBounds - ? B.CreateInBoundsGEP(In, Index, In->getName() + ".sroa.gep") - : B.CreateGEP(In, Index, In->getName() + ".sroa.gep"); - NewPN->addIncoming(NewVal, PHI->getIncomingBlock(I)); + IRBuilderTy B(In->getParent(), std::next(In->getIterator())); + NewVal = IsInBounds + ? B.CreateInBoundsGEP(In, Index, In->getName() + ".sroa.gep") + : B.CreateGEP(In, Index, In->getName() + ".sroa.gep"); + } + NewPN->addIncoming(NewVal, B); } Visited.erase(&GEPI); @@ -3864,63 +3891,53 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { // such loads and stores, we can only pre-split them if their splits exactly // match relative to their starting offset. We have to verify this prior to // any rewriting. - Stores.erase( - llvm::remove_if(Stores, - [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) { - // Lookup the load we are storing in our map of split - // offsets. - auto *LI = cast(SI->getValueOperand()); - // If it was completely unsplittable, then we're done, - // and this store can't be pre-split. - if (UnsplittableLoads.count(LI)) - return true; - - auto LoadOffsetsI = SplitOffsetsMap.find(LI); - if (LoadOffsetsI == SplitOffsetsMap.end()) - return false; // Unrelated loads are definitely safe. - auto &LoadOffsets = LoadOffsetsI->second; - - // Now lookup the store's offsets. - auto &StoreOffsets = SplitOffsetsMap[SI]; - - // If the relative offsets of each split in the load and - // store match exactly, then we can split them and we - // don't need to remove them here. - if (LoadOffsets.Splits == StoreOffsets.Splits) - return false; - - LLVM_DEBUG( - dbgs() - << " Mismatched splits for load and store:\n" - << " " << *LI << "\n" - << " " << *SI << "\n"); - - // We've found a store and load that we need to split - // with mismatched relative splits. Just give up on them - // and remove both instructions from our list of - // candidates. - UnsplittableLoads.insert(LI); - return true; - }), - Stores.end()); + llvm::erase_if(Stores, [&UnsplittableLoads, &SplitOffsetsMap](StoreInst *SI) { + // Lookup the load we are storing in our map of split + // offsets. + auto *LI = cast(SI->getValueOperand()); + // If it was completely unsplittable, then we're done, + // and this store can't be pre-split. + if (UnsplittableLoads.count(LI)) + return true; + + auto LoadOffsetsI = SplitOffsetsMap.find(LI); + if (LoadOffsetsI == SplitOffsetsMap.end()) + return false; // Unrelated loads are definitely safe. + auto &LoadOffsets = LoadOffsetsI->second; + + // Now lookup the store's offsets. + auto &StoreOffsets = SplitOffsetsMap[SI]; + + // If the relative offsets of each split in the load and + // store match exactly, then we can split them and we + // don't need to remove them here. + if (LoadOffsets.Splits == StoreOffsets.Splits) + return false; + + LLVM_DEBUG(dbgs() << " Mismatched splits for load and store:\n" + << " " << *LI << "\n" + << " " << *SI << "\n"); + + // We've found a store and load that we need to split + // with mismatched relative splits. Just give up on them + // and remove both instructions from our list of + // candidates. + UnsplittableLoads.insert(LI); + return true; + }); // Now we have to go *back* through all the stores, because a later store may // have caused an earlier store's load to become unsplittable and if it is // unsplittable for the later store, then we can't rely on it being split in // the earlier store either. - Stores.erase(llvm::remove_if(Stores, - [&UnsplittableLoads](StoreInst *SI) { - auto *LI = - cast(SI->getValueOperand()); - return UnsplittableLoads.count(LI); - }), - Stores.end()); + llvm::erase_if(Stores, [&UnsplittableLoads](StoreInst *SI) { + auto *LI = cast(SI->getValueOperand()); + return UnsplittableLoads.count(LI); + }); // Once we've established all the loads that can't be split for some reason, // filter any that made it into our list out. - Loads.erase(llvm::remove_if(Loads, - [&UnsplittableLoads](LoadInst *LI) { - return UnsplittableLoads.count(LI); - }), - Loads.end()); + llvm::erase_if(Loads, [&UnsplittableLoads](LoadInst *LI) { + return UnsplittableLoads.count(LI); + }); // If no loads or stores are left, there is no pre-splitting to be done for // this alloca. @@ -4057,7 +4074,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { } // Mark the original store as dead. - DeadInsts.insert(SI); + DeadInsts.push_back(SI); } // Save the split loads if there are deferred stores among the users. @@ -4065,7 +4082,7 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { SplitLoadsMap.insert(std::make_pair(LI, std::move(SplitLoads))); // Mark the original load as dead and kill the original slice. - DeadInsts.insert(LI); + DeadInsts.push_back(LI); Offsets.S->kill(); } @@ -4187,15 +4204,14 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { // trivial CSE, including instcombine. if (LI->hasOneUse()) { assert(*LI->user_begin() == SI && "Single use isn't this store!"); - DeadInsts.insert(LI); + DeadInsts.push_back(LI); } - DeadInsts.insert(SI); + DeadInsts.push_back(SI); Offsets.S->kill(); } // Remove the killed slices that have ben pre-split. - AS.erase(llvm::remove_if(AS, [](const Slice &S) { return S.isDead(); }), - AS.end()); + llvm::erase_if(AS, [](const Slice &S) { return S.isDead(); }); // Insert our new slices. This will sort and merge them into the sorted // sequence. @@ -4209,11 +4225,9 @@ bool SROA::presplitLoadsAndStores(AllocaInst &AI, AllocaSlices &AS) { // Finally, don't try to promote any allocas that new require re-splitting. // They have already been added to the worklist above. - PromotableAllocas.erase( - llvm::remove_if( - PromotableAllocas, - [&](AllocaInst *AI) { return ResplitPromotableAllocas.count(AI); }), - PromotableAllocas.end()); + llvm::erase_if(PromotableAllocas, [&](AllocaInst *AI) { + return ResplitPromotableAllocas.count(AI); + }); return true; } @@ -4235,13 +4249,21 @@ AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, // or an i8 array of an appropriate size. Type *SliceTy = nullptr; const DataLayout &DL = AI.getModule()->getDataLayout(); - if (Type *CommonUseTy = findCommonType(P.begin(), P.end(), P.endOffset())) - if (DL.getTypeAllocSize(CommonUseTy).getFixedSize() >= P.size()) - SliceTy = CommonUseTy; + std::pair CommonUseTy = + findCommonType(P.begin(), P.end(), P.endOffset()); + // Do all uses operate on the same type? + if (CommonUseTy.first) + if (DL.getTypeAllocSize(CommonUseTy.first).getFixedSize() >= P.size()) + SliceTy = CommonUseTy.first; + // If not, can we find an appropriate subtype in the original allocated type? if (!SliceTy) if (Type *TypePartitionTy = getTypePartition(DL, AI.getAllocatedType(), P.beginOffset(), P.size())) SliceTy = TypePartitionTy; + // If still not, can we use the largest bitwidth integer type used? + if (!SliceTy && CommonUseTy.second) + if (DL.getTypeAllocSize(CommonUseTy.second).getFixedSize() >= P.size()) + SliceTy = CommonUseTy.second; if ((!SliceTy || (SliceTy->isArrayTy() && SliceTy->getArrayElementType()->isIntegerTy())) && DL.isLegalInteger(P.size() * 8)) @@ -4331,6 +4353,13 @@ AllocaInst *SROA::rewritePartition(AllocaInst &AI, AllocaSlices &AS, } if (Promotable) { + for (Use *U : AS.getDeadUsesIfPromotable()) { + auto *OldInst = dyn_cast(U->get()); + Value::dropDroppableUse(*U); + if (OldInst) + if (isInstructionTriviallyDead(OldInst)) + DeadInsts.push_back(OldInst); + } if (PHIUsers.empty() && SelectUsers.empty()) { // Promote the alloca. PromotableAllocas.push_back(NewAI); @@ -4465,10 +4494,8 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) { // Migrate debug information from the old alloca to the new alloca(s) // and the individual partitions. TinyPtrVector DbgDeclares = FindDbgAddrUses(&AI); - if (!DbgDeclares.empty()) { - auto *Var = DbgDeclares.front()->getVariable(); - auto *Expr = DbgDeclares.front()->getExpression(); - auto VarSize = Var->getSizeInBits(); + for (DbgVariableIntrinsic *DbgDeclare : DbgDeclares) { + auto *Expr = DbgDeclare->getExpression(); DIBuilder DIB(*AI.getModule(), /*AllowUnresolved*/ false); uint64_t AllocaSize = DL.getTypeSizeInBits(AI.getAllocatedType()).getFixedSize(); @@ -4499,6 +4526,7 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) { } // The alloca may be larger than the variable. + auto VarSize = DbgDeclare->getVariable()->getSizeInBits(); if (VarSize) { if (Size > *VarSize) Size = *VarSize; @@ -4516,12 +4544,21 @@ bool SROA::splitAlloca(AllocaInst &AI, AllocaSlices &AS) { } } - // Remove any existing intrinsics describing the same alloca. - for (DbgVariableIntrinsic *OldDII : FindDbgAddrUses(Fragment.Alloca)) - OldDII->eraseFromParent(); + // Remove any existing intrinsics on the new alloca describing + // the variable fragment. + for (DbgVariableIntrinsic *OldDII : FindDbgAddrUses(Fragment.Alloca)) { + auto SameVariableFragment = [](const DbgVariableIntrinsic *LHS, + const DbgVariableIntrinsic *RHS) { + return LHS->getVariable() == RHS->getVariable() && + LHS->getDebugLoc()->getInlinedAt() == + RHS->getDebugLoc()->getInlinedAt(); + }; + if (SameVariableFragment(OldDII, DbgDeclare)) + OldDII->eraseFromParent(); + } - DIB.insertDeclare(Fragment.Alloca, Var, FragmentExpr, - DbgDeclares.front()->getDebugLoc(), &AI); + DIB.insertDeclare(Fragment.Alloca, DbgDeclare->getVariable(), FragmentExpr, + DbgDeclare->getDebugLoc(), &AI); } } return Changed; @@ -4538,7 +4575,7 @@ void SROA::clobberUse(Use &U) { // minimal. if (Instruction *OldI = dyn_cast(OldV)) if (isInstructionTriviallyDead(OldI)) { - DeadInsts.insert(OldI); + DeadInsts.push_back(OldI); } } @@ -4587,7 +4624,7 @@ bool SROA::runOnAlloca(AllocaInst &AI) { DeadUser->replaceAllUsesWith(UndefValue::get(DeadUser->getType())); // And mark it for deletion. - DeadInsts.insert(DeadUser); + DeadInsts.push_back(DeadUser); Changed = true; } for (Use *DeadOp : AS.getDeadOperands()) { @@ -4625,7 +4662,8 @@ bool SROA::deleteDeadInstructions( SmallPtrSetImpl &DeletedAllocas) { bool Changed = false; while (!DeadInsts.empty()) { - Instruction *I = DeadInsts.pop_back_val(); + Instruction *I = dyn_cast_or_null(DeadInsts.pop_back_val()); + if (!I) continue; LLVM_DEBUG(dbgs() << "Deleting dead instruction: " << *I << "\n"); // If the instruction is an alloca, find the possible dbg.declare connected @@ -4644,7 +4682,7 @@ bool SROA::deleteDeadInstructions( // Zero out the operand and see if it becomes trivially dead. Operand = nullptr; if (isInstructionTriviallyDead(U)) - DeadInsts.insert(U); + DeadInsts.push_back(U); } ++NumDeleted; @@ -4707,8 +4745,7 @@ PreservedAnalyses SROA::runImpl(Function &F, DominatorTree &RunDT, auto IsInSet = [&](AllocaInst *AI) { return DeletedAllocas.count(AI); }; Worklist.remove_if(IsInSet); PostPromotionWorklist.remove_if(IsInSet); - PromotableAllocas.erase(llvm::remove_if(PromotableAllocas, IsInSet), - PromotableAllocas.end()); + llvm::erase_if(PromotableAllocas, IsInSet); DeletedAllocas.clear(); } } diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp index 9d088547b436..dba3dba24e25 100644 --- a/llvm/lib/Transforms/Scalar/Scalar.cpp +++ b/llvm/lib/Transforms/Scalar/Scalar.cpp @@ -34,14 +34,14 @@ using namespace llvm; /// ScalarOpts library. void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeADCELegacyPassPass(Registry); + initializeAnnotationRemarksLegacyPass(Registry); initializeBDCELegacyPassPass(Registry); initializeAlignmentFromAssumptionsPass(Registry); initializeCallSiteSplittingLegacyPassPass(Registry); initializeConstantHoistingLegacyPassPass(Registry); - initializeConstantPropagationPass(Registry); + initializeConstraintEliminationPass(Registry); initializeCorrelatedValuePropagationPass(Registry); initializeDCELegacyPassPass(Registry); - initializeDeadInstEliminationPass(Registry); initializeDivRemPairsLegacyPassPass(Registry); initializeScalarizerLegacyPassPass(Registry); initializeDSELegacyPassPass(Registry); @@ -67,22 +67,24 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializeLoopDeletionLegacyPassPass(Registry); initializeLoopAccessLegacyAnalysisPass(Registry); initializeLoopInstSimplifyLegacyPassPass(Registry); - initializeLoopInterchangePass(Registry); + initializeLoopInterchangeLegacyPassPass(Registry); + initializeLoopFlattenLegacyPassPass(Registry); initializeLoopPredicationLegacyPassPass(Registry); initializeLoopRotateLegacyPassPass(Registry); initializeLoopStrengthReducePass(Registry); - initializeLoopRerollPass(Registry); + initializeLoopRerollLegacyPassPass(Registry); initializeLoopUnrollPass(Registry); initializeLoopUnrollAndJamPass(Registry); initializeLoopUnswitchPass(Registry); initializeWarnMissedTransformationsLegacyPass(Registry); - initializeLoopVersioningLICMPass(Registry); + initializeLoopVersioningLICMLegacyPassPass(Registry); initializeLoopIdiomRecognizeLegacyPassPass(Registry); initializeLowerAtomicLegacyPassPass(Registry); initializeLowerConstantIntrinsicsPass(Registry); initializeLowerExpectIntrinsicPass(Registry); initializeLowerGuardIntrinsicLegacyPassPass(Registry); initializeLowerMatrixIntrinsicsLegacyPassPass(Registry); + initializeLowerMatrixIntrinsicsMinimalLegacyPassPass(Registry); initializeLowerWidenableConditionLegacyPassPass(Registry); initializeMemCpyOptLegacyPassPass(Registry); initializeMergeICmpsLegacyPassPass(Registry); @@ -91,25 +93,26 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) { initializePartiallyInlineLibCallsLegacyPassPass(Registry); initializeReassociateLegacyPassPass(Registry); initializeRedundantDbgInstEliminationPass(Registry); - initializeRegToMemPass(Registry); + initializeRegToMemLegacyPass(Registry); initializeRewriteStatepointsForGCLegacyPassPass(Registry); + initializeScalarizeMaskedMemIntrinLegacyPassPass(Registry); initializeSCCPLegacyPassPass(Registry); initializeSROALegacyPassPass(Registry); initializeCFGSimplifyPassPass(Registry); - initializeStructurizeCFGPass(Registry); + initializeStructurizeCFGLegacyPassPass(Registry); initializeSimpleLoopUnswitchLegacyPassPass(Registry); initializeSinkingLegacyPassPass(Registry); initializeTailCallElimPass(Registry); - initializeSeparateConstOffsetFromGEPPass(Registry); + initializeSeparateConstOffsetFromGEPLegacyPassPass(Registry); initializeSpeculativeExecutionLegacyPassPass(Registry); - initializeStraightLineStrengthReducePass(Registry); + initializeStraightLineStrengthReduceLegacyPassPass(Registry); initializePlaceBackedgeSafepointsImplPass(Registry); initializePlaceSafepointsPass(Registry); initializeFloat2IntLegacyPassPass(Registry); initializeLoopDistributeLegacyPass(Registry); initializeLoopLoadEliminationPass(Registry); initializeLoopSimplifyCFGLegacyPassPass(Registry); - initializeLoopVersioningPassPass(Registry); + initializeLoopVersioningLegacyPassPass(Registry); initializeEntryExitInstrumenterPass(Registry); initializePostInlineEntryExitInstrumenterPass(Registry); } @@ -139,7 +142,7 @@ void LLVMAddAlignmentFromAssumptionsPass(LLVMPassManagerRef PM) { } void LLVMAddCFGSimplificationPass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createCFGSimplificationPass(1, false, false, true)); + unwrap(PM)->add(createCFGSimplificationPass()); } void LLVMAddDeadStoreEliminationPass(LLVMPassManagerRef PM) { @@ -166,6 +169,10 @@ void LLVMAddIndVarSimplifyPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createIndVarSimplifyPass()); } +void LLVMAddInstructionSimplifyPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createInstSimplifyLegacyPass()); +} + void LLVMAddJumpThreadingPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createJumpThreadingPass()); } @@ -182,6 +189,10 @@ void LLVMAddLoopDeletionPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createLoopDeletionPass()); } +void LLVMAddLoopFlattenPass(LLVMPassManagerRef PM) { + unwrap(PM)->add(createLoopFlattenPass()); +} + void LLVMAddLoopIdiomPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createLoopIdiomPass()); } @@ -247,10 +258,6 @@ void LLVMAddTailCallEliminationPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createTailCallEliminationPass()); } -void LLVMAddConstantPropagationPass(LLVMPassManagerRef PM) { - unwrap(PM)->add(createConstantPropagationPass()); -} - void LLVMAddDemoteMemoryToRegisterPass(LLVMPassManagerRef PM) { unwrap(PM)->add(createDemoteRegisterToMemoryPass()); } diff --git a/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp b/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp new file mode 100644 index 000000000000..afa2d1bc7966 --- /dev/null +++ b/llvm/lib/Transforms/Scalar/ScalarizeMaskedMemIntrin.cpp @@ -0,0 +1,948 @@ +//===- ScalarizeMaskedMemIntrin.cpp - Scalarize unsupported masked mem ----===// +// instrinsics +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This pass replaces masked memory intrinsics - when unsupported by the target +// - with a chain of basic blocks, that deal with the elements one-by-one if the +// appropriate mask bit is set. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constant.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/IntrinsicInst.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Value.h" +#include "llvm/InitializePasses.h" +#include "llvm/Pass.h" +#include "llvm/Support/Casting.h" +#include "llvm/Transforms/Scalar.h" +#include +#include + +using namespace llvm; + +#define DEBUG_TYPE "scalarize-masked-mem-intrin" + +namespace { + +class ScalarizeMaskedMemIntrinLegacyPass : public FunctionPass { +public: + static char ID; // Pass identification, replacement for typeid + + explicit ScalarizeMaskedMemIntrinLegacyPass() : FunctionPass(ID) { + initializeScalarizeMaskedMemIntrinLegacyPassPass( + *PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override; + + StringRef getPassName() const override { + return "Scalarize Masked Memory Intrinsics"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } +}; + +} // end anonymous namespace + +static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, + const TargetTransformInfo &TTI, const DataLayout &DL); +static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT, + const TargetTransformInfo &TTI, + const DataLayout &DL); + +char ScalarizeMaskedMemIntrinLegacyPass::ID = 0; + +INITIALIZE_PASS_BEGIN(ScalarizeMaskedMemIntrinLegacyPass, DEBUG_TYPE, + "Scalarize unsupported masked memory intrinsics", false, + false) +INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_END(ScalarizeMaskedMemIntrinLegacyPass, DEBUG_TYPE, + "Scalarize unsupported masked memory intrinsics", false, + false) + +FunctionPass *llvm::createScalarizeMaskedMemIntrinLegacyPass() { + return new ScalarizeMaskedMemIntrinLegacyPass(); +} + +static bool isConstantIntVector(Value *Mask) { + Constant *C = dyn_cast(Mask); + if (!C) + return false; + + unsigned NumElts = cast(Mask->getType())->getNumElements(); + for (unsigned i = 0; i != NumElts; ++i) { + Constant *CElt = C->getAggregateElement(i); + if (!CElt || !isa(CElt)) + return false; + } + + return true; +} + +// Translate a masked load intrinsic like +// <16 x i32 > @llvm.masked.load( <16 x i32>* %addr, i32 align, +// <16 x i1> %mask, <16 x i32> %passthru) +// to a chain of basic blocks, with loading element one-by-one if +// the appropriate mask bit is set +// +// %1 = bitcast i8* %addr to i32* +// %2 = extractelement <16 x i1> %mask, i32 0 +// br i1 %2, label %cond.load, label %else +// +// cond.load: ; preds = %0 +// %3 = getelementptr i32* %1, i32 0 +// %4 = load i32* %3 +// %5 = insertelement <16 x i32> %passthru, i32 %4, i32 0 +// br label %else +// +// else: ; preds = %0, %cond.load +// %res.phi.else = phi <16 x i32> [ %5, %cond.load ], [ undef, %0 ] +// %6 = extractelement <16 x i1> %mask, i32 1 +// br i1 %6, label %cond.load1, label %else2 +// +// cond.load1: ; preds = %else +// %7 = getelementptr i32* %1, i32 1 +// %8 = load i32* %7 +// %9 = insertelement <16 x i32> %res.phi.else, i32 %8, i32 1 +// br label %else2 +// +// else2: ; preds = %else, %cond.load1 +// %res.phi.else3 = phi <16 x i32> [ %9, %cond.load1 ], [ %res.phi.else, %else ] +// %10 = extractelement <16 x i1> %mask, i32 2 +// br i1 %10, label %cond.load4, label %else5 +// +static void scalarizeMaskedLoad(CallInst *CI, bool &ModifiedDT) { + Value *Ptr = CI->getArgOperand(0); + Value *Alignment = CI->getArgOperand(1); + Value *Mask = CI->getArgOperand(2); + Value *Src0 = CI->getArgOperand(3); + + const Align AlignVal = cast(Alignment)->getAlignValue(); + VectorType *VecType = cast(CI->getType()); + + Type *EltTy = VecType->getElementType(); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + + Builder.SetInsertPoint(InsertPt); + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + // Short-cut if the mask is all-true. + if (isa(Mask) && cast(Mask)->isAllOnesValue()) { + Value *NewI = Builder.CreateAlignedLoad(VecType, Ptr, AlignVal); + CI->replaceAllUsesWith(NewI); + CI->eraseFromParent(); + return; + } + + // Adjust alignment for the scalar instruction. + const Align AdjustedAlignVal = + commonAlignment(AlignVal, EltTy->getPrimitiveSizeInBits() / 8); + // Bitcast %addr from i8* to EltTy* + Type *NewPtrType = + EltTy->getPointerTo(Ptr->getType()->getPointerAddressSpace()); + Value *FirstEltPtr = Builder.CreateBitCast(Ptr, NewPtrType); + unsigned VectorWidth = cast(VecType)->getNumElements(); + + // The result vector + Value *VResult = Src0; + + if (isConstantIntVector(Mask)) { + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) + continue; + Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx); + LoadInst *Load = Builder.CreateAlignedLoad(EltTy, Gep, AdjustedAlignVal); + VResult = Builder.CreateInsertElement(VResult, Load, Idx); + } + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %res.phi.else3 = phi <16 x i32> [ %11, %cond.load1 ], [ %res.phi.else, %else ] + // %mask_1 = and i16 %scalar_mask, i32 1 << Idx + // %cond = icmp ne i16 %mask_1, 0 + // br i1 %mask_1, label %cond.load, label %else + // + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx); + } + + // Create "cond" block + // + // %EltAddr = getelementptr i32* %1, i32 0 + // %Elt = load i32* %EltAddr + // VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx + // + BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt->getIterator(), + "cond.load"); + Builder.SetInsertPoint(InsertPt); + + Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx); + LoadInst *Load = Builder.CreateAlignedLoad(EltTy, Gep, AdjustedAlignVal); + Value *NewVResult = Builder.CreateInsertElement(VResult, Load, Idx); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = + CondBlock->splitBasicBlock(InsertPt->getIterator(), "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + BasicBlock *PrevIfBlock = IfBlock; + IfBlock = NewIfBlock; + + // Create the phi to join the new and previous value. + PHINode *Phi = Builder.CreatePHI(VecType, 2, "res.phi.else"); + Phi->addIncoming(NewVResult, CondBlock); + Phi->addIncoming(VResult, PrevIfBlock); + VResult = Phi; + } + + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + + ModifiedDT = true; +} + +// Translate a masked store intrinsic, like +// void @llvm.masked.store(<16 x i32> %src, <16 x i32>* %addr, i32 align, +// <16 x i1> %mask) +// to a chain of basic blocks, that stores element one-by-one if +// the appropriate mask bit is set +// +// %1 = bitcast i8* %addr to i32* +// %2 = extractelement <16 x i1> %mask, i32 0 +// br i1 %2, label %cond.store, label %else +// +// cond.store: ; preds = %0 +// %3 = extractelement <16 x i32> %val, i32 0 +// %4 = getelementptr i32* %1, i32 0 +// store i32 %3, i32* %4 +// br label %else +// +// else: ; preds = %0, %cond.store +// %5 = extractelement <16 x i1> %mask, i32 1 +// br i1 %5, label %cond.store1, label %else2 +// +// cond.store1: ; preds = %else +// %6 = extractelement <16 x i32> %val, i32 1 +// %7 = getelementptr i32* %1, i32 1 +// store i32 %6, i32* %7 +// br label %else2 +// . . . +static void scalarizeMaskedStore(CallInst *CI, bool &ModifiedDT) { + Value *Src = CI->getArgOperand(0); + Value *Ptr = CI->getArgOperand(1); + Value *Alignment = CI->getArgOperand(2); + Value *Mask = CI->getArgOperand(3); + + const Align AlignVal = cast(Alignment)->getAlignValue(); + auto *VecType = cast(Src->getType()); + + Type *EltTy = VecType->getElementType(); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + Builder.SetInsertPoint(InsertPt); + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + // Short-cut if the mask is all-true. + if (isa(Mask) && cast(Mask)->isAllOnesValue()) { + Builder.CreateAlignedStore(Src, Ptr, AlignVal); + CI->eraseFromParent(); + return; + } + + // Adjust alignment for the scalar instruction. + const Align AdjustedAlignVal = + commonAlignment(AlignVal, EltTy->getPrimitiveSizeInBits() / 8); + // Bitcast %addr from i8* to EltTy* + Type *NewPtrType = + EltTy->getPointerTo(Ptr->getType()->getPointerAddressSpace()); + Value *FirstEltPtr = Builder.CreateBitCast(Ptr, NewPtrType); + unsigned VectorWidth = cast(VecType)->getNumElements(); + + if (isConstantIntVector(Mask)) { + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) + continue; + Value *OneElt = Builder.CreateExtractElement(Src, Idx); + Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx); + Builder.CreateAlignedStore(OneElt, Gep, AdjustedAlignVal); + } + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %mask_1 = and i16 %scalar_mask, i32 1 << Idx + // %cond = icmp ne i16 %mask_1, 0 + // br i1 %mask_1, label %cond.store, label %else + // + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx); + } + + // Create "cond" block + // + // %OneElt = extractelement <16 x i32> %Src, i32 Idx + // %EltAddr = getelementptr i32* %1, i32 0 + // %store i32 %OneElt, i32* %EltAddr + // + BasicBlock *CondBlock = + IfBlock->splitBasicBlock(InsertPt->getIterator(), "cond.store"); + Builder.SetInsertPoint(InsertPt); + + Value *OneElt = Builder.CreateExtractElement(Src, Idx); + Value *Gep = Builder.CreateConstInBoundsGEP1_32(EltTy, FirstEltPtr, Idx); + Builder.CreateAlignedStore(OneElt, Gep, AdjustedAlignVal); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = + CondBlock->splitBasicBlock(InsertPt->getIterator(), "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + IfBlock = NewIfBlock; + } + CI->eraseFromParent(); + + ModifiedDT = true; +} + +// Translate a masked gather intrinsic like +// <16 x i32 > @llvm.masked.gather.v16i32( <16 x i32*> %Ptrs, i32 4, +// <16 x i1> %Mask, <16 x i32> %Src) +// to a chain of basic blocks, with loading element one-by-one if +// the appropriate mask bit is set +// +// %Ptrs = getelementptr i32, i32* %base, <16 x i64> %ind +// %Mask0 = extractelement <16 x i1> %Mask, i32 0 +// br i1 %Mask0, label %cond.load, label %else +// +// cond.load: +// %Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0 +// %Load0 = load i32, i32* %Ptr0, align 4 +// %Res0 = insertelement <16 x i32> undef, i32 %Load0, i32 0 +// br label %else +// +// else: +// %res.phi.else = phi <16 x i32>[%Res0, %cond.load], [undef, %0] +// %Mask1 = extractelement <16 x i1> %Mask, i32 1 +// br i1 %Mask1, label %cond.load1, label %else2 +// +// cond.load1: +// %Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1 +// %Load1 = load i32, i32* %Ptr1, align 4 +// %Res1 = insertelement <16 x i32> %res.phi.else, i32 %Load1, i32 1 +// br label %else2 +// . . . +// %Result = select <16 x i1> %Mask, <16 x i32> %res.phi.select, <16 x i32> %Src +// ret <16 x i32> %Result +static void scalarizeMaskedGather(CallInst *CI, bool &ModifiedDT) { + Value *Ptrs = CI->getArgOperand(0); + Value *Alignment = CI->getArgOperand(1); + Value *Mask = CI->getArgOperand(2); + Value *Src0 = CI->getArgOperand(3); + + auto *VecType = cast(CI->getType()); + Type *EltTy = VecType->getElementType(); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + Builder.SetInsertPoint(InsertPt); + MaybeAlign AlignVal = cast(Alignment)->getMaybeAlignValue(); + + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + // The result vector + Value *VResult = Src0; + unsigned VectorWidth = VecType->getNumElements(); + + // Shorten the way if the mask is a vector of constants. + if (isConstantIntVector(Mask)) { + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) + continue; + Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx)); + LoadInst *Load = + Builder.CreateAlignedLoad(EltTy, Ptr, AlignVal, "Load" + Twine(Idx)); + VResult = + Builder.CreateInsertElement(VResult, Load, Idx, "Res" + Twine(Idx)); + } + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %Mask1 = and i16 %scalar_mask, i32 1 << Idx + // %cond = icmp ne i16 %mask_1, 0 + // br i1 %Mask1, label %cond.load, label %else + // + + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx, "Mask" + Twine(Idx)); + } + + // Create "cond" block + // + // %EltAddr = getelementptr i32* %1, i32 0 + // %Elt = load i32* %EltAddr + // VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx + // + BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt, "cond.load"); + Builder.SetInsertPoint(InsertPt); + + Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx)); + LoadInst *Load = + Builder.CreateAlignedLoad(EltTy, Ptr, AlignVal, "Load" + Twine(Idx)); + Value *NewVResult = + Builder.CreateInsertElement(VResult, Load, Idx, "Res" + Twine(Idx)); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = CondBlock->splitBasicBlock(InsertPt, "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + BasicBlock *PrevIfBlock = IfBlock; + IfBlock = NewIfBlock; + + PHINode *Phi = Builder.CreatePHI(VecType, 2, "res.phi.else"); + Phi->addIncoming(NewVResult, CondBlock); + Phi->addIncoming(VResult, PrevIfBlock); + VResult = Phi; + } + + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + + ModifiedDT = true; +} + +// Translate a masked scatter intrinsic, like +// void @llvm.masked.scatter.v16i32(<16 x i32> %Src, <16 x i32*>* %Ptrs, i32 4, +// <16 x i1> %Mask) +// to a chain of basic blocks, that stores element one-by-one if +// the appropriate mask bit is set. +// +// %Ptrs = getelementptr i32, i32* %ptr, <16 x i64> %ind +// %Mask0 = extractelement <16 x i1> %Mask, i32 0 +// br i1 %Mask0, label %cond.store, label %else +// +// cond.store: +// %Elt0 = extractelement <16 x i32> %Src, i32 0 +// %Ptr0 = extractelement <16 x i32*> %Ptrs, i32 0 +// store i32 %Elt0, i32* %Ptr0, align 4 +// br label %else +// +// else: +// %Mask1 = extractelement <16 x i1> %Mask, i32 1 +// br i1 %Mask1, label %cond.store1, label %else2 +// +// cond.store1: +// %Elt1 = extractelement <16 x i32> %Src, i32 1 +// %Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1 +// store i32 %Elt1, i32* %Ptr1, align 4 +// br label %else2 +// . . . +static void scalarizeMaskedScatter(CallInst *CI, bool &ModifiedDT) { + Value *Src = CI->getArgOperand(0); + Value *Ptrs = CI->getArgOperand(1); + Value *Alignment = CI->getArgOperand(2); + Value *Mask = CI->getArgOperand(3); + + auto *SrcFVTy = cast(Src->getType()); + + assert( + isa(Ptrs->getType()) && + isa(cast(Ptrs->getType())->getElementType()) && + "Vector of pointers is expected in masked scatter intrinsic"); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + Builder.SetInsertPoint(InsertPt); + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + MaybeAlign AlignVal = cast(Alignment)->getMaybeAlignValue(); + unsigned VectorWidth = SrcFVTy->getNumElements(); + + // Shorten the way if the mask is a vector of constants. + if (isConstantIntVector(Mask)) { + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) + continue; + Value *OneElt = + Builder.CreateExtractElement(Src, Idx, "Elt" + Twine(Idx)); + Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx)); + Builder.CreateAlignedStore(OneElt, Ptr, AlignVal); + } + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %Mask1 = and i16 %scalar_mask, i32 1 << Idx + // %cond = icmp ne i16 %mask_1, 0 + // br i1 %Mask1, label %cond.store, label %else + // + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx, "Mask" + Twine(Idx)); + } + + // Create "cond" block + // + // %Elt1 = extractelement <16 x i32> %Src, i32 1 + // %Ptr1 = extractelement <16 x i32*> %Ptrs, i32 1 + // %store i32 %Elt1, i32* %Ptr1 + // + BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt, "cond.store"); + Builder.SetInsertPoint(InsertPt); + + Value *OneElt = Builder.CreateExtractElement(Src, Idx, "Elt" + Twine(Idx)); + Value *Ptr = Builder.CreateExtractElement(Ptrs, Idx, "Ptr" + Twine(Idx)); + Builder.CreateAlignedStore(OneElt, Ptr, AlignVal); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = CondBlock->splitBasicBlock(InsertPt, "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + IfBlock = NewIfBlock; + } + CI->eraseFromParent(); + + ModifiedDT = true; +} + +static void scalarizeMaskedExpandLoad(CallInst *CI, bool &ModifiedDT) { + Value *Ptr = CI->getArgOperand(0); + Value *Mask = CI->getArgOperand(1); + Value *PassThru = CI->getArgOperand(2); + + auto *VecType = cast(CI->getType()); + + Type *EltTy = VecType->getElementType(); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + + Builder.SetInsertPoint(InsertPt); + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + unsigned VectorWidth = VecType->getNumElements(); + + // The result vector + Value *VResult = PassThru; + + // Shorten the way if the mask is a vector of constants. + // Create a build_vector pattern, with loads/undefs as necessary and then + // shuffle blend with the pass through value. + if (isConstantIntVector(Mask)) { + unsigned MemIndex = 0; + VResult = UndefValue::get(VecType); + SmallVector ShuffleMask(VectorWidth, UndefMaskElem); + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + Value *InsertElt; + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) { + InsertElt = UndefValue::get(EltTy); + ShuffleMask[Idx] = Idx + VectorWidth; + } else { + Value *NewPtr = + Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, MemIndex); + InsertElt = Builder.CreateAlignedLoad(EltTy, NewPtr, Align(1), + "Load" + Twine(Idx)); + ShuffleMask[Idx] = Idx; + ++MemIndex; + } + VResult = Builder.CreateInsertElement(VResult, InsertElt, Idx, + "Res" + Twine(Idx)); + } + VResult = Builder.CreateShuffleVector(VResult, PassThru, ShuffleMask); + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %res.phi.else3 = phi <16 x i32> [ %11, %cond.load1 ], [ %res.phi.else, %else ] + // %mask_1 = extractelement <16 x i1> %mask, i32 Idx + // br i1 %mask_1, label %cond.load, label %else + // + + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx, "Mask" + Twine(Idx)); + } + + // Create "cond" block + // + // %EltAddr = getelementptr i32* %1, i32 0 + // %Elt = load i32* %EltAddr + // VResult = insertelement <16 x i32> VResult, i32 %Elt, i32 Idx + // + BasicBlock *CondBlock = IfBlock->splitBasicBlock(InsertPt->getIterator(), + "cond.load"); + Builder.SetInsertPoint(InsertPt); + + LoadInst *Load = Builder.CreateAlignedLoad(EltTy, Ptr, Align(1)); + Value *NewVResult = Builder.CreateInsertElement(VResult, Load, Idx); + + // Move the pointer if there are more blocks to come. + Value *NewPtr; + if ((Idx + 1) != VectorWidth) + NewPtr = Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, 1); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = + CondBlock->splitBasicBlock(InsertPt->getIterator(), "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + BasicBlock *PrevIfBlock = IfBlock; + IfBlock = NewIfBlock; + + // Create the phi to join the new and previous value. + PHINode *ResultPhi = Builder.CreatePHI(VecType, 2, "res.phi.else"); + ResultPhi->addIncoming(NewVResult, CondBlock); + ResultPhi->addIncoming(VResult, PrevIfBlock); + VResult = ResultPhi; + + // Add a PHI for the pointer if this isn't the last iteration. + if ((Idx + 1) != VectorWidth) { + PHINode *PtrPhi = Builder.CreatePHI(Ptr->getType(), 2, "ptr.phi.else"); + PtrPhi->addIncoming(NewPtr, CondBlock); + PtrPhi->addIncoming(Ptr, PrevIfBlock); + Ptr = PtrPhi; + } + } + + CI->replaceAllUsesWith(VResult); + CI->eraseFromParent(); + + ModifiedDT = true; +} + +static void scalarizeMaskedCompressStore(CallInst *CI, bool &ModifiedDT) { + Value *Src = CI->getArgOperand(0); + Value *Ptr = CI->getArgOperand(1); + Value *Mask = CI->getArgOperand(2); + + auto *VecType = cast(Src->getType()); + + IRBuilder<> Builder(CI->getContext()); + Instruction *InsertPt = CI; + BasicBlock *IfBlock = CI->getParent(); + + Builder.SetInsertPoint(InsertPt); + Builder.SetCurrentDebugLocation(CI->getDebugLoc()); + + Type *EltTy = VecType->getElementType(); + + unsigned VectorWidth = VecType->getNumElements(); + + // Shorten the way if the mask is a vector of constants. + if (isConstantIntVector(Mask)) { + unsigned MemIndex = 0; + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + if (cast(Mask)->getAggregateElement(Idx)->isNullValue()) + continue; + Value *OneElt = + Builder.CreateExtractElement(Src, Idx, "Elt" + Twine(Idx)); + Value *NewPtr = Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, MemIndex); + Builder.CreateAlignedStore(OneElt, NewPtr, Align(1)); + ++MemIndex; + } + CI->eraseFromParent(); + return; + } + + // If the mask is not v1i1, use scalar bit test operations. This generates + // better results on X86 at least. + Value *SclrMask; + if (VectorWidth != 1) { + Type *SclrMaskTy = Builder.getIntNTy(VectorWidth); + SclrMask = Builder.CreateBitCast(Mask, SclrMaskTy, "scalar_mask"); + } + + for (unsigned Idx = 0; Idx < VectorWidth; ++Idx) { + // Fill the "else" block, created in the previous iteration + // + // %mask_1 = extractelement <16 x i1> %mask, i32 Idx + // br i1 %mask_1, label %cond.store, label %else + // + Value *Predicate; + if (VectorWidth != 1) { + Value *Mask = Builder.getInt(APInt::getOneBitSet(VectorWidth, Idx)); + Predicate = Builder.CreateICmpNE(Builder.CreateAnd(SclrMask, Mask), + Builder.getIntN(VectorWidth, 0)); + } else { + Predicate = Builder.CreateExtractElement(Mask, Idx, "Mask" + Twine(Idx)); + } + + // Create "cond" block + // + // %OneElt = extractelement <16 x i32> %Src, i32 Idx + // %EltAddr = getelementptr i32* %1, i32 0 + // %store i32 %OneElt, i32* %EltAddr + // + BasicBlock *CondBlock = + IfBlock->splitBasicBlock(InsertPt->getIterator(), "cond.store"); + Builder.SetInsertPoint(InsertPt); + + Value *OneElt = Builder.CreateExtractElement(Src, Idx); + Builder.CreateAlignedStore(OneElt, Ptr, Align(1)); + + // Move the pointer if there are more blocks to come. + Value *NewPtr; + if ((Idx + 1) != VectorWidth) + NewPtr = Builder.CreateConstInBoundsGEP1_32(EltTy, Ptr, 1); + + // Create "else" block, fill it in the next iteration + BasicBlock *NewIfBlock = + CondBlock->splitBasicBlock(InsertPt->getIterator(), "else"); + Builder.SetInsertPoint(InsertPt); + Instruction *OldBr = IfBlock->getTerminator(); + BranchInst::Create(CondBlock, NewIfBlock, Predicate, OldBr); + OldBr->eraseFromParent(); + BasicBlock *PrevIfBlock = IfBlock; + IfBlock = NewIfBlock; + + // Add a PHI for the pointer if this isn't the last iteration. + if ((Idx + 1) != VectorWidth) { + PHINode *PtrPhi = Builder.CreatePHI(Ptr->getType(), 2, "ptr.phi.else"); + PtrPhi->addIncoming(NewPtr, CondBlock); + PtrPhi->addIncoming(Ptr, PrevIfBlock); + Ptr = PtrPhi; + } + } + CI->eraseFromParent(); + + ModifiedDT = true; +} + +static bool runImpl(Function &F, const TargetTransformInfo &TTI) { + bool EverMadeChange = false; + bool MadeChange = true; + auto &DL = F.getParent()->getDataLayout(); + while (MadeChange) { + MadeChange = false; + for (Function::iterator I = F.begin(); I != F.end();) { + BasicBlock *BB = &*I++; + bool ModifiedDTOnIteration = false; + MadeChange |= optimizeBlock(*BB, ModifiedDTOnIteration, TTI, DL); + + // Restart BB iteration if the dominator tree of the Function was changed + if (ModifiedDTOnIteration) + break; + } + + EverMadeChange |= MadeChange; + } + return EverMadeChange; +} + +bool ScalarizeMaskedMemIntrinLegacyPass::runOnFunction(Function &F) { + auto &TTI = getAnalysis().getTTI(F); + return runImpl(F, TTI); +} + +PreservedAnalyses +ScalarizeMaskedMemIntrinPass::run(Function &F, FunctionAnalysisManager &AM) { + auto &TTI = AM.getResult(F); + if (!runImpl(F, TTI)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + return PA; +} + +static bool optimizeBlock(BasicBlock &BB, bool &ModifiedDT, + const TargetTransformInfo &TTI, + const DataLayout &DL) { + bool MadeChange = false; + + BasicBlock::iterator CurInstIterator = BB.begin(); + while (CurInstIterator != BB.end()) { + if (CallInst *CI = dyn_cast(&*CurInstIterator++)) + MadeChange |= optimizeCallInst(CI, ModifiedDT, TTI, DL); + if (ModifiedDT) + return true; + } + + return MadeChange; +} + +static bool optimizeCallInst(CallInst *CI, bool &ModifiedDT, + const TargetTransformInfo &TTI, + const DataLayout &DL) { + IntrinsicInst *II = dyn_cast(CI); + if (II) { + // The scalarization code below does not work for scalable vectors. + if (isa(II->getType()) || + any_of(II->arg_operands(), + [](Value *V) { return isa(V->getType()); })) + return false; + + switch (II->getIntrinsicID()) { + default: + break; + case Intrinsic::masked_load: + // Scalarize unsupported vector masked load + if (TTI.isLegalMaskedLoad( + CI->getType(), + cast(CI->getArgOperand(1))->getAlignValue())) + return false; + scalarizeMaskedLoad(CI, ModifiedDT); + return true; + case Intrinsic::masked_store: + if (TTI.isLegalMaskedStore( + CI->getArgOperand(0)->getType(), + cast(CI->getArgOperand(2))->getAlignValue())) + return false; + scalarizeMaskedStore(CI, ModifiedDT); + return true; + case Intrinsic::masked_gather: { + unsigned AlignmentInt = + cast(CI->getArgOperand(1))->getZExtValue(); + Type *LoadTy = CI->getType(); + Align Alignment = + DL.getValueOrABITypeAlignment(MaybeAlign(AlignmentInt), LoadTy); + if (TTI.isLegalMaskedGather(LoadTy, Alignment)) + return false; + scalarizeMaskedGather(CI, ModifiedDT); + return true; + } + case Intrinsic::masked_scatter: { + unsigned AlignmentInt = + cast(CI->getArgOperand(2))->getZExtValue(); + Type *StoreTy = CI->getArgOperand(0)->getType(); + Align Alignment = + DL.getValueOrABITypeAlignment(MaybeAlign(AlignmentInt), StoreTy); + if (TTI.isLegalMaskedScatter(StoreTy, Alignment)) + return false; + scalarizeMaskedScatter(CI, ModifiedDT); + return true; + } + case Intrinsic::masked_expandload: + if (TTI.isLegalMaskedExpandLoad(CI->getType())) + return false; + scalarizeMaskedExpandLoad(CI, ModifiedDT); + return true; + case Intrinsic::masked_compressstore: + if (TTI.isLegalMaskedCompressStore(CI->getArgOperand(0)->getType())) + return false; + scalarizeMaskedCompressStore(CI, ModifiedDT); + return true; + } + } + + return false; +} diff --git a/llvm/lib/Transforms/Scalar/Scalarizer.cpp b/llvm/lib/Transforms/Scalar/Scalarizer.cpp index 851bd79cd6d8..c95984fe198f 100644 --- a/llvm/lib/Transforms/Scalar/Scalarizer.cpp +++ b/llvm/lib/Transforms/Scalar/Scalarizer.cpp @@ -398,7 +398,8 @@ void ScalarizerVisitor::gather(Instruction *Op, const ValueVector &CV) { continue; Instruction *Old = cast(V); - CV[I]->takeName(Old); + if (isa(CV[I])) + CV[I]->takeName(Old); Old->replaceAllUsesWith(CV[I]); PotentiallyDeadInstrs.emplace_back(Old); } @@ -732,7 +733,7 @@ bool ScalarizerVisitor::visitBitCastInst(BitCastInst &BCI) { auto *MidTy = FixedVectorType::get(SrcVT->getElementType(), FanIn); unsigned Op0I = 0; for (unsigned ResI = 0; ResI < DstNumElems; ++ResI) { - Value *V = UndefValue::get(MidTy); + Value *V = PoisonValue::get(MidTy); for (unsigned MidI = 0; MidI < FanIn; ++MidI) V = Builder.CreateInsertElement(V, Op0[Op0I++], Builder.getInt32(MidI), BCI.getName() + ".i" + Twine(ResI) @@ -931,7 +932,7 @@ bool ScalarizerVisitor::finish() { if (!Op->use_empty()) { // The value is still needed, so recreate it using a series of // InsertElements. - Value *Res = UndefValue::get(Op->getType()); + Value *Res = PoisonValue::get(Op->getType()); if (auto *Ty = dyn_cast(Op->getType())) { BasicBlock *BB = Op->getParent(); unsigned Count = cast(Ty)->getNumElements(); @@ -941,13 +942,13 @@ bool ScalarizerVisitor::finish() { for (unsigned I = 0; I < Count; ++I) Res = Builder.CreateInsertElement(Res, CV[I], Builder.getInt32(I), Op->getName() + ".upto" + Twine(I)); + Res->takeName(Op); } else { assert(CV.size() == 1 && Op->getType() == CV[0]->getType()); Res = CV[0]; if (Op == Res) continue; } - Res->takeName(Op); Op->replaceAllUsesWith(Res); } PotentiallyDeadInstrs.emplace_back(Op); diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp index f1d2e3c1ecfa..f216956406b6 100644 --- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -155,6 +155,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DepthFirstIterator.h" @@ -177,6 +178,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/User.h" @@ -342,13 +344,14 @@ private: /// A pass that tries to split every GEP in the function into a variadic /// base and a constant offset. It is a FunctionPass because searching for the /// constant offset may inspect other basic blocks. -class SeparateConstOffsetFromGEP : public FunctionPass { +class SeparateConstOffsetFromGEPLegacyPass : public FunctionPass { public: static char ID; - SeparateConstOffsetFromGEP(bool LowerGEP = false) + SeparateConstOffsetFromGEPLegacyPass(bool LowerGEP = false) : FunctionPass(ID), LowerGEP(LowerGEP) { - initializeSeparateConstOffsetFromGEPPass(*PassRegistry::getPassRegistry()); + initializeSeparateConstOffsetFromGEPLegacyPassPass( + *PassRegistry::getPassRegistry()); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -360,13 +363,25 @@ public: AU.addRequired(); } - bool doInitialization(Module &M) override { - DL = &M.getDataLayout(); - return false; - } - bool runOnFunction(Function &F) override; +private: + bool LowerGEP; +}; + +/// A pass that tries to split every GEP in the function into a variadic +/// base and a constant offset. It is a FunctionPass because searching for the +/// constant offset may inspect other basic blocks. +class SeparateConstOffsetFromGEP { +public: + SeparateConstOffsetFromGEP( + DominatorTree *DT, ScalarEvolution *SE, LoopInfo *LI, + TargetLibraryInfo *TLI, + function_ref GetTTI, bool LowerGEP) + : DT(DT), SE(SE), LI(LI), TLI(TLI), GetTTI(GetTTI), LowerGEP(LowerGEP) {} + + bool run(Function &F); + private: /// Tries to split the given GEP into a variadic base and a constant offset, /// and returns true if the splitting succeeds. @@ -450,9 +465,10 @@ private: const DataLayout *DL = nullptr; DominatorTree *DT = nullptr; ScalarEvolution *SE; - LoopInfo *LI; TargetLibraryInfo *TLI; + // Retrieved lazily since not always used. + function_ref GetTTI; /// Whether to lower a GEP with multiple indices into arithmetic operations or /// multiple GEPs with a single index. @@ -464,10 +480,10 @@ private: } // end anonymous namespace -char SeparateConstOffsetFromGEP::ID = 0; +char SeparateConstOffsetFromGEPLegacyPass::ID = 0; INITIALIZE_PASS_BEGIN( - SeparateConstOffsetFromGEP, "separate-const-offset-from-gep", + SeparateConstOffsetFromGEPLegacyPass, "separate-const-offset-from-gep", "Split GEPs to a variadic base and a constant offset for better CSE", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) @@ -476,12 +492,12 @@ INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_END( - SeparateConstOffsetFromGEP, "separate-const-offset-from-gep", + SeparateConstOffsetFromGEPLegacyPass, "separate-const-offset-from-gep", "Split GEPs to a variadic base and a constant offset for better CSE", false, false) FunctionPass *llvm::createSeparateConstOffsetFromGEPPass(bool LowerGEP) { - return new SeparateConstOffsetFromGEP(LowerGEP); + return new SeparateConstOffsetFromGEPLegacyPass(LowerGEP); } bool ConstantOffsetExtractor::CanTraceInto(bool SignExtended, @@ -886,8 +902,8 @@ void SeparateConstOffsetFromGEP::lowerToSingleIndexGEPs( // If we created a GEP with constant index, and the base is loop invariant, // then we swap the first one with it, so LICM can move constant GEP out // later. - GetElementPtrInst *FirstGEP = dyn_cast_or_null(FirstResult); - GetElementPtrInst *SecondGEP = dyn_cast_or_null(ResultPtr); + auto *FirstGEP = dyn_cast_or_null(FirstResult); + auto *SecondGEP = dyn_cast(ResultPtr); if (isSwapCandidate && isLegalToSwapOperand(FirstGEP, SecondGEP, L)) swapGEPOperand(FirstGEP, SecondGEP); @@ -962,8 +978,7 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) { if (!NeedsExtraction) return Changed; - TargetTransformInfo &TTI = - getAnalysis().getTTI(*GEP->getFunction()); + TargetTransformInfo &TTI = GetTTI(*GEP->getFunction()); // If LowerGEP is disabled, before really splitting the GEP, check whether the // backend supports the addressing mode we are about to produce. If no, this @@ -1128,17 +1143,25 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) { return true; } -bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) { +bool SeparateConstOffsetFromGEPLegacyPass::runOnFunction(Function &F) { if (skipFunction(F)) return false; + auto *DT = &getAnalysis().getDomTree(); + auto *SE = &getAnalysis().getSE(); + auto *LI = &getAnalysis().getLoopInfo(); + auto *TLI = &getAnalysis().getTLI(F); + auto GetTTI = [this](Function &F) -> TargetTransformInfo & { + return this->getAnalysis().getTTI(F); + }; + SeparateConstOffsetFromGEP Impl(DT, SE, LI, TLI, GetTTI, LowerGEP); + return Impl.run(F); +} +bool SeparateConstOffsetFromGEP::run(Function &F) { if (DisableSeparateConstOffsetFromGEP) return false; - DT = &getAnalysis().getDomTree(); - SE = &getAnalysis().getSE(); - LI = &getAnalysis().getLoopInfo(); - TLI = &getAnalysis().getTLI(F); + DL = &F.getParent()->getDataLayout(); bool Changed = false; for (BasicBlock &B : F) { for (BasicBlock::iterator I = B.begin(), IE = B.end(); I != IE;) @@ -1345,3 +1368,20 @@ void SeparateConstOffsetFromGEP::swapGEPOperand(GetElementPtrInst *First, } else First->setIsInBounds(true); } + +PreservedAnalyses +SeparateConstOffsetFromGEPPass::run(Function &F, FunctionAnalysisManager &AM) { + auto *DT = &AM.getResult(F); + auto *SE = &AM.getResult(F); + auto *LI = &AM.getResult(F); + auto *TLI = &AM.getResult(F); + auto GetTTI = [&AM](Function &F) -> TargetTransformInfo & { + return AM.getResult(F); + }; + SeparateConstOffsetFromGEP Impl(DT, SE, LI, TLI, GetTTI, LowerGEP); + if (!Impl.run(F)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} diff --git a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp index 6c6d6ca9cf65..9d3c8d0f3739 100644 --- a/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp +++ b/llvm/lib/Transforms/Scalar/SimpleLoopUnswitch.cpp @@ -26,16 +26,18 @@ #include "llvm/Analysis/LoopPass.h" #include "llvm/Analysis/MemorySSA.h" #include "llvm/Analysis/MemorySSAUpdater.h" +#include "llvm/Analysis/MustExecute.h" +#include "llvm/Analysis/ScalarEvolution.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" -#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Use.h" #include "llvm/IR/Value.h" #include "llvm/InitializePasses.h" @@ -49,6 +51,7 @@ #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include @@ -93,6 +96,11 @@ static cl::opt UnswitchGuards( "simple-loop-unswitch-guards", cl::init(true), cl::Hidden, cl::desc("If enabled, simple loop unswitching will also consider " "llvm.experimental.guard intrinsics as unswitch candidates.")); +static cl::opt DropNonTrivialImplicitNullChecks( + "simple-loop-unswitch-drop-non-trivial-implicit-null-checks", + cl::init(false), cl::Hidden, + cl::desc("If enabled, drop make.implicit metadata in unswitched implicit " + "null checks to save time analyzing if we can keep it.")); /// Collect all of the loop invariant input values transitively used by the /// homogeneous instruction graph from a given root. @@ -684,11 +692,9 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT, // successor. BasicBlock *CommonSuccBB = nullptr; if (SI.getNumCases() > 0 && - std::all_of(std::next(SI.case_begin()), SI.case_end(), - [&SI](const SwitchInst::CaseHandle &Case) { - return Case.getCaseSuccessor() == - SI.case_begin()->getCaseSuccessor(); - })) + all_of(drop_begin(SI.cases()), [&SI](const SwitchInst::CaseHandle &Case) { + return Case.getCaseSuccessor() == SI.case_begin()->getCaseSuccessor(); + })) CommonSuccBB = SI.case_begin()->getCaseSuccessor(); if (!DefaultExitBB) { // If we're not unswitching the default, we need it to match any cases to @@ -847,12 +853,13 @@ static bool unswitchTrivialSwitch(Loop &L, SwitchInst &SI, DominatorTree &DT, DTUpdates.push_back({DT.Delete, ParentBB, SplitUnswitchedPair.first}); DTUpdates.push_back({DT.Insert, OldPH, SplitUnswitchedPair.second}); } - DT.applyUpdates(DTUpdates); if (MSSAU) { - MSSAU->applyUpdates(DTUpdates, DT); + MSSAU->applyUpdates(DTUpdates, DT, /*UpdateDT=*/true); if (VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); + } else { + DT.applyUpdates(DTUpdates); } assert(DT.verify(DominatorTree::VerificationLevel::Fast)); @@ -1133,9 +1140,22 @@ static BasicBlock *buildClonedLoopBlocks( // Replace the cloned branch with an unconditional branch to the cloned // unswitched successor. auto *ClonedSuccBB = cast(VMap.lookup(UnswitchedSuccBB)); - ClonedParentBB->getTerminator()->eraseFromParent(); + Instruction *ClonedTerminator = ClonedParentBB->getTerminator(); + // Trivial Simplification. If Terminator is a conditional branch and + // condition becomes dead - erase it. + Value *ClonedConditionToErase = nullptr; + if (auto *BI = dyn_cast(ClonedTerminator)) + ClonedConditionToErase = BI->getCondition(); + else if (auto *SI = dyn_cast(ClonedTerminator)) + ClonedConditionToErase = SI->getCondition(); + + ClonedTerminator->eraseFromParent(); BranchInst::Create(ClonedSuccBB, ClonedParentBB); + if (ClonedConditionToErase) + RecursivelyDeleteTriviallyDeadInstructions(ClonedConditionToErase, nullptr, + MSSAU); + // If there are duplicate entries in the PHI nodes because of multiple edges // to the unswitched successor, we need to nuke all but one as we replaced it // with a direct branch. @@ -1194,7 +1214,7 @@ static Loop *cloneLoopNest(Loop &OrigRootL, Loop *RootParentL, LI.addTopLevelLoop(ClonedRootL); AddClonedBlocksToLoop(OrigRootL, *ClonedRootL); - if (OrigRootL.empty()) + if (OrigRootL.isInnermost()) return ClonedRootL; // If we have a nest, we can quickly clone the entire loop nest using an @@ -2070,6 +2090,23 @@ static void unswitchNontrivialInvariants( DominatingSucc, *VMaps.back(), DTUpdates, AC, DT, LI, MSSAU); } + // Drop metadata if we may break its semantics by moving this instr into the + // split block. + if (TI.getMetadata(LLVMContext::MD_make_implicit)) { + if (DropNonTrivialImplicitNullChecks) + // Do not spend time trying to understand if we can keep it, just drop it + // to save compile time. + TI.setMetadata(LLVMContext::MD_make_implicit, nullptr); + else { + // It is only legal to preserve make.implicit metadata if we are + // guaranteed no reach implicit null check after following this branch. + ICFLoopSafetyInfo SafetyInfo; + SafetyInfo.computeLoopSafetyInfo(&L); + if (!SafetyInfo.isGuaranteedToExecute(TI, &DT, &L)) + TI.setMetadata(LLVMContext::MD_make_implicit, nullptr); + } + } + // The stitching of the branched code back together depends on whether we're // doing full unswitching or not with the exception that we always want to // nuke the initial terminator placed in the split block. @@ -2316,12 +2353,12 @@ static void unswitchNontrivialInvariants( for (Loop *UpdatedL : llvm::concat(NonChildClonedLoops, HoistedLoops)) { UpdateLoop(*UpdatedL); - if (!UpdatedL->getParentLoop()) + if (UpdatedL->isOutermost()) OuterExitL = nullptr; } if (IsStillLoop) { UpdateLoop(L); - if (!L.getParentLoop()) + if (L.isOutermost()) OuterExitL = nullptr; } @@ -2669,6 +2706,10 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI, // (convergent, noduplicate, or cross-basic-block tokens). // FIXME: We might be able to safely handle some of these in non-duplicated // regions. + TargetTransformInfo::TargetCostKind CostKind = + L.getHeader()->getParent()->hasMinSize() + ? TargetTransformInfo::TCK_CodeSize + : TargetTransformInfo::TCK_SizeAndLatency; int LoopCost = 0; for (auto *BB : L.blocks()) { int Cost = 0; @@ -2682,7 +2723,7 @@ unswitchBestCondition(Loop &L, DominatorTree &DT, LoopInfo &LI, if (CB->isConvergent() || CB->cannotDuplicate()) return false; - Cost += TTI.getUserCost(&I, TargetTransformInfo::TCK_CodeSize); + Cost += TTI.getUserCost(&I, CostKind); } assert(Cost >= 0 && "Must not have negative costs!"); LoopCost += Cost; @@ -2844,7 +2885,6 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI, ScalarEvolution *SE, MemorySSAUpdater *MSSAU) { assert(L.isRecursivelyLCSSAForm(DT, LI) && "Loops must be in LCSSA form before unswitching."); - bool Changed = false; // Must be in loop simplified form: we need a preheader and dedicated exits. if (!L.isLoopSimplifyForm()) @@ -2864,6 +2904,10 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI, if (!NonTrivial && !EnableNonTrivialUnswitch) return false; + // Skip non-trivial unswitching for optsize functions. + if (L.getHeader()->getParent()->hasOptSize()) + return false; + // For non-trivial unswitching, because it often creates new loops, we rely on // the pass manager to iterate on the loops rather than trying to immediately // reach a fixed point. There is no substantial advantage to iterating @@ -2876,7 +2920,7 @@ static bool unswitchLoop(Loop &L, DominatorTree &DT, LoopInfo &LI, return true; // No other opportunities to unswitch. - return Changed; + return false; } PreservedAnalyses SimpleLoopUnswitchPass::run(Loop &L, LoopAnalysisManager &AM, diff --git a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp index 2e459c9a64d4..38e7109ead57 100644 --- a/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp +++ b/llvm/lib/Transforms/Scalar/SimplifyCFGPass.cpp @@ -25,21 +25,25 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CFG.h" +#include "llvm/Analysis/DomTreeUpdater.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/CFG.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" +#include "llvm/IR/Dominators.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" +#include "llvm/IR/ValueHandle.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Scalar.h" #include "llvm/Transforms/Scalar/SimplifyCFG.h" #include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/SimplifyCFGOptions.h" #include using namespace llvm; @@ -61,6 +65,10 @@ static cl::opt UserForwardSwitchCond( "forward-switch-cond", cl::Hidden, cl::init(false), cl::desc("Forward switch condition to phi ops (default = false)")); +static cl::opt UserHoistCommonInsts( + "hoist-common-insts", cl::Hidden, cl::init(false), + cl::desc("hoist common instructions (default = false)")); + static cl::opt UserSinkCommonInsts( "sink-common-insts", cl::Hidden, cl::init(false), cl::desc("Sink common instructions (default = false)")); @@ -70,14 +78,18 @@ STATISTIC(NumSimpl, "Number of blocks simplified"); /// If we have more than one empty (other than phi node) return blocks, /// merge them together to promote recursive block merging. -static bool mergeEmptyReturnBlocks(Function &F) { +static bool mergeEmptyReturnBlocks(Function &F, DomTreeUpdater *DTU) { bool Changed = false; + std::vector Updates; + SmallVector DeadBlocks; + BasicBlock *RetBlock = nullptr; // Scan all the blocks in the function, looking for empty return blocks. - for (Function::iterator BBI = F.begin(), E = F.end(); BBI != E; ) { - BasicBlock &BB = *BBI++; + for (BasicBlock &BB : make_early_inc_range(F)) { + if (DTU && DTU->isBBPendingDeletion(&BB)) + continue; // Only look at return blocks. ReturnInst *Ret = dyn_cast(BB.getTerminator()); @@ -128,8 +140,18 @@ static bool mergeEmptyReturnBlocks(Function &F) { if (Ret->getNumOperands() == 0 || Ret->getOperand(0) == cast(RetBlock->getTerminator())->getOperand(0)) { + // All predecessors of BB should now branch to RetBlock instead. + if (DTU) { + for (auto *Predecessor : predecessors(&BB)) { + // But, iff Predecessor already branches to RetBlock, + // don't (re-)add DomTree edge, because it already exists. + if (!is_contained(successors(Predecessor), RetBlock)) + Updates.push_back({DominatorTree::Insert, Predecessor, RetBlock}); + Updates.push_back({DominatorTree::Delete, Predecessor, &BB}); + } + } BB.replaceAllUsesWith(RetBlock); - BB.eraseFromParent(); + DeadBlocks.emplace_back(&BB); continue; } @@ -153,6 +175,17 @@ static bool mergeEmptyReturnBlocks(Function &F) { RetBlockPHI->addIncoming(Ret->getOperand(0), &BB); BB.getTerminator()->eraseFromParent(); BranchInst::Create(RetBlock, &BB); + if (DTU) + Updates.push_back({DominatorTree::Insert, &BB, RetBlock}); + } + + if (DTU) { + DTU->applyUpdates(Updates); + for (auto *BB : DeadBlocks) + DTU->deleteBB(BB); + } else { + for (auto *BB : DeadBlocks) + BB->eraseFromParent(); } return Changed; @@ -161,22 +194,36 @@ static bool mergeEmptyReturnBlocks(Function &F) { /// Call SimplifyCFG on all the blocks in the function, /// iterating until no more changes are made. static bool iterativelySimplifyCFG(Function &F, const TargetTransformInfo &TTI, + DomTreeUpdater *DTU, const SimplifyCFGOptions &Options) { bool Changed = false; bool LocalChange = true; SmallVector, 32> Edges; FindFunctionBackedges(F, Edges); - SmallPtrSet LoopHeaders; + SmallPtrSet UniqueLoopHeaders; for (unsigned i = 0, e = Edges.size(); i != e; ++i) - LoopHeaders.insert(const_cast(Edges[i].second)); + UniqueLoopHeaders.insert(const_cast(Edges[i].second)); + + SmallVector LoopHeaders(UniqueLoopHeaders.begin(), + UniqueLoopHeaders.end()); while (LocalChange) { LocalChange = false; // Loop over all of the basic blocks and remove them if they are unneeded. for (Function::iterator BBIt = F.begin(); BBIt != F.end(); ) { - if (simplifyCFG(&*BBIt++, TTI, Options, &LoopHeaders)) { + BasicBlock &BB = *BBIt++; + if (DTU) { + assert( + !DTU->isBBPendingDeletion(&BB) && + "Should not end up trying to simplify blocks marked for removal."); + // Make sure that the advanced iterator does not point at the blocks + // that are marked for removal, skip over all such blocks. + while (BBIt != F.end() && DTU->isBBPendingDeletion(&*BBIt)) + ++BBIt; + } + if (simplifyCFG(&BB, TTI, DTU, Options, LoopHeaders)) { LocalChange = true; ++NumSimpl; } @@ -186,11 +233,14 @@ static bool iterativelySimplifyCFG(Function &F, const TargetTransformInfo &TTI, return Changed; } -static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI, - const SimplifyCFGOptions &Options) { - bool EverChanged = removeUnreachableBlocks(F); - EverChanged |= mergeEmptyReturnBlocks(F); - EverChanged |= iterativelySimplifyCFG(F, TTI, Options); +static bool simplifyFunctionCFGImpl(Function &F, const TargetTransformInfo &TTI, + DominatorTree *DT, + const SimplifyCFGOptions &Options) { + DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); + + bool EverChanged = removeUnreachableBlocks(F, DT ? &DTU : nullptr); + EverChanged |= mergeEmptyReturnBlocks(F, DT ? &DTU : nullptr); + EverChanged |= iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options); // If neither pass changed anything, we're done. if (!EverChanged) return false; @@ -200,43 +250,75 @@ static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI, // iterate between the two optimizations. We structure the code like this to // avoid rerunning iterativelySimplifyCFG if the second pass of // removeUnreachableBlocks doesn't do anything. - if (!removeUnreachableBlocks(F)) + if (!removeUnreachableBlocks(F, DT ? &DTU : nullptr)) return true; do { - EverChanged = iterativelySimplifyCFG(F, TTI, Options); - EverChanged |= removeUnreachableBlocks(F); + EverChanged = iterativelySimplifyCFG(F, TTI, DT ? &DTU : nullptr, Options); + EverChanged |= removeUnreachableBlocks(F, DT ? &DTU : nullptr); } while (EverChanged); return true; } +static bool simplifyFunctionCFG(Function &F, const TargetTransformInfo &TTI, + DominatorTree *DT, + const SimplifyCFGOptions &Options) { + assert((!RequireAndPreserveDomTree || + (DT && DT->verify(DominatorTree::VerificationLevel::Full))) && + "Original domtree is invalid?"); + + bool Changed = simplifyFunctionCFGImpl(F, TTI, DT, Options); + + assert((!RequireAndPreserveDomTree || + (DT && DT->verify(DominatorTree::VerificationLevel::Full))) && + "Failed to maintain validity of domtree!"); + + return Changed; +} + // Command-line settings override compile-time settings. -SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts) { - Options.BonusInstThreshold = UserBonusInstThreshold.getNumOccurrences() - ? UserBonusInstThreshold - : Opts.BonusInstThreshold; - Options.ForwardSwitchCondToPhi = UserForwardSwitchCond.getNumOccurrences() - ? UserForwardSwitchCond - : Opts.ForwardSwitchCondToPhi; - Options.ConvertSwitchToLookupTable = UserSwitchToLookup.getNumOccurrences() - ? UserSwitchToLookup - : Opts.ConvertSwitchToLookupTable; - Options.NeedCanonicalLoop = UserKeepLoops.getNumOccurrences() - ? UserKeepLoops - : Opts.NeedCanonicalLoop; - Options.SinkCommonInsts = UserSinkCommonInsts.getNumOccurrences() - ? UserSinkCommonInsts - : Opts.SinkCommonInsts; +static void applyCommandLineOverridesToOptions(SimplifyCFGOptions &Options) { + if (UserBonusInstThreshold.getNumOccurrences()) + Options.BonusInstThreshold = UserBonusInstThreshold; + if (UserForwardSwitchCond.getNumOccurrences()) + Options.ForwardSwitchCondToPhi = UserForwardSwitchCond; + if (UserSwitchToLookup.getNumOccurrences()) + Options.ConvertSwitchToLookupTable = UserSwitchToLookup; + if (UserKeepLoops.getNumOccurrences()) + Options.NeedCanonicalLoop = UserKeepLoops; + if (UserHoistCommonInsts.getNumOccurrences()) + Options.HoistCommonInsts = UserHoistCommonInsts; + if (UserSinkCommonInsts.getNumOccurrences()) + Options.SinkCommonInsts = UserSinkCommonInsts; +} + +SimplifyCFGPass::SimplifyCFGPass() : Options() { + applyCommandLineOverridesToOptions(Options); +} + +SimplifyCFGPass::SimplifyCFGPass(const SimplifyCFGOptions &Opts) + : Options(Opts) { + applyCommandLineOverridesToOptions(Options); } PreservedAnalyses SimplifyCFGPass::run(Function &F, FunctionAnalysisManager &AM) { auto &TTI = AM.getResult(F); Options.AC = &AM.getResult(F); - if (!simplifyFunctionCFG(F, TTI, Options)) + DominatorTree *DT = nullptr; + if (RequireAndPreserveDomTree) + DT = &AM.getResult(F); + if (F.hasFnAttribute(Attribute::OptForFuzzing)) { + Options.setSimplifyCondBranch(false).setFoldTwoEntryPHINode(false); + } else { + Options.setSimplifyCondBranch(true).setFoldTwoEntryPHINode(true); + } + if (!simplifyFunctionCFG(F, TTI, DT, Options)) return PreservedAnalyses::all(); PreservedAnalyses PA; + if (RequireAndPreserveDomTree) + PA.preserve(); PA.preserve(); return PA; } @@ -247,33 +329,14 @@ struct CFGSimplifyPass : public FunctionPass { SimplifyCFGOptions Options; std::function PredicateFtor; - CFGSimplifyPass(unsigned Threshold = 1, bool ForwardSwitchCond = false, - bool ConvertSwitch = false, bool KeepLoops = true, - bool SinkCommon = false, + CFGSimplifyPass(SimplifyCFGOptions Options_ = SimplifyCFGOptions(), std::function Ftor = nullptr) - : FunctionPass(ID), PredicateFtor(std::move(Ftor)) { + : FunctionPass(ID), Options(Options_), PredicateFtor(std::move(Ftor)) { initializeCFGSimplifyPassPass(*PassRegistry::getPassRegistry()); // Check for command-line overrides of options for debug/customization. - Options.BonusInstThreshold = UserBonusInstThreshold.getNumOccurrences() - ? UserBonusInstThreshold - : Threshold; - - Options.ForwardSwitchCondToPhi = UserForwardSwitchCond.getNumOccurrences() - ? UserForwardSwitchCond - : ForwardSwitchCond; - - Options.ConvertSwitchToLookupTable = UserSwitchToLookup.getNumOccurrences() - ? UserSwitchToLookup - : ConvertSwitch; - - Options.NeedCanonicalLoop = - UserKeepLoops.getNumOccurrences() ? UserKeepLoops : KeepLoops; - - Options.SinkCommonInsts = UserSinkCommonInsts.getNumOccurrences() - ? UserSinkCommonInsts - : SinkCommon; + applyCommandLineOverridesToOptions(Options); } bool runOnFunction(Function &F) override { @@ -281,6 +344,9 @@ struct CFGSimplifyPass : public FunctionPass { return false; Options.AC = &getAnalysis().getAssumptionCache(F); + DominatorTree *DT = nullptr; + if (RequireAndPreserveDomTree) + DT = &getAnalysis().getDomTree(); if (F.hasFnAttribute(Attribute::OptForFuzzing)) { Options.setSimplifyCondBranch(false) .setFoldTwoEntryPHINode(false); @@ -290,11 +356,15 @@ struct CFGSimplifyPass : public FunctionPass { } auto &TTI = getAnalysis().getTTI(F); - return simplifyFunctionCFG(F, TTI, Options); + return simplifyFunctionCFG(F, TTI, DT, Options); } void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired(); + if (RequireAndPreserveDomTree) + AU.addRequired(); AU.addRequired(); + if (RequireAndPreserveDomTree) + AU.addPreserved(); AU.addPreserved(); } }; @@ -305,15 +375,13 @@ INITIALIZE_PASS_BEGIN(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false, false) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_END(CFGSimplifyPass, "simplifycfg", "Simplify the CFG", false, false) // Public interface to the CFGSimplification pass FunctionPass * -llvm::createCFGSimplificationPass(unsigned Threshold, bool ForwardSwitchCond, - bool ConvertSwitch, bool KeepLoops, - bool SinkCommon, +llvm::createCFGSimplificationPass(SimplifyCFGOptions Options, std::function Ftor) { - return new CFGSimplifyPass(Threshold, ForwardSwitchCond, ConvertSwitch, - KeepLoops, SinkCommon, std::move(Ftor)); + return new CFGSimplifyPass(Options, std::move(Ftor)); } diff --git a/llvm/lib/Transforms/Scalar/Sink.cpp b/llvm/lib/Transforms/Scalar/Sink.cpp index 48f289c8f17d..89cfbe384be4 100644 --- a/llvm/lib/Transforms/Scalar/Sink.cpp +++ b/llvm/lib/Transforms/Scalar/Sink.cpp @@ -32,31 +32,6 @@ using namespace llvm; STATISTIC(NumSunk, "Number of instructions sunk"); STATISTIC(NumSinkIter, "Number of sinking iterations"); -/// AllUsesDominatedByBlock - Return true if all uses of the specified value -/// occur in blocks dominated by the specified block. -static bool AllUsesDominatedByBlock(Instruction *Inst, BasicBlock *BB, - DominatorTree &DT) { - // Ignoring debug uses is necessary so debug info doesn't affect the code. - // This may leave a referencing dbg_value in the original block, before - // the definition of the vreg. Dwarf generator handles this although the - // user might not get the right info at runtime. - for (Use &U : Inst->uses()) { - // Determine the block of the use. - Instruction *UseInst = cast(U.getUser()); - BasicBlock *UseBlock = UseInst->getParent(); - if (PHINode *PN = dyn_cast(UseInst)) { - // PHI nodes use the operand in the predecessor block, not the block with - // the PHI. - unsigned Num = PHINode::getIncomingValueNumForOperand(U.getOperandNo()); - UseBlock = PN->getIncomingBlock(Num); - } - // Check that it dominates. - if (!DT.dominates(BB, UseBlock)) - return false; - } - return true; -} - static bool isSafeToMove(Instruction *Inst, AliasAnalysis &AA, SmallPtrSetImpl &Stores) { @@ -97,11 +72,6 @@ static bool IsAcceptableTarget(Instruction *Inst, BasicBlock *SuccToSinkTo, assert(Inst && "Instruction to be sunk is null"); assert(SuccToSinkTo && "Candidate sink target is null"); - // It is not possible to sink an instruction into its own block. This can - // happen with loops. - if (Inst->getParent() == SuccToSinkTo) - return false; - // It's never legal to sink an instruction into a block which terminates in an // EH-pad. if (SuccToSinkTo->getTerminator()->isExceptionalTerminator()) @@ -129,9 +99,7 @@ static bool IsAcceptableTarget(Instruction *Inst, BasicBlock *SuccToSinkTo, return false; } - // Finally, check that all the uses of the instruction are actually - // dominated by the candidate - return AllUsesDominatedByBlock(Inst, SuccToSinkTo, DT); + return true; } /// SinkInstruction - Determine whether it is safe to sink the specified machine @@ -162,25 +130,37 @@ static bool SinkInstruction(Instruction *Inst, // decide. BasicBlock *SuccToSinkTo = nullptr; - // Instructions can only be sunk if all their uses are in blocks - // dominated by one of the successors. - // Look at all the dominated blocks and see if we can sink it in one. - DomTreeNode *DTN = DT.getNode(Inst->getParent()); - for (auto I = DTN->begin(), E = DTN->end(); I != E && SuccToSinkTo == nullptr; - ++I) { - BasicBlock *Candidate = (*I)->getBlock(); - // A node always immediate-dominates its children on the dominator - // tree. - if (IsAcceptableTarget(Inst, Candidate, DT, LI)) - SuccToSinkTo = Candidate; + // Find the nearest common dominator of all users as the candidate. + BasicBlock *BB = Inst->getParent(); + for (Use &U : Inst->uses()) { + Instruction *UseInst = cast(U.getUser()); + BasicBlock *UseBlock = UseInst->getParent(); + // Don't worry about dead users. + if (!DT.isReachableFromEntry(UseBlock)) + continue; + if (PHINode *PN = dyn_cast(UseInst)) { + // PHI nodes use the operand in the predecessor block, not the block with + // the PHI. + unsigned Num = PHINode::getIncomingValueNumForOperand(U.getOperandNo()); + UseBlock = PN->getIncomingBlock(Num); + } + if (SuccToSinkTo) + SuccToSinkTo = DT.findNearestCommonDominator(SuccToSinkTo, UseBlock); + else + SuccToSinkTo = UseBlock; + // The current basic block needs to dominate the candidate. + if (!DT.dominates(BB, SuccToSinkTo)) + return false; } - // If no suitable postdominator was found, look at all the successors and - // decide which one we should sink to, if any. - for (succ_iterator I = succ_begin(Inst->getParent()), - E = succ_end(Inst->getParent()); I != E && !SuccToSinkTo; ++I) { - if (IsAcceptableTarget(Inst, *I, DT, LI)) - SuccToSinkTo = *I; + if (SuccToSinkTo) { + // The nearest common dominator may be in a parent loop of BB, which may not + // be beneficial. Find an ancestor. + while (SuccToSinkTo != BB && + !IsAcceptableTarget(Inst, SuccToSinkTo, DT, LI)) + SuccToSinkTo = DT.getNode(SuccToSinkTo)->getIDom()->getBlock(); + if (SuccToSinkTo == BB) + SuccToSinkTo = nullptr; } // If we couldn't find a block to sink to, ignore this instruction. diff --git a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp b/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp index 8258b92a716d..9b18c945d950 100644 --- a/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp +++ b/llvm/lib/Transforms/Scalar/SpeculateAroundPHIs.cpp @@ -756,13 +756,10 @@ static bool tryToSpeculatePHIs(SmallVectorImpl &PNs, // For each PHI node in this block, check whether there are immediate folding // opportunities from speculation, and whether that speculation will be // valid. This determise the set of safe PHIs to speculate. - PNs.erase(llvm::remove_if(PNs, - [&](PHINode *PN) { - return !isSafeAndProfitableToSpeculateAroundPHI( - *PN, CostSavingsMap, PotentialSpecSet, - UnsafeSet, DT, TTI); - }), - PNs.end()); + llvm::erase_if(PNs, [&](PHINode *PN) { + return !isSafeAndProfitableToSpeculateAroundPHI( + *PN, CostSavingsMap, PotentialSpecSet, UnsafeSet, DT, TTI); + }); // If no PHIs were profitable, skip. if (PNs.empty()) { LLVM_DEBUG(dbgs() << " No safe and profitable PHIs found!\n"); diff --git a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp index f82a2936c762..c78185f2a6ad 100644 --- a/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp +++ b/llvm/lib/Transforms/Scalar/SpeculativeExecution.cpp @@ -245,6 +245,13 @@ static unsigned ComputeSpeculationCost(const Instruction *I, case Instruction::FNeg: case Instruction::ICmp: case Instruction::FCmp: + case Instruction::Trunc: + case Instruction::Freeze: + case Instruction::ExtractElement: + case Instruction::InsertElement: + case Instruction::ShuffleVector: + case Instruction::ExtractValue: + case Instruction::InsertValue: return TTI.getUserCost(I, TargetTransformInfo::TCK_SizeAndLatency); default: @@ -274,7 +281,7 @@ bool SpeculativeExecutionPass::considerHoistingFromTo( for (const Value *V : U->operand_values()) { if (const Instruction *I = dyn_cast(V)) { - if (NotHoisted.count(I) > 0) + if (NotHoisted.contains(I)) return false; } } diff --git a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp index 9f82b1263ebd..577992ccb5f4 100644 --- a/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp +++ b/llvm/lib/Transforms/Scalar/StraightLineStrengthReduce.cpp @@ -55,6 +55,7 @@ // - When (i' - i) is constant but i and i' are not, we could still perform // SLSR. +#include "llvm/Transforms/Scalar/StraightLineStrengthReduce.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallVector.h" @@ -95,8 +96,39 @@ static const unsigned UnknownAddressSpace = namespace { -class StraightLineStrengthReduce : public FunctionPass { +class StraightLineStrengthReduceLegacyPass : public FunctionPass { + const DataLayout *DL = nullptr; + public: + static char ID; + + StraightLineStrengthReduceLegacyPass() : FunctionPass(ID) { + initializeStraightLineStrengthReduceLegacyPassPass( + *PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.addRequired(); + AU.addRequired(); + // We do not modify the shape of the CFG. + AU.setPreservesCFG(); + } + + bool doInitialization(Module &M) override { + DL = &M.getDataLayout(); + return false; + } + + bool runOnFunction(Function &F) override; +}; + +class StraightLineStrengthReduce { +public: + StraightLineStrengthReduce(const DataLayout *DL, DominatorTree *DT, + ScalarEvolution *SE, TargetTransformInfo *TTI) + : DL(DL), DT(DT), SE(SE), TTI(TTI) {} + // SLSR candidate. Such a candidate must be in one of the forms described in // the header comments. struct Candidate { @@ -144,26 +176,7 @@ public: Candidate *Basis = nullptr; }; - static char ID; - - StraightLineStrengthReduce() : FunctionPass(ID) { - initializeStraightLineStrengthReducePass(*PassRegistry::getPassRegistry()); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.addRequired(); - AU.addRequired(); - // We do not modify the shape of the CFG. - AU.setPreservesCFG(); - } - - bool doInitialization(Module &M) override { - DL = &M.getDataLayout(); - return false; - } - - bool runOnFunction(Function &F) override; + bool runOnFunction(Function &F); private: // Returns true if Basis is a basis for C, i.e., Basis dominates C and they @@ -243,18 +256,18 @@ private: } // end anonymous namespace -char StraightLineStrengthReduce::ID = 0; +char StraightLineStrengthReduceLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(StraightLineStrengthReduce, "slsr", +INITIALIZE_PASS_BEGIN(StraightLineStrengthReduceLegacyPass, "slsr", "Straight line strength reduction", false, false) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) -INITIALIZE_PASS_END(StraightLineStrengthReduce, "slsr", +INITIALIZE_PASS_END(StraightLineStrengthReduceLegacyPass, "slsr", "Straight line strength reduction", false, false) FunctionPass *llvm::createStraightLineStrengthReducePass() { - return new StraightLineStrengthReduce(); + return new StraightLineStrengthReduceLegacyPass(); } bool StraightLineStrengthReduce::isBasisFor(const Candidate &Basis, @@ -272,9 +285,7 @@ bool StraightLineStrengthReduce::isBasisFor(const Candidate &Basis, static bool isGEPFoldable(GetElementPtrInst *GEP, const TargetTransformInfo *TTI) { - SmallVector Indices; - for (auto I = GEP->idx_begin(); I != GEP->idx_end(); ++I) - Indices.push_back(*I); + SmallVector Indices(GEP->indices()); return TTI->getGEPCost(GEP->getSourceElementType(), GEP->getPointerOperand(), Indices) == TargetTransformInfo::TCC_Free; } @@ -704,13 +715,17 @@ void StraightLineStrengthReduce::rewriteCandidateWithBasis( UnlinkedInstructions.push_back(C.Ins); } -bool StraightLineStrengthReduce::runOnFunction(Function &F) { +bool StraightLineStrengthReduceLegacyPass::runOnFunction(Function &F) { if (skipFunction(F)) return false; - TTI = &getAnalysis().getTTI(F); - DT = &getAnalysis().getDomTree(); - SE = &getAnalysis().getSE(); + auto *TTI = &getAnalysis().getTTI(F); + auto *DT = &getAnalysis().getDomTree(); + auto *SE = &getAnalysis().getSE(); + return StraightLineStrengthReduce(DL, DT, SE, TTI).runOnFunction(F); +} + +bool StraightLineStrengthReduce::runOnFunction(Function &F) { // Traverse the dominator tree in the depth-first order. This order makes sure // all bases of a candidate are in Candidates when we process it. for (const auto Node : depth_first(DT)) @@ -740,3 +755,25 @@ bool StraightLineStrengthReduce::runOnFunction(Function &F) { UnlinkedInstructions.clear(); return Ret; } + +namespace llvm { + +PreservedAnalyses +StraightLineStrengthReducePass::run(Function &F, FunctionAnalysisManager &AM) { + const DataLayout *DL = &F.getParent()->getDataLayout(); + auto *DT = &AM.getResult(F); + auto *SE = &AM.getResult(F); + auto *TTI = &AM.getResult(F); + + if (!StraightLineStrengthReduce(DL, DT, SE, TTI).runOnFunction(F)) + return PreservedAnalyses::all(); + + PreservedAnalyses PA; + PA.preserveSet(); + PA.preserve(); + PA.preserve(); + PA.preserve(); + return PA; +} + +} // namespace llvm diff --git a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp index c20e57b02c1a..3e15cad5f3f3 100644 --- a/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp +++ b/llvm/lib/Transforms/Scalar/StructurizeCFG.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Scalar/StructurizeCFG.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SCCIterator.h" @@ -28,6 +29,7 @@ #include "llvm/IR/Instruction.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" @@ -55,7 +57,7 @@ using namespace llvm::PatternMatch; #define DEBUG_TYPE "structurizecfg" // The name for newly created blocks. -static const char *const FlowBlockName = "Flow"; +const char FlowBlockName[] = "Flow"; namespace { @@ -233,9 +235,8 @@ public: /// while the true side continues the general flow. So the loop condition /// consist of a network of PHI nodes where the true incoming values expresses /// breaks and the false values expresses continue states. -class StructurizeCFG : public RegionPass { - bool SkipUniformRegions; +class StructurizeCFG { Type *Boolean; ConstantInt *BoolTrue; ConstantInt *BoolFalse; @@ -244,7 +245,7 @@ class StructurizeCFG : public RegionPass { Function *Func; Region *ParentRegion; - LegacyDivergenceAnalysis *DA; + LegacyDivergenceAnalysis *DA = nullptr; DominatorTree *DT; SmallVector Order; @@ -308,20 +309,36 @@ class StructurizeCFG : public RegionPass { void rebuildSSA(); +public: + void init(Region *R); + bool run(Region *R, DominatorTree *DT); + bool makeUniformRegion(Region *R, LegacyDivergenceAnalysis *DA); +}; + +class StructurizeCFGLegacyPass : public RegionPass { + bool SkipUniformRegions; + public: static char ID; - explicit StructurizeCFG(bool SkipUniformRegions_ = false) - : RegionPass(ID), - SkipUniformRegions(SkipUniformRegions_) { + explicit StructurizeCFGLegacyPass(bool SkipUniformRegions_ = false) + : RegionPass(ID), SkipUniformRegions(SkipUniformRegions_) { if (ForceSkipUniformRegions.getNumOccurrences()) SkipUniformRegions = ForceSkipUniformRegions.getValue(); - initializeStructurizeCFGPass(*PassRegistry::getPassRegistry()); + initializeStructurizeCFGLegacyPassPass(*PassRegistry::getPassRegistry()); } - bool doInitialization(Region *R, RGPassManager &RGM) override; - - bool runOnRegion(Region *R, RGPassManager &RGM) override; + bool runOnRegion(Region *R, RGPassManager &RGM) override { + StructurizeCFG SCFG; + SCFG.init(R); + if (SkipUniformRegions) { + LegacyDivergenceAnalysis *DA = &getAnalysis(); + if (SCFG.makeUniformRegion(R, DA)) + return false; + } + DominatorTree *DT = &getAnalysis().getDomTree(); + return SCFG.run(R, DT); + } StringRef getPassName() const override { return "Structurize control flow"; } @@ -338,28 +355,16 @@ public: } // end anonymous namespace -char StructurizeCFG::ID = 0; +char StructurizeCFGLegacyPass::ID = 0; -INITIALIZE_PASS_BEGIN(StructurizeCFG, "structurizecfg", "Structurize the CFG", - false, false) +INITIALIZE_PASS_BEGIN(StructurizeCFGLegacyPass, "structurizecfg", + "Structurize the CFG", false, false) INITIALIZE_PASS_DEPENDENCY(LegacyDivergenceAnalysis) -INITIALIZE_PASS_DEPENDENCY(LowerSwitch) +INITIALIZE_PASS_DEPENDENCY(LowerSwitchLegacyPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(RegionInfoPass) -INITIALIZE_PASS_END(StructurizeCFG, "structurizecfg", "Structurize the CFG", - false, false) - -/// Initialize the types and constants used in the pass -bool StructurizeCFG::doInitialization(Region *R, RGPassManager &RGM) { - LLVMContext &Context = R->getEntry()->getContext(); - - Boolean = Type::getInt1Ty(Context); - BoolTrue = ConstantInt::getTrue(Context); - BoolFalse = ConstantInt::getFalse(Context); - BoolUndef = UndefValue::get(Boolean); - - return false; -} +INITIALIZE_PASS_END(StructurizeCFGLegacyPass, "structurizecfg", + "Structurize the CFG", false, false) /// Build up the general order of nodes, by performing a topological sort of the /// parent region's nodes, while ensuring that there is no outer cycle node @@ -1003,48 +1008,62 @@ static bool hasOnlyUniformBranches(Region *R, unsigned UniformMDKindID, return SubRegionsAreUniform || (ConditionalDirectChildren <= 1); } -/// Run the transformation for each region found -bool StructurizeCFG::runOnRegion(Region *R, RGPassManager &RGM) { +void StructurizeCFG::init(Region *R) { + LLVMContext &Context = R->getEntry()->getContext(); + + Boolean = Type::getInt1Ty(Context); + BoolTrue = ConstantInt::getTrue(Context); + BoolFalse = ConstantInt::getFalse(Context); + BoolUndef = UndefValue::get(Boolean); + + this->DA = nullptr; +} + +bool StructurizeCFG::makeUniformRegion(Region *R, + LegacyDivergenceAnalysis *DA) { if (R->isTopLevelRegion()) return false; - DA = nullptr; - - if (SkipUniformRegions) { - // TODO: We could probably be smarter here with how we handle sub-regions. - // We currently rely on the fact that metadata is set by earlier invocations - // of the pass on sub-regions, and that this metadata doesn't get lost -- - // but we shouldn't rely on metadata for correctness! - unsigned UniformMDKindID = - R->getEntry()->getContext().getMDKindID("structurizecfg.uniform"); - DA = &getAnalysis(); - - if (hasOnlyUniformBranches(R, UniformMDKindID, *DA)) { - LLVM_DEBUG(dbgs() << "Skipping region with uniform control flow: " << *R - << '\n'); - - // Mark all direct child block terminators as having been treated as - // uniform. To account for a possible future in which non-uniform - // sub-regions are treated more cleverly, indirect children are not - // marked as uniform. - MDNode *MD = MDNode::get(R->getEntry()->getParent()->getContext(), {}); - for (RegionNode *E : R->elements()) { - if (E->isSubRegion()) - continue; - - if (Instruction *Term = E->getEntry()->getTerminator()) - Term->setMetadata(UniformMDKindID, MD); - } + this->DA = DA; + // TODO: We could probably be smarter here with how we handle sub-regions. + // We currently rely on the fact that metadata is set by earlier invocations + // of the pass on sub-regions, and that this metadata doesn't get lost -- + // but we shouldn't rely on metadata for correctness! + unsigned UniformMDKindID = + R->getEntry()->getContext().getMDKindID("structurizecfg.uniform"); + + if (hasOnlyUniformBranches(R, UniformMDKindID, *DA)) { + LLVM_DEBUG(dbgs() << "Skipping region with uniform control flow: " << *R + << '\n'); + + // Mark all direct child block terminators as having been treated as + // uniform. To account for a possible future in which non-uniform + // sub-regions are treated more cleverly, indirect children are not + // marked as uniform. + MDNode *MD = MDNode::get(R->getEntry()->getParent()->getContext(), {}); + for (RegionNode *E : R->elements()) { + if (E->isSubRegion()) + continue; - return false; + if (Instruction *Term = E->getEntry()->getTerminator()) + Term->setMetadata(UniformMDKindID, MD); } + + return true; } + return false; +} + +/// Run the transformation for each region found +bool StructurizeCFG::run(Region *R, DominatorTree *DT) { + if (R->isTopLevelRegion()) + return false; + + this->DT = DT; Func = R->getEntry()->getParent(); ParentRegion = R; - DT = &getAnalysis().getDomTree(); - orderNodes(); collectInfos(); createFlow(); @@ -1069,5 +1088,33 @@ bool StructurizeCFG::runOnRegion(Region *R, RGPassManager &RGM) { } Pass *llvm::createStructurizeCFGPass(bool SkipUniformRegions) { - return new StructurizeCFG(SkipUniformRegions); + return new StructurizeCFGLegacyPass(SkipUniformRegions); +} + +static void addRegionIntoQueue(Region &R, std::vector &Regions) { + Regions.push_back(&R); + for (const auto &E : R) + addRegionIntoQueue(*E, Regions); +} + +PreservedAnalyses StructurizeCFGPass::run(Function &F, + FunctionAnalysisManager &AM) { + + bool Changed = false; + DominatorTree *DT = &AM.getResult(F); + auto &RI = AM.getResult(F); + std::vector Regions; + addRegionIntoQueue(*RI.getTopLevelRegion(), Regions); + while (!Regions.empty()) { + Region *R = Regions.back(); + StructurizeCFG SCFG; + SCFG.init(R); + Changed |= SCFG.run(R, DT); + Regions.pop_back(); + } + if (!Changed) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + return PA; } diff --git a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp index 5bb1d54d7d12..9e7cccc88412 100644 --- a/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp +++ b/llvm/lib/Transforms/Scalar/TailRecursionElimination.cpp @@ -92,7 +92,10 @@ STATISTIC(NumAccumAdded, "Number of accumulators introduced"); /// Scan the specified function for alloca instructions. /// If it contains any dynamic allocas, returns false. static bool canTRE(Function &F) { - // Because of PR962, we don't TRE dynamic allocas. + // FIXME: The code generator produces really bad code when an 'escaping + // alloca' is changed from being a static alloca to being a dynamic alloca. + // Until this is resolved, disable this transformation if that would ever + // happen. This bug is PR962. return llvm::all_of(instructions(F), [](Instruction &I) { auto *AI = dyn_cast(&I); return !AI || AI->isStaticAlloca(); @@ -237,7 +240,11 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls, Escaped = ESCAPED; CallInst *CI = dyn_cast(&I); - if (!CI || CI->isTailCall() || isa(&I)) + // A PseudoProbeInst has the IntrInaccessibleMemOnly tag hence it is + // considered accessing memory and will be marked as a tail call if we + // don't bail out here. + if (!CI || CI->isTailCall() || isa(&I) || + isa(&I)) continue; bool IsNoTail = CI->isNoTailCall() || CI->hasOperandBundles(); @@ -279,7 +286,7 @@ static bool markTails(Function &F, bool &AllCallsAreTailCalls, } } - for (auto *SuccBB : make_range(succ_begin(BB), succ_end(BB))) { + for (auto *SuccBB : successors(BB)) { auto &State = Visited[SuccBB]; if (State < Escaped) { State = Escaped; @@ -419,7 +426,7 @@ class TailRecursionEliminator { DomTreeUpdater &DTU) : F(F), TTI(TTI), AA(AA), ORE(ORE), DTU(DTU) {} - CallInst *findTRECandidate(Instruction *TI, + CallInst *findTRECandidate(BasicBlock *BB, bool CannotTailCallElimCallsMarkedTail); void createTailRecurseLoopHeader(CallInst *CI); @@ -428,14 +435,10 @@ class TailRecursionEliminator { bool eliminateCall(CallInst *CI); - bool foldReturnAndProcessPred(ReturnInst *Ret, - bool CannotTailCallElimCallsMarkedTail); - - bool processReturningBlock(ReturnInst *Ret, - bool CannotTailCallElimCallsMarkedTail); - void cleanupAndFinalize(); + bool processBlock(BasicBlock &BB, bool CannotTailCallElimCallsMarkedTail); + public: static bool eliminate(Function &F, const TargetTransformInfo *TTI, AliasAnalysis *AA, OptimizationRemarkEmitter *ORE, @@ -444,8 +447,8 @@ public: } // namespace CallInst *TailRecursionEliminator::findTRECandidate( - Instruction *TI, bool CannotTailCallElimCallsMarkedTail) { - BasicBlock *BB = TI->getParent(); + BasicBlock *BB, bool CannotTailCallElimCallsMarkedTail) { + Instruction *TI = BB->getTerminator(); if (&BB->front() == TI) // Make sure there is something before the terminator. return nullptr; @@ -672,63 +675,6 @@ bool TailRecursionEliminator::eliminateCall(CallInst *CI) { return true; } -bool TailRecursionEliminator::foldReturnAndProcessPred( - ReturnInst *Ret, bool CannotTailCallElimCallsMarkedTail) { - BasicBlock *BB = Ret->getParent(); - - bool Change = false; - - // Make sure this block is a trivial return block. - assert(BB->getFirstNonPHIOrDbg() == Ret && - "Trying to fold non-trivial return block"); - - // If the return block contains nothing but the return and PHI's, - // there might be an opportunity to duplicate the return in its - // predecessors and perform TRE there. Look for predecessors that end - // in unconditional branch and recursive call(s). - SmallVector UncondBranchPreds; - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { - BasicBlock *Pred = *PI; - Instruction *PTI = Pred->getTerminator(); - if (BranchInst *BI = dyn_cast(PTI)) - if (BI->isUnconditional()) - UncondBranchPreds.push_back(BI); - } - - while (!UncondBranchPreds.empty()) { - BranchInst *BI = UncondBranchPreds.pop_back_val(); - BasicBlock *Pred = BI->getParent(); - if (CallInst *CI = - findTRECandidate(BI, CannotTailCallElimCallsMarkedTail)) { - LLVM_DEBUG(dbgs() << "FOLDING: " << *BB - << "INTO UNCOND BRANCH PRED: " << *Pred); - FoldReturnIntoUncondBranch(Ret, BB, Pred, &DTU); - - // Cleanup: if all predecessors of BB have been eliminated by - // FoldReturnIntoUncondBranch, delete it. It is important to empty it, - // because the ret instruction in there is still using a value which - // eliminateRecursiveTailCall will attempt to remove. - if (!BB->hasAddressTaken() && pred_begin(BB) == pred_end(BB)) - DTU.deleteBB(BB); - - eliminateCall(CI); - ++NumRetDuped; - Change = true; - } - } - - return Change; -} - -bool TailRecursionEliminator::processReturningBlock( - ReturnInst *Ret, bool CannotTailCallElimCallsMarkedTail) { - CallInst *CI = findTRECandidate(Ret, CannotTailCallElimCallsMarkedTail); - if (!CI) - return false; - - return eliminateCall(CI); -} - void TailRecursionEliminator::cleanupAndFinalize() { // If we eliminated any tail recursions, it's possible that we inserted some // silly PHI nodes which just merge an initial value (the incoming operand) @@ -801,6 +747,50 @@ void TailRecursionEliminator::cleanupAndFinalize() { } } +bool TailRecursionEliminator::processBlock( + BasicBlock &BB, bool CannotTailCallElimCallsMarkedTail) { + Instruction *TI = BB.getTerminator(); + + if (BranchInst *BI = dyn_cast(TI)) { + if (BI->isConditional()) + return false; + + BasicBlock *Succ = BI->getSuccessor(0); + ReturnInst *Ret = dyn_cast(Succ->getFirstNonPHIOrDbg(true)); + + if (!Ret) + return false; + + CallInst *CI = findTRECandidate(&BB, CannotTailCallElimCallsMarkedTail); + + if (!CI) + return false; + + LLVM_DEBUG(dbgs() << "FOLDING: " << *Succ + << "INTO UNCOND BRANCH PRED: " << BB); + FoldReturnIntoUncondBranch(Ret, Succ, &BB, &DTU); + ++NumRetDuped; + + // If all predecessors of Succ have been eliminated by + // FoldReturnIntoUncondBranch, delete it. It is important to empty it, + // because the ret instruction in there is still using a value which + // eliminateCall will attempt to remove. This block can only contain + // instructions that can't have uses, therefore it is safe to remove. + if (pred_empty(Succ)) + DTU.deleteBB(Succ); + + eliminateCall(CI); + return true; + } else if (isa(TI)) { + CallInst *CI = findTRECandidate(&BB, CannotTailCallElimCallsMarkedTail); + + if (CI) + return eliminateCall(CI); + } + + return false; +} + bool TailRecursionEliminator::eliminate(Function &F, const TargetTransformInfo *TTI, AliasAnalysis *AA, @@ -825,23 +815,11 @@ bool TailRecursionEliminator::eliminate(Function &F, // TRE would deallocate variable sized allocas, TRE doesn't). bool CanTRETailMarkedCall = canTRE(F); + // Change any tail recursive calls to loops. TailRecursionEliminator TRE(F, TTI, AA, ORE, DTU); - // Change any tail recursive calls to loops. - // - // FIXME: The code generator produces really bad code when an 'escaping - // alloca' is changed from being a static alloca to being a dynamic alloca. - // Until this is resolved, disable this transformation if that would ever - // happen. This bug is PR962. - for (Function::iterator BBI = F.begin(), E = F.end(); BBI != E; /*in loop*/) { - BasicBlock *BB = &*BBI++; // foldReturnAndProcessPred may delete BB. - if (ReturnInst *Ret = dyn_cast(BB->getTerminator())) { - bool Change = TRE.processReturningBlock(Ret, !CanTRETailMarkedCall); - if (!Change && BB->getFirstNonPHIOrDbg() == Ret) - Change = TRE.foldReturnAndProcessPred(Ret, !CanTRETailMarkedCall); - MadeChange |= Change; - } - } + for (BasicBlock &BB : F) + MadeChange |= TRE.processBlock(BB, !CanTRETailMarkedCall); TRE.cleanupAndFinalize(); diff --git a/llvm/lib/Transforms/Scalar/WarnMissedTransforms.cpp b/llvm/lib/Transforms/Scalar/WarnMissedTransforms.cpp index 7c81e6352dec..80a7d3a43ad6 100644 --- a/llvm/lib/Transforms/Scalar/WarnMissedTransforms.cpp +++ b/llvm/lib/Transforms/Scalar/WarnMissedTransforms.cpp @@ -48,12 +48,12 @@ static void warnAboutLeftoverTransformations(Loop *L, if (hasVectorizeTransformation(L) == TM_ForcedByUser) { LLVM_DEBUG(dbgs() << "Leftover vectorization transformation\n"); - Optional VectorizeWidth = - getOptionalIntLoopAttribute(L, "llvm.loop.vectorize.width"); + Optional VectorizeWidth = + getOptionalElementCountLoopAttribute(L); Optional InterleaveCount = getOptionalIntLoopAttribute(L, "llvm.loop.interleave.count"); - if (VectorizeWidth.getValueOr(0) != 1) + if (!VectorizeWidth || VectorizeWidth->isVector()) ORE->emit( DiagnosticInfoOptimizationFailure(DEBUG_TYPE, "FailedRequestedVectorization", diff --git a/llvm/lib/Transforms/Utils/AMDGPUEmitPrintf.cpp b/llvm/lib/Transforms/Utils/AMDGPUEmitPrintf.cpp index 84a66e1e96d2..ccdcf7cbce38 100644 --- a/llvm/lib/Transforms/Utils/AMDGPUEmitPrintf.cpp +++ b/llvm/lib/Transforms/Utils/AMDGPUEmitPrintf.cpp @@ -17,9 +17,6 @@ #include "llvm/Transforms/Utils/AMDGPUEmitPrintf.h" #include "llvm/ADT/SparseBitVector.h" #include "llvm/Analysis/ValueTracking.h" -#include "llvm/IR/IRBuilder.h" - -#include using namespace llvm; diff --git a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp index 7ff73fcdada7..3daff3b4430b 100644 --- a/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp +++ b/llvm/lib/Transforms/Utils/AssumeBundleBuilder.cpp @@ -52,6 +52,7 @@ namespace { bool isUsefullToPreserve(Attribute::AttrKind Kind) { switch (Kind) { case Attribute::NonNull: + case Attribute::NoUndef: case Attribute::Alignment: case Attribute::Dereferenceable: case Attribute::DereferenceableOrNull: @@ -69,7 +70,7 @@ RetainedKnowledge canonicalizedKnowledge(RetainedKnowledge RK, Module *M) { default: return RK; case Attribute::NonNull: - RK.WasOn = GetUnderlyingObject(RK.WasOn, M->getDataLayout()); + RK.WasOn = getUnderlyingObject(RK.WasOn); return RK; case Attribute::Alignment: { Value *V = RK.WasOn->stripInBoundsOffsets([&](const Value *Strip) { @@ -145,7 +146,7 @@ struct AssumeBuilderState { if (!RK.WasOn) return true; if (RK.WasOn->getType()->isPointerTy()) { - Value *UnderlyingPtr = GetUnderlyingObject(RK.WasOn, M->getDataLayout()); + Value *UnderlyingPtr = getUnderlyingObject(RK.WasOn); if (isa(UnderlyingPtr) || isa(UnderlyingPtr)) return false; } diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index 085d91031cf9..6bcd42c4c6d8 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -105,7 +105,7 @@ void llvm::DeleteDeadBlocks(ArrayRef BBs, DomTreeUpdater *DTU, DetatchDeadBlocks(BBs, DTU ? &Updates : nullptr, KeepOneInputPHIs); if (DTU) - DTU->applyUpdatesPermissive(Updates); + DTU->applyUpdates(Updates); for (BasicBlock *BB : BBs) if (DTU) @@ -136,9 +136,10 @@ bool llvm::EliminateUnreachableBlocks(Function &F, DomTreeUpdater *DTU, return !DeadBlocks.empty(); } -void llvm::FoldSingleEntryPHINodes(BasicBlock *BB, +bool llvm::FoldSingleEntryPHINodes(BasicBlock *BB, MemoryDependenceResults *MemDep) { - if (!isa(BB->begin())) return; + if (!isa(BB->begin())) + return false; while (PHINode *PN = dyn_cast(BB->begin())) { if (PN->getIncomingValue(0) != PN) @@ -151,6 +152,7 @@ void llvm::FoldSingleEntryPHINodes(BasicBlock *BB, PN->eraseFromParent(); } + return true; } bool llvm::DeleteDeadPHIs(BasicBlock *BB, const TargetLibraryInfo *TLI, @@ -228,19 +230,21 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU, // These dominator edges will be redirected from Pred. std::vector Updates; if (DTU) { - Updates.reserve(1 + (2 * succ_size(BB))); + SmallSetVector UniqueSuccessors(succ_begin(BB), + succ_end(BB)); + Updates.reserve(1 + (2 * UniqueSuccessors.size())); // Add insert edges first. Experimentally, for the particular case of two // blocks that can be merged, with a single successor and single predecessor // respectively, it is beneficial to have all insert updates first. Deleting // edges first may lead to unreachable blocks, followed by inserting edges // making the blocks reachable again. Such DT updates lead to high compile // times. We add inserts before deletes here to reduce compile time. - for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) + for (BasicBlock *UniqueSuccessor : UniqueSuccessors) // This successor of BB may already have PredBB as a predecessor. - if (llvm::find(successors(PredBB), *I) == succ_end(PredBB)) - Updates.push_back({DominatorTree::Insert, PredBB, *I}); - for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) - Updates.push_back({DominatorTree::Delete, BB, *I}); + if (!llvm::is_contained(successors(PredBB), UniqueSuccessor)) + Updates.push_back({DominatorTree::Insert, PredBB, UniqueSuccessor}); + for (BasicBlock *UniqueSuccessor : UniqueSuccessors) + Updates.push_back({DominatorTree::Delete, BB, UniqueSuccessor}); Updates.push_back({DominatorTree::Delete, PredBB, BB}); } @@ -285,11 +289,6 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU, // Add unreachable to now empty BB. new UnreachableInst(BB->getContext(), BB); - // Eliminate duplicate/redundant dbg.values. This seems to be a good place to - // do that since we might end up with redundant dbg.values describing the - // entry PHI node post-splice. - RemoveRedundantDbgInstrs(PredBB); - // Inherit predecessors name if it exists. if (!PredBB->hasName()) PredBB->takeName(BB); @@ -306,7 +305,7 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU, isa(BB->getTerminator()) && "The successor list of BB isn't empty before " "applying corresponding DTU updates."); - DTU->applyUpdatesPermissive(Updates); + DTU->applyUpdates(Updates); DTU->deleteBB(BB); } else { BB->eraseFromParent(); // Nuke BB if DTU is nullptr. @@ -498,14 +497,16 @@ void llvm::ReplaceInstWithInst(Instruction *From, Instruction *To) { } BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT, - LoopInfo *LI, MemorySSAUpdater *MSSAU) { + LoopInfo *LI, MemorySSAUpdater *MSSAU, + const Twine &BBName) { unsigned SuccNum = GetSuccessorNumber(BB, Succ); // If this is a critical edge, let SplitCriticalEdge do it. Instruction *LatchTerm = BB->getTerminator(); if (SplitCriticalEdge( LatchTerm, SuccNum, - CriticalEdgeSplittingOptions(DT, LI, MSSAU).setPreserveLCSSA())) + CriticalEdgeSplittingOptions(DT, LI, MSSAU).setPreserveLCSSA(), + BBName)) return LatchTerm->getSuccessor(SuccNum); // If the edge isn't critical, then BB has a single successor or Succ has a @@ -515,14 +516,15 @@ BasicBlock *llvm::SplitEdge(BasicBlock *BB, BasicBlock *Succ, DominatorTree *DT, // block. assert(SP == BB && "CFG broken"); SP = nullptr; - return SplitBlock(Succ, &Succ->front(), DT, LI, MSSAU); + return SplitBlock(Succ, &Succ->front(), DT, LI, MSSAU, BBName, + /*Before=*/true); } // Otherwise, if BB has a single successor, split it at the bottom of the // block. assert(BB->getTerminator()->getNumSuccessors() == 1 && "Should have a single succ!"); - return SplitBlock(BB, BB->getTerminator(), DT, LI, MSSAU); + return SplitBlock(BB, BB->getTerminator(), DT, LI, MSSAU, BBName); } unsigned @@ -540,9 +542,16 @@ llvm::SplitAllCriticalEdges(Function &F, return NumBroken; } -BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt, - DominatorTree *DT, LoopInfo *LI, - MemorySSAUpdater *MSSAU, const Twine &BBName) { +static BasicBlock *SplitBlockImpl(BasicBlock *Old, Instruction *SplitPt, + DomTreeUpdater *DTU, DominatorTree *DT, + LoopInfo *LI, MemorySSAUpdater *MSSAU, + const Twine &BBName, bool Before) { + if (Before) { + DomTreeUpdater LocalDTU(DT, DomTreeUpdater::UpdateStrategy::Lazy); + return splitBlockBefore(Old, SplitPt, + DTU ? DTU : (DT ? &LocalDTU : nullptr), LI, MSSAU, + BBName); + } BasicBlock::iterator SplitIt = SplitPt->getIterator(); while (isa(SplitIt) || SplitIt->isEHPad()) ++SplitIt; @@ -556,7 +565,20 @@ BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt, if (Loop *L = LI->getLoopFor(Old)) L->addBasicBlockToLoop(New, *LI); - if (DT) + if (DTU) { + SmallVector Updates; + // Old dominates New. New node dominates all other nodes dominated by Old. + SmallSetVector UniqueSuccessorsOfOld(succ_begin(New), + succ_end(New)); + Updates.push_back({DominatorTree::Insert, Old, New}); + Updates.reserve(Updates.size() + 2 * UniqueSuccessorsOfOld.size()); + for (BasicBlock *UniqueSuccessorOfOld : UniqueSuccessorsOfOld) { + Updates.push_back({DominatorTree::Insert, New, UniqueSuccessorOfOld}); + Updates.push_back({DominatorTree::Delete, Old, UniqueSuccessorOfOld}); + } + + DTU->applyUpdates(Updates); + } else if (DT) // Old dominates New. New node dominates all other nodes dominated by Old. if (DomTreeNode *OldNode = DT->getNode(Old)) { std::vector Children(OldNode->begin(), OldNode->end()); @@ -574,14 +596,94 @@ BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt, return New; } +BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt, + DominatorTree *DT, LoopInfo *LI, + MemorySSAUpdater *MSSAU, const Twine &BBName, + bool Before) { + return SplitBlockImpl(Old, SplitPt, /*DTU=*/nullptr, DT, LI, MSSAU, BBName, + Before); +} +BasicBlock *llvm::SplitBlock(BasicBlock *Old, Instruction *SplitPt, + DomTreeUpdater *DTU, LoopInfo *LI, + MemorySSAUpdater *MSSAU, const Twine &BBName, + bool Before) { + return SplitBlockImpl(Old, SplitPt, DTU, /*DT=*/nullptr, LI, MSSAU, BBName, + Before); +} + +BasicBlock *llvm::splitBlockBefore(BasicBlock *Old, Instruction *SplitPt, + DomTreeUpdater *DTU, LoopInfo *LI, + MemorySSAUpdater *MSSAU, + const Twine &BBName) { + + BasicBlock::iterator SplitIt = SplitPt->getIterator(); + while (isa(SplitIt) || SplitIt->isEHPad()) + ++SplitIt; + std::string Name = BBName.str(); + BasicBlock *New = Old->splitBasicBlock( + SplitIt, Name.empty() ? Old->getName() + ".split" : Name, + /* Before=*/true); + + // The new block lives in whichever loop the old one did. This preserves + // LCSSA as well, because we force the split point to be after any PHI nodes. + if (LI) + if (Loop *L = LI->getLoopFor(Old)) + L->addBasicBlockToLoop(New, *LI); + + if (DTU) { + SmallVector DTUpdates; + // New dominates Old. The predecessor nodes of the Old node dominate + // New node. + SmallSetVector UniquePredecessorsOfOld(pred_begin(New), + pred_end(New)); + DTUpdates.push_back({DominatorTree::Insert, New, Old}); + DTUpdates.reserve(DTUpdates.size() + 2 * UniquePredecessorsOfOld.size()); + for (BasicBlock *UniquePredecessorOfOld : UniquePredecessorsOfOld) { + DTUpdates.push_back({DominatorTree::Insert, UniquePredecessorOfOld, New}); + DTUpdates.push_back({DominatorTree::Delete, UniquePredecessorOfOld, Old}); + } + + DTU->applyUpdates(DTUpdates); + + // Move MemoryAccesses still tracked in Old, but part of New now. + // Update accesses in successor blocks accordingly. + if (MSSAU) { + MSSAU->applyUpdates(DTUpdates, DTU->getDomTree()); + if (VerifyMemorySSA) + MSSAU->getMemorySSA()->verifyMemorySSA(); + } + } + return New; +} + /// Update DominatorTree, LoopInfo, and LCCSA analysis information. static void UpdateAnalysisInformation(BasicBlock *OldBB, BasicBlock *NewBB, ArrayRef Preds, - DominatorTree *DT, LoopInfo *LI, - MemorySSAUpdater *MSSAU, + DomTreeUpdater *DTU, DominatorTree *DT, + LoopInfo *LI, MemorySSAUpdater *MSSAU, bool PreserveLCSSA, bool &HasLoopExit) { // Update dominator tree if available. - if (DT) { + if (DTU) { + // Recalculation of DomTree is needed when updating a forward DomTree and + // the Entry BB is replaced. + if (NewBB == &NewBB->getParent()->getEntryBlock() && DTU->hasDomTree()) { + // The entry block was removed and there is no external interface for + // the dominator tree to be notified of this change. In this corner-case + // we recalculate the entire tree. + DTU->recalculate(*NewBB->getParent()); + } else { + // Split block expects NewBB to have a non-empty set of predecessors. + SmallVector Updates; + SmallSetVector UniquePreds(Preds.begin(), Preds.end()); + Updates.push_back({DominatorTree::Insert, NewBB, OldBB}); + Updates.reserve(Updates.size() + 2 * UniquePreds.size()); + for (auto *UniquePred : UniquePreds) { + Updates.push_back({DominatorTree::Insert, UniquePred, NewBB}); + Updates.push_back({DominatorTree::Delete, UniquePred, OldBB}); + } + DTU->applyUpdates(Updates); + } + } else if (DT) { if (OldBB == DT->getRootNode()->getBlock()) { assert(NewBB == &NewBB->getParent()->getEntryBlock()); DT->setNewRoot(NewBB); @@ -599,6 +701,8 @@ static void UpdateAnalysisInformation(BasicBlock *OldBB, BasicBlock *NewBB, if (!LI) return; + if (DTU && DTU->hasDomTree()) + DT = &DTU->getDomTree(); assert(DT && "DT should be available to update LoopInfo!"); Loop *L = LI->getLoopFor(OldBB); @@ -732,11 +836,17 @@ static void UpdatePHINodes(BasicBlock *OrigBB, BasicBlock *NewBB, } } -BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, - ArrayRef Preds, - const char *Suffix, DominatorTree *DT, - LoopInfo *LI, MemorySSAUpdater *MSSAU, - bool PreserveLCSSA) { +static void SplitLandingPadPredecessorsImpl( + BasicBlock *OrigBB, ArrayRef Preds, const char *Suffix1, + const char *Suffix2, SmallVectorImpl &NewBBs, + DomTreeUpdater *DTU, DominatorTree *DT, LoopInfo *LI, + MemorySSAUpdater *MSSAU, bool PreserveLCSSA); + +static BasicBlock * +SplitBlockPredecessorsImpl(BasicBlock *BB, ArrayRef Preds, + const char *Suffix, DomTreeUpdater *DTU, + DominatorTree *DT, LoopInfo *LI, + MemorySSAUpdater *MSSAU, bool PreserveLCSSA) { // Do not attempt to split that which cannot be split. if (!BB->canSplitPredecessors()) return nullptr; @@ -747,8 +857,8 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, SmallVector NewBBs; std::string NewName = std::string(Suffix) + ".split-lp"; - SplitLandingPadPredecessors(BB, Preds, Suffix, NewName.c_str(), NewBBs, DT, - LI, MSSAU, PreserveLCSSA); + SplitLandingPadPredecessorsImpl(BB, Preds, Suffix, NewName.c_str(), NewBBs, + DTU, DT, LI, MSSAU, PreserveLCSSA); return NewBBs[0]; } @@ -758,12 +868,22 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, // The new block unconditionally branches to the old block. BranchInst *BI = BranchInst::Create(BB, NewBB); + + Loop *L = nullptr; + BasicBlock *OldLatch = nullptr; // Splitting the predecessors of a loop header creates a preheader block. - if (LI && LI->isLoopHeader(BB)) + if (LI && LI->isLoopHeader(BB)) { + L = LI->getLoopFor(BB); // Using the loop start line number prevents debuggers stepping into the // loop body for this instruction. - BI->setDebugLoc(LI->getLoopFor(BB)->getStartLoc()); - else + BI->setDebugLoc(L->getStartLoc()); + + // If BB is the header of the Loop, it is possible that the loop is + // modified, such that the current latch does not remain the latch of the + // loop. If that is the case, the loop metadata from the current latch needs + // to be applied to the new latch. + OldLatch = L->getLoopLatch(); + } else BI->setDebugLoc(BB->getFirstNonPHIOrDbg()->getDebugLoc()); // Move the edges from Preds to point to NewBB instead of BB. @@ -790,7 +910,7 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, // Update DominatorTree, LoopInfo, and LCCSA analysis information. bool HasLoopExit = false; - UpdateAnalysisInformation(BB, NewBB, Preds, DT, LI, MSSAU, PreserveLCSSA, + UpdateAnalysisInformation(BB, NewBB, Preds, DTU, DT, LI, MSSAU, PreserveLCSSA, HasLoopExit); if (!Preds.empty()) { @@ -798,16 +918,41 @@ BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, UpdatePHINodes(BB, NewBB, Preds, BI, HasLoopExit); } + if (OldLatch) { + BasicBlock *NewLatch = L->getLoopLatch(); + if (NewLatch != OldLatch) { + MDNode *MD = OldLatch->getTerminator()->getMetadata("llvm.loop"); + NewLatch->getTerminator()->setMetadata("llvm.loop", MD); + OldLatch->getTerminator()->setMetadata("llvm.loop", nullptr); + } + } + return NewBB; } -void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, - ArrayRef Preds, - const char *Suffix1, const char *Suffix2, - SmallVectorImpl &NewBBs, - DominatorTree *DT, LoopInfo *LI, - MemorySSAUpdater *MSSAU, - bool PreserveLCSSA) { +BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, + ArrayRef Preds, + const char *Suffix, DominatorTree *DT, + LoopInfo *LI, MemorySSAUpdater *MSSAU, + bool PreserveLCSSA) { + return SplitBlockPredecessorsImpl(BB, Preds, Suffix, /*DTU=*/nullptr, DT, LI, + MSSAU, PreserveLCSSA); +} +BasicBlock *llvm::SplitBlockPredecessors(BasicBlock *BB, + ArrayRef Preds, + const char *Suffix, + DomTreeUpdater *DTU, LoopInfo *LI, + MemorySSAUpdater *MSSAU, + bool PreserveLCSSA) { + return SplitBlockPredecessorsImpl(BB, Preds, Suffix, DTU, + /*DT=*/nullptr, LI, MSSAU, PreserveLCSSA); +} + +static void SplitLandingPadPredecessorsImpl( + BasicBlock *OrigBB, ArrayRef Preds, const char *Suffix1, + const char *Suffix2, SmallVectorImpl &NewBBs, + DomTreeUpdater *DTU, DominatorTree *DT, LoopInfo *LI, + MemorySSAUpdater *MSSAU, bool PreserveLCSSA) { assert(OrigBB->isLandingPad() && "Trying to split a non-landing pad!"); // Create a new basic block for OrigBB's predecessors listed in Preds. Insert @@ -832,8 +977,8 @@ void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, } bool HasLoopExit = false; - UpdateAnalysisInformation(OrigBB, NewBB1, Preds, DT, LI, MSSAU, PreserveLCSSA, - HasLoopExit); + UpdateAnalysisInformation(OrigBB, NewBB1, Preds, DTU, DT, LI, MSSAU, + PreserveLCSSA, HasLoopExit); // Update the PHI nodes in OrigBB with the values coming from NewBB1. UpdatePHINodes(OrigBB, NewBB1, Preds, BI1, HasLoopExit); @@ -868,7 +1013,7 @@ void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, // Update DominatorTree, LoopInfo, and LCCSA analysis information. HasLoopExit = false; - UpdateAnalysisInformation(OrigBB, NewBB2, NewBB2Preds, DT, LI, MSSAU, + UpdateAnalysisInformation(OrigBB, NewBB2, NewBB2Preds, DTU, DT, LI, MSSAU, PreserveLCSSA, HasLoopExit); // Update the PHI nodes in OrigBB with the values coming from NewBB2. @@ -905,6 +1050,29 @@ void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, } } +void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, + ArrayRef Preds, + const char *Suffix1, const char *Suffix2, + SmallVectorImpl &NewBBs, + DominatorTree *DT, LoopInfo *LI, + MemorySSAUpdater *MSSAU, + bool PreserveLCSSA) { + return SplitLandingPadPredecessorsImpl( + OrigBB, Preds, Suffix1, Suffix2, NewBBs, + /*DTU=*/nullptr, DT, LI, MSSAU, PreserveLCSSA); +} +void llvm::SplitLandingPadPredecessors(BasicBlock *OrigBB, + ArrayRef Preds, + const char *Suffix1, const char *Suffix2, + SmallVectorImpl &NewBBs, + DomTreeUpdater *DTU, LoopInfo *LI, + MemorySSAUpdater *MSSAU, + bool PreserveLCSSA) { + return SplitLandingPadPredecessorsImpl(OrigBB, Preds, Suffix1, Suffix2, + NewBBs, DTU, /*DT=*/nullptr, LI, MSSAU, + PreserveLCSSA); +} + ReturnInst *llvm::FoldReturnIntoUncondBranch(ReturnInst *RI, BasicBlock *BB, BasicBlock *Pred, DomTreeUpdater *DTU) { @@ -964,14 +1132,24 @@ ReturnInst *llvm::FoldReturnIntoUncondBranch(ReturnInst *RI, BasicBlock *BB, return cast(NewRet); } -Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, - Instruction *SplitBefore, - bool Unreachable, - MDNode *BranchWeights, - DominatorTree *DT, LoopInfo *LI, - BasicBlock *ThenBlock) { +static Instruction * +SplitBlockAndInsertIfThenImpl(Value *Cond, Instruction *SplitBefore, + bool Unreachable, MDNode *BranchWeights, + DomTreeUpdater *DTU, DominatorTree *DT, + LoopInfo *LI, BasicBlock *ThenBlock) { + SmallVector Updates; BasicBlock *Head = SplitBefore->getParent(); BasicBlock *Tail = Head->splitBasicBlock(SplitBefore->getIterator()); + if (DTU) { + SmallSetVector UniqueSuccessorsOfHead(succ_begin(Tail), + succ_end(Tail)); + Updates.push_back({DominatorTree::Insert, Head, Tail}); + Updates.reserve(Updates.size() + 2 * UniqueSuccessorsOfHead.size()); + for (BasicBlock *UniqueSuccessorOfHead : UniqueSuccessorsOfHead) { + Updates.push_back({DominatorTree::Insert, Tail, UniqueSuccessorOfHead}); + Updates.push_back({DominatorTree::Delete, Head, UniqueSuccessorOfHead}); + } + } Instruction *HeadOldTerm = Head->getTerminator(); LLVMContext &C = Head->getContext(); Instruction *CheckTerm; @@ -980,17 +1158,24 @@ Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, ThenBlock = BasicBlock::Create(C, "", Head->getParent(), Tail); if (Unreachable) CheckTerm = new UnreachableInst(C, ThenBlock); - else + else { CheckTerm = BranchInst::Create(Tail, ThenBlock); + if (DTU) + Updates.push_back({DominatorTree::Insert, ThenBlock, Tail}); + } CheckTerm->setDebugLoc(SplitBefore->getDebugLoc()); } else CheckTerm = ThenBlock->getTerminator(); BranchInst *HeadNewTerm = - BranchInst::Create(/*ifTrue*/ThenBlock, /*ifFalse*/Tail, Cond); + BranchInst::Create(/*ifTrue*/ ThenBlock, /*ifFalse*/ Tail, Cond); + if (DTU) + Updates.push_back({DominatorTree::Insert, Head, ThenBlock}); HeadNewTerm->setMetadata(LLVMContext::MD_prof, BranchWeights); ReplaceInstWithInst(HeadOldTerm, HeadNewTerm); - if (DT) { + if (DTU) + DTU->applyUpdates(Updates); + else if (DT) { if (DomTreeNode *OldNode = DT->getNode(Head)) { std::vector Children(OldNode->begin(), OldNode->end()); @@ -1016,6 +1201,27 @@ Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, return CheckTerm; } +Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, + Instruction *SplitBefore, + bool Unreachable, + MDNode *BranchWeights, + DominatorTree *DT, LoopInfo *LI, + BasicBlock *ThenBlock) { + return SplitBlockAndInsertIfThenImpl(Cond, SplitBefore, Unreachable, + BranchWeights, + /*DTU=*/nullptr, DT, LI, ThenBlock); +} +Instruction *llvm::SplitBlockAndInsertIfThen(Value *Cond, + Instruction *SplitBefore, + bool Unreachable, + MDNode *BranchWeights, + DomTreeUpdater *DTU, LoopInfo *LI, + BasicBlock *ThenBlock) { + return SplitBlockAndInsertIfThenImpl(Cond, SplitBefore, Unreachable, + BranchWeights, DTU, /*DT=*/nullptr, LI, + ThenBlock); +} + void llvm::SplitBlockAndInsertIfThenElse(Value *Cond, Instruction *SplitBefore, Instruction **ThenTerm, Instruction **ElseTerm, @@ -1326,11 +1532,11 @@ BasicBlock *llvm::CreateControlFlowHub( SmallVector Updates; if (DTU) { for (auto In : Incoming) { + Updates.push_back({DominatorTree::Insert, In, FirstGuardBlock}); for (auto Succ : successors(In)) { if (Outgoing.count(Succ)) Updates.push_back({DominatorTree::Delete, In, Succ}); } - Updates.push_back({DominatorTree::Insert, In, FirstGuardBlock}); } } diff --git a/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp b/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp index 39fb504cf7b7..939a1a3a868d 100644 --- a/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp +++ b/llvm/lib/Transforms/Utils/BreakCriticalEdges.cpp @@ -134,9 +134,9 @@ static void createPHIsForSplitLoopExit(ArrayRef Preds, } } -BasicBlock * -llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, - const CriticalEdgeSplittingOptions &Options) { +BasicBlock *llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, + const CriticalEdgeSplittingOptions &Options, + const Twine &BBName) { if (!isCriticalEdge(TI, SuccNum, Options.MergeIdenticalEdges)) return nullptr; @@ -158,22 +158,21 @@ llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, SmallVector LoopPreds; // Check if extra modifications will be required to preserve loop-simplify // form after splitting. If it would require splitting blocks with IndirectBr - // terminators, bail out if preserving loop-simplify form is requested. + // or CallBr terminators, bail out if preserving loop-simplify form is + // requested. if (LI) { if (Loop *TIL = LI->getLoopFor(TIBB)) { - // The only that we can break LoopSimplify form by splitting a critical - // edge is if after the split there exists some edge from TIL to DestBB - // *and* the only edge into DestBB from outside of TIL is that of + // The only way that we can break LoopSimplify form by splitting a + // critical edge is if after the split there exists some edge from TIL to + // DestBB *and* the only edge into DestBB from outside of TIL is that of // NewBB. If the first isn't true, then LoopSimplify still holds, NewBB // is the new exit block and it has no non-loop predecessors. If the // second isn't true, then DestBB was not in LoopSimplify form prior to // the split as it had a non-loop predecessor. In both of these cases, // the predecessor must be directly in TIL, not in a subloop, or again // LoopSimplify doesn't hold. - for (pred_iterator I = pred_begin(DestBB), E = pred_end(DestBB); I != E; - ++I) { - BasicBlock *P = *I; + for (BasicBlock *P : predecessors(DestBB)) { if (P == TIBB) continue; // The new block is known. if (LI->getLoopFor(P) != TIL) { @@ -186,7 +185,10 @@ llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, // Loop-simplify form can be preserved, if we can split all in-loop // predecessors. if (any_of(LoopPreds, [](BasicBlock *Pred) { - return isa(Pred->getTerminator()); + const Instruction *T = Pred->getTerminator(); + if (const auto *CBR = dyn_cast(T)) + return CBR->getDefaultDest() != Pred; + return isa(T); })) { if (Options.PreserveLoopSimplify) return nullptr; @@ -196,8 +198,13 @@ llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, } // Create a new basic block, linking it into the CFG. - BasicBlock *NewBB = BasicBlock::Create(TI->getContext(), - TIBB->getName() + "." + DestBB->getName() + "_crit_edge"); + BasicBlock *NewBB = nullptr; + if (BBName.str() != "") + NewBB = BasicBlock::Create(TI->getContext(), BBName); + else + NewBB = BasicBlock::Create(TI->getContext(), TIBB->getName() + "." + + DestBB->getName() + + "_crit_edge"); // Create our unconditional branch. BranchInst *NewBI = BranchInst::Create(DestBB, NewBB); NewBI->setDebugLoc(TI->getDebugLoc()); @@ -270,7 +277,7 @@ llvm::SplitCriticalEdge(Instruction *TI, unsigned SuccNum, SmallVector Updates; Updates.push_back({DominatorTree::Insert, TIBB, NewBB}); Updates.push_back({DominatorTree::Insert, NewBB, DestBB}); - if (llvm::find(successors(TIBB), DestBB) == succ_end(TIBB)) + if (!llvm::is_contained(successors(TIBB), DestBB)) Updates.push_back({DominatorTree::Delete, TIBB, DestBB}); if (DT) diff --git a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp index c64ad147fdfe..f4afa3ad4623 100644 --- a/llvm/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/BuildLibCalls.cpp @@ -31,14 +31,22 @@ using namespace llvm; //- Infer Attributes ---------------------------------------------------------// STATISTIC(NumReadNone, "Number of functions inferred as readnone"); +STATISTIC(NumInaccessibleMemOnly, + "Number of functions inferred as inaccessiblememonly"); STATISTIC(NumReadOnly, "Number of functions inferred as readonly"); STATISTIC(NumArgMemOnly, "Number of functions inferred as argmemonly"); +STATISTIC(NumInaccessibleMemOrArgMemOnly, + "Number of functions inferred as inaccessiblemem_or_argmemonly"); STATISTIC(NumNoUnwind, "Number of functions inferred as nounwind"); STATISTIC(NumNoCapture, "Number of arguments inferred as nocapture"); +STATISTIC(NumWriteOnlyArg, "Number of arguments inferred as writeonly"); +STATISTIC(NumSExtArg, "Number of arguments inferred as signext"); STATISTIC(NumReadOnlyArg, "Number of arguments inferred as readonly"); STATISTIC(NumNoAlias, "Number of function returns inferred as noalias"); +STATISTIC(NumNoUndef, "Number of function returns inferred as noundef returns"); STATISTIC(NumNonNull, "Number of function returns inferred as nonnull returns"); STATISTIC(NumReturnedArg, "Number of arguments inferred as returned"); +STATISTIC(NumWillReturn, "Number of functions inferred as willreturn"); static bool setDoesNotAccessMemory(Function &F) { if (F.doesNotAccessMemory()) @@ -48,6 +56,14 @@ static bool setDoesNotAccessMemory(Function &F) { return true; } +static bool setOnlyAccessesInaccessibleMemory(Function &F) { + if (F.onlyAccessesInaccessibleMemory()) + return false; + F.setOnlyAccessesInaccessibleMemory(); + ++NumInaccessibleMemOnly; + return true; +} + static bool setOnlyReadsMemory(Function &F) { if (F.onlyReadsMemory()) return false; @@ -64,6 +80,14 @@ static bool setOnlyAccessesArgMemory(Function &F) { return true; } +static bool setOnlyAccessesInaccessibleMemOrArgMem(Function &F) { + if (F.onlyAccessesInaccessibleMemOrArgMem()) + return false; + F.setOnlyAccessesInaccessibleMemOrArgMem(); + ++NumInaccessibleMemOrArgMemOnly; + return true; +} + static bool setDoesNotThrow(Function &F) { if (F.doesNotThrow()) return false; @@ -104,6 +128,48 @@ static bool setOnlyReadsMemory(Function &F, unsigned ArgNo) { return true; } +static bool setOnlyWritesMemory(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::WriteOnly)) + return false; + F.addParamAttr(ArgNo, Attribute::WriteOnly); + ++NumWriteOnlyArg; + return true; +} + +static bool setSignExtendedArg(Function &F, unsigned ArgNo) { + if (F.hasParamAttribute(ArgNo, Attribute::SExt)) + return false; + F.addParamAttr(ArgNo, Attribute::SExt); + ++NumSExtArg; + return true; +} + +static bool setRetNoUndef(Function &F) { + if (!F.getReturnType()->isVoidTy() && + !F.hasAttribute(AttributeList::ReturnIndex, Attribute::NoUndef)) { + F.addAttribute(AttributeList::ReturnIndex, Attribute::NoUndef); + ++NumNoUndef; + return true; + } + return false; +} + +static bool setArgsNoUndef(Function &F) { + bool Changed = false; + for (unsigned ArgNo = 0; ArgNo < F.arg_size(); ++ArgNo) { + if (!F.hasParamAttribute(ArgNo, Attribute::NoUndef)) { + F.addParamAttr(ArgNo, Attribute::NoUndef); + ++NumNoUndef; + Changed = true; + } + } + return Changed; +} + +static bool setRetAndArgsNoUndef(Function &F) { + return setRetNoUndef(F) | setArgsNoUndef(F); +} + static bool setRetNonNull(Function &F) { assert(F.getReturnType()->isPointerTy() && "nonnull applies only to pointers"); @@ -136,6 +202,14 @@ static bool setDoesNotFreeMemory(Function &F) { return true; } +static bool setWillReturn(Function &F) { + if (F.hasFnAttribute(Attribute::WillReturn)) + return false; + F.addFnAttr(Attribute::WillReturn); + ++NumWillReturn; + return true; +} + bool llvm::inferLibFuncAttributes(Module *M, StringRef Name, const TargetLibraryInfo &TLI) { Function *F = M->getFunction(Name); @@ -163,12 +237,15 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_strchr: case LibFunc_strrchr: + Changed |= setOnlyAccessesArgMemory(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_strtol: case LibFunc_strtod: @@ -178,26 +255,31 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_strtold: case LibFunc_strtoull: Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_strcpy: case LibFunc_strncpy: - Changed |= setDoesNotAlias(F, 0); - Changed |= setDoesNotAlias(F, 1); - LLVM_FALLTHROUGH; case LibFunc_strcat: case LibFunc_strncat: + Changed |= setWillReturn(F); Changed |= setReturnedArg(F, 0); LLVM_FALLTHROUGH; case LibFunc_stpcpy: case LibFunc_stpncpy: + Changed |= setOnlyAccessesArgMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setOnlyReadsMemory(F, 1); + Changed |= setDoesNotAlias(F, 0); + Changed |= setDoesNotAlias(F, 1); return Changed; case LibFunc_strxfrm: Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); @@ -206,51 +288,70 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_strspn: // 0,1 case LibFunc_strncmp: // 0,1 case LibFunc_strcspn: // 0,1 - case LibFunc_strcoll: // 0,1 + Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); + Changed |= setOnlyReadsMemory(F); + Changed |= setDoesNotCapture(F, 0); + Changed |= setDoesNotCapture(F, 1); + return Changed; + case LibFunc_strcoll: case LibFunc_strcasecmp: // 0,1 case LibFunc_strncasecmp: // + // Those functions may depend on the locale, which may be accessed through + // global memory. Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_strstr: case LibFunc_strpbrk: + Changed |= setOnlyAccessesArgMemory(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_strtok: case LibFunc_strtok_r: Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_scanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_setbuf: case LibFunc_setvbuf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_strdup: case LibFunc_strndup: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_stat: case LibFunc_statvfs: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_sscanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -258,70 +359,95 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_sprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotAlias(F, 0); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_snprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotAlias(F, 0); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setDoesNotCapture(F, 2); Changed |= setOnlyReadsMemory(F, 2); return Changed; case LibFunc_setitimer: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); Changed |= setDoesNotCapture(F, 2); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_system: // May throw; "system" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_malloc: + case LibFunc_vec_malloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_memcmp: + Changed |= setOnlyAccessesArgMemory(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_memchr: case LibFunc_memrchr: - Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setOnlyReadsMemory(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_modf: case LibFunc_modff: case LibFunc_modfl: Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_memcpy: + Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotAlias(F, 0); - Changed |= setDoesNotAlias(F, 1); Changed |= setReturnedArg(F, 0); - Changed |= setDoesNotThrow(F); + Changed |= setOnlyWritesMemory(F, 0); + Changed |= setDoesNotAlias(F, 1); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_memmove: - Changed |= setReturnedArg(F, 0); Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); + Changed |= setReturnedArg(F, 0); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_mempcpy: case LibFunc_memccpy: + Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotAlias(F, 0); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setDoesNotAlias(F, 1); - Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; @@ -329,38 +455,57 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotThrow(F); return Changed; case LibFunc_memalign: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); + Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_mkdir: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_mktime: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_realloc: + case LibFunc_vec_realloc: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); return Changed; + case LibFunc_reallocf: + Changed |= setRetNoUndef(F); + Changed |= setWillReturn(F); + return Changed; case LibFunc_read: // May throw; "read" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_rewind: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_rmdir: case LibFunc_remove: case LibFunc_realpath: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_rename: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -368,6 +513,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_readlink: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -375,35 +521,52 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_write: // May throw; "write" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_aligned_alloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_bcopy: Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); - Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); + Changed |= setOnlyWritesMemory(F, 1); + Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_bcmp: Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); Changed |= setOnlyReadsMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_bzero: Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyWritesMemory(F, 0); return Changed; case LibFunc_calloc: + case LibFunc_vec_calloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_chmod: case LibFunc_chown: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); @@ -411,6 +574,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_ctermid: case LibFunc_clearerr: case LibFunc_closedir: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; @@ -420,14 +584,17 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_atoll: Changed |= setDoesNotThrow(F); Changed |= setOnlyReadsMemory(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_access: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_fopen: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 0); @@ -436,13 +603,25 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_fdopen: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_feof: + Changed |= setRetAndArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; case LibFunc_free: + case LibFunc_vec_free: + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); + Changed |= setArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; case LibFunc_fseek: case LibFunc_ftell: case LibFunc_fgetc: @@ -456,10 +635,12 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_flockfile: case LibFunc_funlockfile: case LibFunc_ftrylockfile: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_ferror: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F); @@ -467,26 +648,38 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_fputc: case LibFunc_fputc_unlocked: case LibFunc_fstat: + Changed |= setRetAndArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; case LibFunc_frexp: case LibFunc_frexpf: case LibFunc_frexpl: + Changed |= setDoesNotThrow(F); + Changed |= setWillReturn(F); + Changed |= setDoesNotCapture(F, 1); + return Changed; case LibFunc_fstatvfs: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_fgets: case LibFunc_fgets_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 2); return Changed; case LibFunc_fread: case LibFunc_fread_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); return Changed; case LibFunc_fwrite: case LibFunc_fwrite_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 3); @@ -494,6 +687,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_fputs: case LibFunc_fputs_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -501,23 +695,35 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_fscanf: case LibFunc_fprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_fgetpos: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_getc: + Changed |= setRetAndArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; case LibFunc_getlogin_r: + Changed |= setRetAndArgsNoUndef(F); + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; case LibFunc_getc_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_getenv: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setOnlyReadsMemory(F); Changed |= setDoesNotCapture(F, 0); @@ -525,37 +731,45 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_gets: case LibFunc_getchar: case LibFunc_getchar_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); return Changed; case LibFunc_getitimer: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_getpwnam: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_ungetc: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_uname: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_unlink: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_unsetenv: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_utime: case LibFunc_utimes: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -564,30 +778,36 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_putc: case LibFunc_putc_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_puts: case LibFunc_printf: case LibFunc_perror: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_pread: // May throw; "pread" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_pwrite: // May throw; "pwrite" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_putchar: case LibFunc_putchar_unlocked: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); return Changed; case LibFunc_popen: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 0); @@ -596,15 +816,18 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_pclose: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_vscanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_vsscanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -612,28 +835,35 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_vfscanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_valloc: + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; case LibFunc_vprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_vfprintf: case LibFunc_vsprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_vsnprintf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 2); @@ -641,20 +871,24 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_open: // May throw; "open" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_opendir: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_tmpfile: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; case LibFunc_times: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; @@ -666,24 +900,29 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setDoesNotAccessMemory(F); return Changed; case LibFunc_lstat: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_lchown: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_qsort: // May throw; places call through function pointer. + // Cannot give undef pointer/size + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 3); return Changed; case LibFunc_dunder_strdup: case LibFunc_dunder_strndup: Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; @@ -693,14 +932,17 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_under_IO_getc: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_under_IO_putc: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_dunder_isoc99_scanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); @@ -708,12 +950,14 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_stat64: case LibFunc_lstat64: case LibFunc_statvfs64: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 0); return Changed; case LibFunc_dunder_isoc99_sscanf: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); @@ -721,6 +965,7 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { Changed |= setOnlyReadsMemory(F, 1); return Changed; case LibFunc_fopen64: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); Changed |= setDoesNotCapture(F, 0); @@ -730,20 +975,24 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { return Changed; case LibFunc_fseeko64: case LibFunc_ftello64: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); return Changed; case LibFunc_tmpfile64: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setRetDoesNotAlias(F); return Changed; case LibFunc_fstat64: case LibFunc_fstatvfs64: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 1); return Changed; case LibFunc_open64: // May throw; "open" is a valid pthread cancellation point. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotCapture(F, 0); Changed |= setOnlyReadsMemory(F, 0); return Changed; @@ -751,21 +1000,67 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { // Currently some platforms have the restrict keyword on the arguments to // gettimeofday. To be conservative, do not add noalias to gettimeofday's // arguments. + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotThrow(F); Changed |= setDoesNotCapture(F, 0); Changed |= setDoesNotCapture(F, 1); return Changed; + case LibFunc_ZdlPvRKSt9nothrow_t: // delete(void*, nothrow) + case LibFunc_ZdlPvSt11align_val_tRKSt9nothrow_t: // delete(void*, align_val_t, nothrow) + case LibFunc_ZdaPvRKSt9nothrow_t: // delete[](void*, nothrow) + case LibFunc_ZdaPvSt11align_val_tRKSt9nothrow_t: // delete[](void*, align_val_t, nothrow) + Changed |= setDoesNotThrow(F); + LLVM_FALLTHROUGH; + case LibFunc_ZdlPv: // delete(void*) + case LibFunc_ZdlPvj: // delete(void*, unsigned int) + case LibFunc_ZdlPvm: // delete(void*, unsigned long) + case LibFunc_ZdaPv: // delete[](void*) + case LibFunc_ZdaPvj: // delete[](void*, unsigned int) + case LibFunc_ZdaPvm: // delete[](void*, unsigned long) + case LibFunc_ZdlPvSt11align_val_t: // delete(void*, align_val_t) + case LibFunc_ZdlPvjSt11align_val_t: // delete(void*, unsigned int, align_val_t) + case LibFunc_ZdlPvmSt11align_val_t: // delete(void*, unsigned long, align_val_t) + case LibFunc_ZdaPvSt11align_val_t: // delete[](void*, align_val_t) + case LibFunc_ZdaPvjSt11align_val_t: // delete[](void*, unsigned int, align_val_t) + case LibFunc_ZdaPvmSt11align_val_t: // delete[](void*, unsigned long, align_val_t); + Changed |= setOnlyAccessesInaccessibleMemOrArgMem(F); + Changed |= setArgsNoUndef(F); + Changed |= setWillReturn(F); + Changed |= setDoesNotCapture(F, 0); + return Changed; + case LibFunc_ZnwjRKSt9nothrow_t: // new(unsigned int, nothrow) + case LibFunc_ZnwmRKSt9nothrow_t: // new(unsigned long, nothrow) + case LibFunc_ZnajRKSt9nothrow_t: // new[](unsigned int, nothrow) + case LibFunc_ZnamRKSt9nothrow_t: // new[](unsigned long, nothrow) + case LibFunc_ZnwjSt11align_val_tRKSt9nothrow_t: // new(unsigned int, align_val_t, nothrow) + case LibFunc_ZnwmSt11align_val_tRKSt9nothrow_t: // new(unsigned long, align_val_t, nothrow) + case LibFunc_ZnajSt11align_val_tRKSt9nothrow_t: // new[](unsigned int, align_val_t, nothrow) + case LibFunc_ZnamSt11align_val_tRKSt9nothrow_t: // new[](unsigned long, align_val_t, nothrow) + // Nothrow operator new may return null pointer + Changed |= setDoesNotThrow(F); + Changed |= setOnlyAccessesInaccessibleMemory(F); + Changed |= setRetNoUndef(F); + Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); + return Changed; case LibFunc_Znwj: // new(unsigned int) case LibFunc_Znwm: // new(unsigned long) case LibFunc_Znaj: // new[](unsigned int) case LibFunc_Znam: // new[](unsigned long) + case LibFunc_ZnwjSt11align_val_t: // new(unsigned int, align_val_t) + case LibFunc_ZnwmSt11align_val_t: // new(unsigned long, align_val_t) + case LibFunc_ZnajSt11align_val_t: // new[](unsigned int, align_val_t) + case LibFunc_ZnamSt11align_val_t: // new[](unsigned long, align_val_t) case LibFunc_msvc_new_int: // new(unsigned int) case LibFunc_msvc_new_longlong: // new(unsigned long long) case LibFunc_msvc_new_array_int: // new[](unsigned int) case LibFunc_msvc_new_array_longlong: // new[](unsigned long long) + Changed |= setOnlyAccessesInaccessibleMemory(F); // Operator new always returns a nonnull noalias pointer + Changed |= setRetNoUndef(F); Changed |= setRetNonNull(F); Changed |= setRetDoesNotAlias(F); + Changed |= setWillReturn(F); return Changed; // TODO: add LibFunc entries for: // case LibFunc_memset_pattern4: @@ -773,15 +1068,155 @@ bool llvm::inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI) { case LibFunc_memset_pattern16: Changed |= setOnlyAccessesArgMemory(F); Changed |= setDoesNotCapture(F, 0); + Changed |= setOnlyWritesMemory(F, 0); Changed |= setDoesNotCapture(F, 1); Changed |= setOnlyReadsMemory(F, 1); return Changed; + case LibFunc_memset: + Changed |= setOnlyAccessesArgMemory(F); + Changed |= setWillReturn(F); + Changed |= setDoesNotThrow(F); + Changed |= setOnlyWritesMemory(F, 0); + return Changed; // int __nvvm_reflect(const char *) case LibFunc_nvvm_reflect: + Changed |= setRetAndArgsNoUndef(F); Changed |= setDoesNotAccessMemory(F); Changed |= setDoesNotThrow(F); return Changed; - + case LibFunc_ldexp: + case LibFunc_ldexpf: + case LibFunc_ldexpl: + Changed |= setSignExtendedArg(F, 1); + Changed |= setWillReturn(F); + return Changed; + case LibFunc_abs: + case LibFunc_acos: + case LibFunc_acosf: + case LibFunc_acosh: + case LibFunc_acoshf: + case LibFunc_acoshl: + case LibFunc_acosl: + case LibFunc_asin: + case LibFunc_asinf: + case LibFunc_asinh: + case LibFunc_asinhf: + case LibFunc_asinhl: + case LibFunc_asinl: + case LibFunc_atan: + case LibFunc_atan2: + case LibFunc_atan2f: + case LibFunc_atan2l: + case LibFunc_atanf: + case LibFunc_atanh: + case LibFunc_atanhf: + case LibFunc_atanhl: + case LibFunc_atanl: + case LibFunc_cbrt: + case LibFunc_cbrtf: + case LibFunc_cbrtl: + case LibFunc_ceil: + case LibFunc_ceilf: + case LibFunc_ceill: + case LibFunc_copysign: + case LibFunc_copysignf: + case LibFunc_copysignl: + case LibFunc_cos: + case LibFunc_cosh: + case LibFunc_coshf: + case LibFunc_coshl: + case LibFunc_cosf: + case LibFunc_cosl: + case LibFunc_cospi: + case LibFunc_cospif: + case LibFunc_exp: + case LibFunc_expf: + case LibFunc_expl: + case LibFunc_exp2: + case LibFunc_exp2f: + case LibFunc_exp2l: + case LibFunc_expm1: + case LibFunc_expm1f: + case LibFunc_expm1l: + case LibFunc_fabs: + case LibFunc_fabsf: + case LibFunc_fabsl: + case LibFunc_ffs: + case LibFunc_ffsl: + case LibFunc_ffsll: + case LibFunc_floor: + case LibFunc_floorf: + case LibFunc_floorl: + case LibFunc_fls: + case LibFunc_flsl: + case LibFunc_flsll: + case LibFunc_fmax: + case LibFunc_fmaxf: + case LibFunc_fmaxl: + case LibFunc_fmin: + case LibFunc_fminf: + case LibFunc_fminl: + case LibFunc_fmod: + case LibFunc_fmodf: + case LibFunc_fmodl: + case LibFunc_isascii: + case LibFunc_isdigit: + case LibFunc_labs: + case LibFunc_llabs: + case LibFunc_log: + case LibFunc_log10: + case LibFunc_log10f: + case LibFunc_log10l: + case LibFunc_log1p: + case LibFunc_log1pf: + case LibFunc_log1pl: + case LibFunc_log2: + case LibFunc_log2f: + case LibFunc_log2l: + case LibFunc_logb: + case LibFunc_logbf: + case LibFunc_logbl: + case LibFunc_logf: + case LibFunc_logl: + case LibFunc_nearbyint: + case LibFunc_nearbyintf: + case LibFunc_nearbyintl: + case LibFunc_pow: + case LibFunc_powf: + case LibFunc_powl: + case LibFunc_rint: + case LibFunc_rintf: + case LibFunc_rintl: + case LibFunc_round: + case LibFunc_roundf: + case LibFunc_roundl: + case LibFunc_sin: + case LibFunc_sincospif_stret: + case LibFunc_sinf: + case LibFunc_sinh: + case LibFunc_sinhf: + case LibFunc_sinhl: + case LibFunc_sinl: + case LibFunc_sinpi: + case LibFunc_sinpif: + case LibFunc_sqrt: + case LibFunc_sqrtf: + case LibFunc_sqrtl: + case LibFunc_strnlen: + case LibFunc_tan: + case LibFunc_tanf: + case LibFunc_tanh: + case LibFunc_tanhf: + case LibFunc_tanhl: + case LibFunc_tanl: + case LibFunc_toascii: + case LibFunc_trunc: + case LibFunc_truncf: + case LibFunc_truncl: + Changed |= setDoesNotThrow(F); + Changed |= setDoesNotFreeMemory(F); + Changed |= setWillReturn(F); + return Changed; default: // FIXME: It'd be really nice to cover all the library functions we're // aware of here. @@ -930,6 +1365,15 @@ Value *llvm::emitMemCpyChk(Value *Dst, Value *Src, Value *Len, Value *ObjSize, return CI; } +Value *llvm::emitMemPCpy(Value *Dst, Value *Src, Value *Len, IRBuilderBase &B, + const DataLayout &DL, const TargetLibraryInfo *TLI) { + LLVMContext &Context = B.GetInsertBlock()->getContext(); + return emitLibCall( + LibFunc_mempcpy, B.getInt8PtrTy(), + {B.getInt8PtrTy(), B.getInt8PtrTy(), DL.getIntPtrType(Context)}, + {Dst, Src, Len}, B, TLI); +} + Value *llvm::emitMemChr(Value *Ptr, Value *Val, Value *Len, IRBuilderBase &B, const DataLayout &DL, const TargetLibraryInfo *TLI) { LLVMContext &Context = B.GetInsertBlock()->getContext(); @@ -969,7 +1413,7 @@ Value *llvm::emitSNPrintf(Value *Dest, Value *Size, Value *Fmt, ArrayRef VariadicArgs, IRBuilderBase &B, const TargetLibraryInfo *TLI) { SmallVector Args{castToCStr(Dest, B), Size, castToCStr(Fmt, B)}; - Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + llvm::append_range(Args, VariadicArgs); return emitLibCall(LibFunc_snprintf, B.getInt32Ty(), {B.getInt8PtrTy(), Size->getType(), B.getInt8PtrTy()}, Args, B, TLI, /*IsVaArgs=*/true); @@ -979,7 +1423,7 @@ Value *llvm::emitSPrintf(Value *Dest, Value *Fmt, ArrayRef VariadicArgs, IRBuilderBase &B, const TargetLibraryInfo *TLI) { SmallVector Args{castToCStr(Dest, B), castToCStr(Fmt, B)}; - Args.insert(Args.end(), VariadicArgs.begin(), VariadicArgs.end()); + llvm::append_range(Args, VariadicArgs); return emitLibCall(LibFunc_sprintf, B.getInt32Ty(), {B.getInt8PtrTy(), B.getInt8PtrTy()}, Args, B, TLI, /*IsVaArgs=*/true); @@ -1087,12 +1531,15 @@ Value *llvm::emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI, static Value *emitBinaryFloatFnCallHelper(Value *Op1, Value *Op2, StringRef Name, IRBuilderBase &B, - const AttributeList &Attrs) { + const AttributeList &Attrs, + const TargetLibraryInfo *TLI = nullptr) { assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall"); Module *M = B.GetInsertBlock()->getModule(); FunctionCallee Callee = M->getOrInsertFunction(Name, Op1->getType(), Op1->getType(), Op2->getType()); + if (TLI != nullptr) + inferLibFuncAttributes(M, Name, *TLI); CallInst *CI = B.CreateCall(Callee, { Op1, Op2 }, Name); // The incoming attribute set may have come from a speculatable intrinsic, but @@ -1128,7 +1575,7 @@ Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name = getFloatFnName(TLI, Op1->getType(), DoubleFn, FloatFn, LongDoubleFn); - return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs); + return emitBinaryFloatFnCallHelper(Op1, Op2, Name, B, Attrs, TLI); } Value *llvm::emitPutChar(Value *Char, IRBuilderBase &B, diff --git a/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp b/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp index 52e859361c59..b2763900e154 100644 --- a/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp +++ b/llvm/lib/Transforms/Utils/CallGraphUpdater.cpp @@ -96,11 +96,12 @@ void CallGraphUpdater::reanalyzeFunction(Function &Fn) { } } -void CallGraphUpdater::registerOutlinedFunction(Function &NewFn) { +void CallGraphUpdater::registerOutlinedFunction(Function &OriginalFn, + Function &NewFn) { if (CG) CG->addToCallGraph(&NewFn); else if (LCG) - LCG->addNewFunctionIntoSCC(NewFn, *SCC); + LCG->addSplitFunction(OriginalFn, NewFn); } void CallGraphUpdater::removeFunction(Function &DeadFn) { diff --git a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp index 5a47c1fd0b6c..bf08bf274737 100644 --- a/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp +++ b/llvm/lib/Transforms/Utils/CallPromotionUtils.cpp @@ -112,9 +112,7 @@ static void createRetPHINode(Instruction *OrigInst, Instruction *NewInst, Builder.SetInsertPoint(&MergeBlock->front()); PHINode *Phi = Builder.CreatePHI(OrigInst->getType(), 0); - SmallVector UsersToUpdate; - for (User *U : OrigInst->users()) - UsersToUpdate.push_back(U); + SmallVector UsersToUpdate(OrigInst->users()); for (User *U : UsersToUpdate) U->replaceUsesOfWith(OrigInst, Phi); Phi->addIncoming(OrigInst, OrigInst->getParent()); @@ -165,9 +163,7 @@ static void createRetBitCast(CallBase &CB, Type *RetTy, CastInst **RetBitCast) { // Save the users of the calling instruction. These uses will be changed to // use the bitcast after we create it. - SmallVector UsersToUpdate; - for (User *U : CB.users()) - UsersToUpdate.push_back(U); + SmallVector UsersToUpdate(CB.users()); // Determine an appropriate location to create the bitcast for the return // value. The location depends on if we have a call or invoke instruction. @@ -430,10 +426,11 @@ bool llvm::isLegalToPromote(const CallBase &CB, Function *Callee, } } for (; I < NumArgs; I++) { - // Vararg functions can have more arguments than paramters. + // Vararg functions can have more arguments than parameters. assert(Callee->isVarArg()); if (CB.paramHasAttr(I, Attribute::StructRet)) { - *FailureReason = "SRet arg to vararg function"; + if (FailureReason) + *FailureReason = "SRet arg to vararg function"; return false; } } diff --git a/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp b/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp index 1ae17c64b8f6..1f649fe6c748 100644 --- a/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp +++ b/llvm/lib/Transforms/Utils/CanonicalizeFreezeInLoops.cpp @@ -109,7 +109,7 @@ void CanonicalizeFreezeInLoopsImpl::InsertFreezeAndForgetFromSCEV(Use &U) { auto *ValueToFr = U.get(); assert(L->contains(UserI->getParent()) && "Should not process an instruction that isn't inside the loop"); - if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, UserI, &DT)) + if (isGuaranteedNotToBeUndefOrPoison(ValueToFr, nullptr, UserI, &DT)) return; LLVM_DEBUG(dbgs() << "canonfr: inserting freeze:\n"); @@ -176,7 +176,7 @@ bool CanonicalizeFreezeInLoopsImpl::run() { assert(StepI && "Step instruction should have been found"); // Drop flags from the step instruction. - if (!isGuaranteedNotToBeUndefOrPoison(StepI, StepI, &DT)) { + if (!isGuaranteedNotToBeUndefOrPoison(StepI, nullptr, StepI, &DT)) { LLVM_DEBUG(dbgs() << "canonfr: drop flags: " << *StepI << "\n"); StepI->dropPoisonGeneratingFlags(); SE.forgetValue(StepI); diff --git a/llvm/lib/Transforms/Utils/CloneFunction.cpp b/llvm/lib/Transforms/Utils/CloneFunction.cpp index 788983c15690..51a49574e55d 100644 --- a/llvm/lib/Transforms/Utils/CloneFunction.cpp +++ b/llvm/lib/Transforms/Utils/CloneFunction.cpp @@ -27,6 +27,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -36,6 +37,8 @@ #include using namespace llvm; +#define DEBUG_TYPE "clone-function" + /// See comments in Cloning.h. BasicBlock *llvm::CloneBasicBlock(const BasicBlock *BB, ValueToValueMapTy &VMap, const Twine &NameSuffix, Function *F, @@ -137,15 +140,10 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, MD[SP].reset(SP); } - SmallVector, 1> MDs; - OldFunc->getAllMetadata(MDs); - for (auto MD : MDs) { - NewFunc->addMetadata( - MD.first, - *MapMetadata(MD.second, VMap, - ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, - TypeMapper, Materializer)); - } + // Everything else beyond this point deals with function instructions, + // so if we are dealing with a function declaration, we're done. + if (OldFunc->isDeclaration()) + return; // When we remap instructions, we want to avoid duplicating inlined // DISubprograms, so record all subprograms we find as we duplicate @@ -157,7 +155,6 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, // Loop over all of the basic blocks in the function, cloning them as // appropriate. Note that we save BE this way in order to handle cloning of // recursive functions into themselves. - // for (Function::const_iterator BI = OldFunc->begin(), BE = OldFunc->end(); BI != BE; ++BI) { const BasicBlock &BB = *BI; @@ -196,6 +193,19 @@ void llvm::CloneFunctionInto(Function *NewFunc, const Function *OldFunc, for (DIType *Type : DIFinder.types()) VMap.MD()[Type].reset(Type); + // Duplicate the metadata that is attached to the cloned function. + // Subprograms/CUs/types that were already mapped to themselves won't be + // duplicated. + SmallVector, 1> MDs; + OldFunc->getAllMetadata(MDs); + for (auto MD : MDs) { + NewFunc->addMetadata( + MD.first, + *MapMetadata(MD.second, VMap, + ModuleLevelChanges ? RF_None : RF_NoModuleLevelChanges, + TypeMapper, Materializer)); + } + // Loop over all of the instructions in the function, fixing up operand // references as we go. This uses VMap to do all the hard work. for (Function::iterator BB = @@ -426,9 +436,7 @@ void PruningFunctionCloner::CloneBlock(const BasicBlock *BB, CodeInfo->OperandBundleCallSites.push_back(NewInst); // Recursively clone any reachable successor blocks. - const Instruction *TI = BB->getTerminator(); - for (const BasicBlock *Succ : successors(TI)) - ToClone.push_back(Succ); + append_range(ToClone, successors(BB->getTerminator())); } if (CodeInfo) { @@ -668,8 +676,7 @@ void llvm::CloneAndPruneIntoFromInst(Function *NewFunc, const Function *OldFunc, // Check if this block has become dead during inlining or other // simplifications. Note that the first block will appear dead, as it has // not yet been wired up properly. - if (I != Begin && (pred_begin(&*I) == pred_end(&*I) || - I->getSinglePredecessor() == &*I)) { + if (I != Begin && (pred_empty(&*I) || I->getSinglePredecessor() == &*I)) { BasicBlock *DeadBB = &*I++; DeleteDeadBlock(DeadBB); continue; @@ -877,3 +884,108 @@ BasicBlock *llvm::DuplicateInstructionsInSplitBetween( return NewBB; } + +void llvm::cloneNoAliasScopes( + ArrayRef NoAliasDeclScopes, + DenseMap &ClonedScopes, + StringRef Ext, LLVMContext &Context) { + MDBuilder MDB(Context); + + for (auto *ScopeList : NoAliasDeclScopes) { + for (auto &MDOperand : ScopeList->operands()) { + if (MDNode *MD = dyn_cast(MDOperand)) { + AliasScopeNode SNANode(MD); + + std::string Name; + auto ScopeName = SNANode.getName(); + if (!ScopeName.empty()) + Name = (Twine(ScopeName) + ":" + Ext).str(); + else + Name = std::string(Ext); + + MDNode *NewScope = MDB.createAnonymousAliasScope( + const_cast(SNANode.getDomain()), Name); + ClonedScopes.insert(std::make_pair(MD, NewScope)); + } + } + } +} + +void llvm::adaptNoAliasScopes( + Instruction *I, const DenseMap &ClonedScopes, + LLVMContext &Context) { + auto CloneScopeList = [&](const MDNode *ScopeList) -> MDNode * { + bool NeedsReplacement = false; + SmallVector NewScopeList; + for (auto &MDOp : ScopeList->operands()) { + if (MDNode *MD = dyn_cast(MDOp)) { + if (auto *NewMD = ClonedScopes.lookup(MD)) { + NewScopeList.push_back(NewMD); + NeedsReplacement = true; + continue; + } + NewScopeList.push_back(MD); + } + } + if (NeedsReplacement) + return MDNode::get(Context, NewScopeList); + return nullptr; + }; + + if (auto *Decl = dyn_cast(I)) + if (auto *NewScopeList = CloneScopeList(Decl->getScopeList())) + Decl->setScopeList(NewScopeList); + + auto replaceWhenNeeded = [&](unsigned MD_ID) { + if (const MDNode *CSNoAlias = I->getMetadata(MD_ID)) + if (auto *NewScopeList = CloneScopeList(CSNoAlias)) + I->setMetadata(MD_ID, NewScopeList); + }; + replaceWhenNeeded(LLVMContext::MD_noalias); + replaceWhenNeeded(LLVMContext::MD_alias_scope); +} + +void llvm::cloneAndAdaptNoAliasScopes( + ArrayRef NoAliasDeclScopes, + ArrayRef NewBlocks, LLVMContext &Context, StringRef Ext) { + if (NoAliasDeclScopes.empty()) + return; + + DenseMap ClonedScopes; + LLVM_DEBUG(dbgs() << "cloneAndAdaptNoAliasScopes: cloning " + << NoAliasDeclScopes.size() << " node(s)\n"); + + cloneNoAliasScopes(NoAliasDeclScopes, ClonedScopes, Ext, Context); + // Identify instructions using metadata that needs adaptation + for (BasicBlock *NewBlock : NewBlocks) + for (Instruction &I : *NewBlock) + adaptNoAliasScopes(&I, ClonedScopes, Context); +} + +void llvm::cloneAndAdaptNoAliasScopes( + ArrayRef NoAliasDeclScopes, Instruction *IStart, + Instruction *IEnd, LLVMContext &Context, StringRef Ext) { + if (NoAliasDeclScopes.empty()) + return; + + DenseMap ClonedScopes; + LLVM_DEBUG(dbgs() << "cloneAndAdaptNoAliasScopes: cloning " + << NoAliasDeclScopes.size() << " node(s)\n"); + + cloneNoAliasScopes(NoAliasDeclScopes, ClonedScopes, Ext, Context); + // Identify instructions using metadata that needs adaptation + assert(IStart->getParent() == IEnd->getParent() && "different basic block ?"); + auto ItStart = IStart->getIterator(); + auto ItEnd = IEnd->getIterator(); + ++ItEnd; // IEnd is included, increment ItEnd to get the end of the range + for (auto &I : llvm::make_range(ItStart, ItEnd)) + adaptNoAliasScopes(&I, ClonedScopes, Context); +} + +void llvm::identifyNoAliasScopesToClone( + ArrayRef BBs, SmallVectorImpl &NoAliasDeclScopes) { + for (BasicBlock *BB : BBs) + for (Instruction &I : *BB) + if (auto *Decl = dyn_cast(&I)) + NoAliasDeclScopes.push_back(Decl->getScopeList()); +} diff --git a/llvm/lib/Transforms/Utils/CloneModule.cpp b/llvm/lib/Transforms/Utils/CloneModule.cpp index 2c8c3abb2922..a6327bbf21bc 100644 --- a/llvm/lib/Transforms/Utils/CloneModule.cpp +++ b/llvm/lib/Transforms/Utils/CloneModule.cpp @@ -117,10 +117,17 @@ std::unique_ptr llvm::CloneModule( // for (Module::const_global_iterator I = M.global_begin(), E = M.global_end(); I != E; ++I) { + GlobalVariable *GV = cast(VMap[&*I]); + + SmallVector, 1> MDs; + I->getAllMetadata(MDs); + for (auto MD : MDs) + GV->addMetadata(MD.first, + *MapMetadata(MD.second, VMap, RF_MoveDistinctMDs)); + if (I->isDeclaration()) continue; - GlobalVariable *GV = cast(VMap[&*I]); if (!ShouldCloneDefinition(&*I)) { // Skip after setting the correct linkage for an external reference. GV->setLinkage(GlobalValue::ExternalLinkage); @@ -129,12 +136,6 @@ std::unique_ptr llvm::CloneModule( if (I->hasInitializer()) GV->setInitializer(MapValue(I->getInitializer(), VMap)); - SmallVector, 1> MDs; - I->getAllMetadata(MDs); - for (auto MD : MDs) - GV->addMetadata(MD.first, - *MapMetadata(MD.second, VMap, RF_MoveDistinctMDs)); - copyComdat(GV, &*I); } diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 8cdbb9d35652..390925a03b73 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -535,6 +535,46 @@ void CodeExtractor::findAllocas(const CodeExtractorAnalysisCache &CEAC, continue; } + // Find bitcasts in the outlined region that have lifetime marker users + // outside that region. Replace the lifetime marker use with an + // outside region bitcast to avoid unnecessary alloca/reload instructions + // and extra lifetime markers. + SmallVector LifetimeBitcastUsers; + for (User *U : AI->users()) { + if (!definedInRegion(Blocks, U)) + continue; + + if (U->stripInBoundsConstantOffsets() != AI) + continue; + + Instruction *Bitcast = cast(U); + for (User *BU : Bitcast->users()) { + IntrinsicInst *IntrInst = dyn_cast(BU); + if (!IntrInst) + continue; + + if (!IntrInst->isLifetimeStartOrEnd()) + continue; + + if (definedInRegion(Blocks, IntrInst)) + continue; + + LLVM_DEBUG(dbgs() << "Replace use of extracted region bitcast" + << *Bitcast << " in out-of-region lifetime marker " + << *IntrInst << "\n"); + LifetimeBitcastUsers.push_back(IntrInst); + } + } + + for (Instruction *I : LifetimeBitcastUsers) { + Module *M = AIFunc->getParent(); + LLVMContext &Ctx = M->getContext(); + auto *Int8PtrTy = Type::getInt8PtrTy(Ctx); + CastInst *CastI = + CastInst::CreatePointerCast(AI, Int8PtrTy, "lt.cast", I); + I->replaceUsesOfWith(I->getOperand(1), CastI); + } + // Follow any bitcasts. SmallVector Bitcasts; SmallVector BitcastLifetimeInfo; @@ -728,8 +768,7 @@ void CodeExtractor::severSplitPHINodesOfExits( NewBB = BasicBlock::Create(ExitBB->getContext(), ExitBB->getName() + ".split", ExitBB->getParent(), ExitBB); - SmallVector Preds(pred_begin(ExitBB), - pred_end(ExitBB)); + SmallVector Preds(predecessors(ExitBB)); for (BasicBlock *PredBB : Preds) if (Blocks.count(PredBB)) PredBB->getTerminator()->replaceUsesOfWith(ExitBB, NewBB); @@ -895,6 +934,7 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::WriteOnly: case Attribute::ZExt: case Attribute::ImmArg: + case Attribute::ByRef: case Attribute::EndAttrKinds: case Attribute::EmptyKey: case Attribute::TombstoneKey: @@ -902,9 +942,11 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, // Those attributes should be safe to propagate to the extracted function. case Attribute::AlwaysInline: case Attribute::Cold: + case Attribute::Hot: case Attribute::NoRecurse: case Attribute::InlineHint: case Attribute::MinSize: + case Attribute::NoCallback: case Attribute::NoDuplicate: case Attribute::NoFree: case Attribute::NoImplicitFloat: @@ -930,6 +972,8 @@ Function *CodeExtractor::constructFunction(const ValueSet &inputs, case Attribute::StrictFP: case Attribute::UWTable: case Attribute::NoCfCheck: + case Attribute::MustProgress: + case Attribute::NoProfile: break; } @@ -1434,7 +1478,7 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, // function arguments, as the parameters don't correspond to anything at the // source level. assert(OldSP->getUnit() && "Missing compile unit for subprogram"); - DIBuilder DIB(*OldFunc.getParent(), /*AllowUnresolvedNodes=*/false, + DIBuilder DIB(*OldFunc.getParent(), /*AllowUnresolved=*/false, OldSP->getUnit()); auto SPType = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); DISubprogram::DISPFlags SPFlags = DISubprogram::SPFlagDefinition | @@ -1505,7 +1549,7 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, // function. for (Instruction &I : instructions(NewFunc)) { if (const DebugLoc &DL = I.getDebugLoc()) - I.setDebugLoc(DebugLoc::get(DL.getLine(), DL.getCol(), NewSP)); + I.setDebugLoc(DILocation::get(Ctx, DL.getLine(), DL.getCol(), NewSP)); // Loop info metadata may contain line locations. Fix them up. auto updateLoopInfoLoc = [&Ctx, @@ -1516,7 +1560,7 @@ static void fixupDebugInfoPostExtraction(Function &OldFunc, Function &NewFunc, updateLoopMetadataDebugLocations(I, updateLoopInfoLoc); } if (!TheCall.getDebugLoc()) - TheCall.setDebugLoc(DebugLoc::get(0, 0, OldSP)); + TheCall.setDebugLoc(DILocation::get(Ctx, 0, 0, OldSP)); eraseDebugIntrinsicsWithNonLocalRefs(NewFunc); } @@ -1739,7 +1783,7 @@ bool CodeExtractor::verifyAssumptionCache(const Function &OldFunc, const Function &NewFunc, AssumptionCache *AC) { for (auto AssumeVH : AC->assumptions()) { - CallInst *I = dyn_cast_or_null(AssumeVH); + auto *I = dyn_cast_or_null(AssumeVH); if (!I) continue; @@ -1751,12 +1795,12 @@ bool CodeExtractor::verifyAssumptionCache(const Function &OldFunc, // that were previously in the old function, but that have now been moved // to the new function. for (auto AffectedValVH : AC->assumptionsFor(I->getOperand(0))) { - CallInst *AffectedCI = dyn_cast_or_null(AffectedValVH); + auto *AffectedCI = dyn_cast_or_null(AffectedValVH); if (!AffectedCI) continue; if (AffectedCI->getFunction() != &OldFunc) return true; - auto *AssumedInst = dyn_cast(AffectedCI->getOperand(0)); + auto *AssumedInst = cast(AffectedCI->getOperand(0)); if (AssumedInst->getFunction() != &OldFunc) return true; } diff --git a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp index 08047dc0f96e..ce982c7403aa 100644 --- a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp +++ b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp @@ -355,35 +355,32 @@ bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint, // Check if there exists instructions which may throw, may synchonize, or may // never return, from I to InsertPoint. if (!isSafeToSpeculativelyExecute(&I)) - if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), - [](Instruction *I) { - if (I->mayThrow()) - return true; - - const CallBase *CB = dyn_cast(I); - if (!CB) - return false; - if (!CB->hasFnAttr(Attribute::WillReturn)) - return true; - if (!CB->hasFnAttr(Attribute::NoSync)) - return true; - - return false; - })) { + if (llvm::any_of(InstsToCheck, [](Instruction *I) { + if (I->mayThrow()) + return true; + + const CallBase *CB = dyn_cast(I); + if (!CB) + return false; + if (!CB->hasFnAttr(Attribute::WillReturn)) + return true; + if (!CB->hasFnAttr(Attribute::NoSync)) + return true; + + return false; + })) { return reportInvalidCandidate(I, MayThrowException); } // Check if I has any output/flow/anti dependences with instructions from \p // StartInst to \p EndInst. - if (std::any_of(InstsToCheck.begin(), InstsToCheck.end(), - [&DI, &I](Instruction *CurInst) { - auto DepResult = DI->depends(&I, CurInst, true); - if (DepResult && - (DepResult->isOutput() || DepResult->isFlow() || - DepResult->isAnti())) - return true; - return false; - })) + if (llvm::any_of(InstsToCheck, [&DI, &I](Instruction *CurInst) { + auto DepResult = DI->depends(&I, CurInst, true); + if (DepResult && (DepResult->isOutput() || DepResult->isFlow() || + DepResult->isAnti())) + return true; + return false; + })) return reportInvalidCandidate(I, HasDependences); return true; diff --git a/llvm/lib/Transforms/Utils/Debugify.cpp b/llvm/lib/Transforms/Utils/Debugify.cpp index 8f98d81a3d79..3e4d53c10dc9 100644 --- a/llvm/lib/Transforms/Utils/Debugify.cpp +++ b/llvm/lib/Transforms/Utils/Debugify.cpp @@ -20,6 +20,7 @@ #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassInstrumentation.h" #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" @@ -198,6 +199,18 @@ bool llvm::applyDebugifyMetadata( return true; } +static bool applyDebugify(Function &F) { + Module &M = *F.getParent(); + auto FuncIt = F.getIterator(); + return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), + "FunctionDebugify: ", /*ApplyToMF=*/nullptr); +} + +static bool applyDebugify(Module &M) { + return applyDebugifyMetadata(M, M.functions(), + "ModuleDebugify: ", /*ApplyToMF=*/nullptr); +} + bool llvm::stripDebugifyMetadata(Module &M) { bool Changed = false; @@ -226,9 +239,7 @@ bool llvm::stripDebugifyMetadata(Module &M) { NamedMDNode *NMD = M.getModuleFlagsMetadata(); if (!NMD) return Changed; - SmallVector Flags; - for (MDNode *Flag : NMD->operands()) - Flags.push_back(Flag); + SmallVector Flags(NMD->operands()); NMD->clearOperands(); for (MDNode *Flag : Flags) { MDString *Key = dyn_cast_or_null(Flag->getOperand(1)); @@ -383,10 +394,7 @@ bool checkDebugifyMetadata(Module &M, /// ModulePass for attaching synthetic debug info to everything, used with the /// legacy module pass manager. struct DebugifyModulePass : public ModulePass { - bool runOnModule(Module &M) override { - return applyDebugifyMetadata(M, M.functions(), - "ModuleDebugify: ", /*ApplyToMF*/ nullptr); - } + bool runOnModule(Module &M) override { return applyDebugify(M); } DebugifyModulePass() : ModulePass(ID) {} @@ -400,12 +408,7 @@ struct DebugifyModulePass : public ModulePass { /// FunctionPass for attaching synthetic debug info to instructions within a /// single function, used with the legacy module pass manager. struct DebugifyFunctionPass : public FunctionPass { - bool runOnFunction(Function &F) override { - Module &M = *F.getParent(); - auto FuncIt = F.getIterator(); - return applyDebugifyMetadata(M, make_range(FuncIt, std::next(FuncIt)), - "FunctionDebugify: ", /*ApplyToMF*/ nullptr); - } + bool runOnFunction(Function &F) override { return applyDebugify(F); } DebugifyFunctionPass() : FunctionPass(ID) {} @@ -472,9 +475,32 @@ private: } // end anonymous namespace -ModulePass *createDebugifyModulePass() { return new DebugifyModulePass(); } +void llvm::exportDebugifyStats(StringRef Path, const DebugifyStatsMap &Map) { + std::error_code EC; + raw_fd_ostream OS{Path, EC}; + if (EC) { + errs() << "Could not open file: " << EC.message() << ", " << Path << '\n'; + return; + } + + OS << "Pass Name" << ',' << "# of missing debug values" << ',' + << "# of missing locations" << ',' << "Missing/Expected value ratio" << ',' + << "Missing/Expected location ratio" << '\n'; + for (const auto &Entry : Map) { + StringRef Pass = Entry.first; + DebugifyStatistics Stats = Entry.second; + + OS << Pass << ',' << Stats.NumDbgValuesMissing << ',' + << Stats.NumDbgLocsMissing << ',' << Stats.getMissingValueRatio() << ',' + << Stats.getEmptyLocationRatio() << '\n'; + } +} + +ModulePass *llvm::createDebugifyModulePass() { + return new DebugifyModulePass(); +} -FunctionPass *createDebugifyFunctionPass() { +FunctionPass *llvm::createDebugifyFunctionPass() { return new DebugifyFunctionPass(); } @@ -484,15 +510,15 @@ PreservedAnalyses NewPMDebugifyPass::run(Module &M, ModuleAnalysisManager &) { return PreservedAnalyses::all(); } -ModulePass *createCheckDebugifyModulePass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { +ModulePass *llvm::createCheckDebugifyModulePass(bool Strip, + StringRef NameOfWrappedPass, + DebugifyStatsMap *StatsMap) { return new CheckDebugifyModulePass(Strip, NameOfWrappedPass, StatsMap); } -FunctionPass *createCheckDebugifyFunctionPass(bool Strip, - StringRef NameOfWrappedPass, - DebugifyStatsMap *StatsMap) { +FunctionPass * +llvm::createCheckDebugifyFunctionPass(bool Strip, StringRef NameOfWrappedPass, + DebugifyStatsMap *StatsMap) { return new CheckDebugifyFunctionPass(Strip, NameOfWrappedPass, StatsMap); } @@ -503,6 +529,41 @@ PreservedAnalyses NewPMCheckDebugifyPass::run(Module &M, return PreservedAnalyses::all(); } +static bool isIgnoredPass(StringRef PassID) { + return isSpecialPass(PassID, {"PassManager", "PassAdaptor", + "AnalysisManagerProxy", "PrintFunctionPass", + "PrintModulePass", "BitcodeWriterPass", + "ThinLTOBitcodeWriterPass", "VerifierPass"}); +} + +void DebugifyEachInstrumentation::registerCallbacks( + PassInstrumentationCallbacks &PIC) { + PIC.registerBeforeNonSkippedPassCallback([](StringRef P, Any IR) { + if (isIgnoredPass(P)) + return; + if (any_isa(IR)) + applyDebugify(*const_cast(any_cast(IR))); + else if (any_isa(IR)) + applyDebugify(*const_cast(any_cast(IR))); + }); + PIC.registerAfterPassCallback([this](StringRef P, Any IR, + const PreservedAnalyses &PassPA) { + if (isIgnoredPass(P)) + return; + if (any_isa(IR)) { + auto &F = *const_cast(any_cast(IR)); + Module &M = *F.getParent(); + auto It = F.getIterator(); + checkDebugifyMetadata(M, make_range(It, std::next(It)), P, + "CheckFunctionDebugify", /*Strip=*/true, &StatsMap); + } else if (any_isa(IR)) { + auto &M = *const_cast(any_cast(IR)); + checkDebugifyMetadata(M, M.functions(), P, "CheckModuleDebugify", + /*Strip=*/true, &StatsMap); + } + }); +} + char DebugifyModulePass::ID = 0; static RegisterPass DM("debugify", "Attach debug info to everything"); diff --git a/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp b/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp index f84ff9e5aad1..26f8e21952cc 100644 --- a/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp +++ b/llvm/lib/Transforms/Utils/EntryExitInstrumenter.cpp @@ -83,7 +83,7 @@ static bool runOnFunction(Function &F, bool PostInlining) { if (!EntryFunc.empty()) { DebugLoc DL; if (auto SP = F.getSubprogram()) - DL = DebugLoc::get(SP->getScopeLine(), 0, SP); + DL = DILocation::get(SP->getContext(), SP->getScopeLine(), 0, SP); insertCall(F, EntryFunc, &*F.begin()->getFirstInsertionPt(), DL); Changed = true; @@ -97,19 +97,14 @@ static bool runOnFunction(Function &F, bool PostInlining) { continue; // If T is preceded by a musttail call, that's the real terminator. - Instruction *Prev = T->getPrevNode(); - if (BitCastInst *BCI = dyn_cast_or_null(Prev)) - Prev = BCI->getPrevNode(); - if (CallInst *CI = dyn_cast_or_null(Prev)) { - if (CI->isMustTailCall()) - T = CI; - } + if (CallInst *CI = BB.getTerminatingMustTailCall()) + T = CI; DebugLoc DL; if (DebugLoc TerminatorDL = T->getDebugLoc()) DL = TerminatorDL; else if (auto SP = F.getSubprogram()) - DL = DebugLoc::get(0, 0, SP); + DL = DILocation::get(SP->getContext(), 0, 0, SP); insertCall(F, ExitFunc, T, DL); Changed = true; diff --git a/llvm/lib/Transforms/Utils/EscapeEnumerator.cpp b/llvm/lib/Transforms/Utils/EscapeEnumerator.cpp index cae9d9ee6d70..accedd5b4ee0 100644 --- a/llvm/lib/Transforms/Utils/EscapeEnumerator.cpp +++ b/llvm/lib/Transforms/Utils/EscapeEnumerator.cpp @@ -41,6 +41,8 @@ IRBuilder<> *EscapeEnumerator::Next() { if (!isa(TI) && !isa(TI)) continue; + if (CallInst *CI = CurBB->getTerminatingMustTailCall()) + TI = CI; Builder.SetInsertPoint(TI); return &Builder; } @@ -54,11 +56,12 @@ IRBuilder<> *EscapeEnumerator::Next() { return nullptr; // Find all 'call' instructions that may throw. + // We cannot tranform calls with musttail tag. SmallVector Calls; for (BasicBlock &BB : F) for (Instruction &II : BB) if (CallInst *CI = dyn_cast(&II)) - if (!CI->doesNotThrow()) + if (!CI->doesNotThrow() && !CI->isMustTailCall()) Calls.push_back(CI); if (Calls.empty()) diff --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp index c5dfbf9d92d1..732b00635e29 100644 --- a/llvm/lib/Transforms/Utils/Evaluator.cpp +++ b/llvm/lib/Transforms/Utils/Evaluator.cpp @@ -183,11 +183,11 @@ evaluateBitcastFromPtr(Constant *Ptr, const DataLayout &DL, std::function Func) { Constant *Val; while (!(Val = Func(Ptr))) { - // If Ty is a struct, we can convert the pointer to the struct + // If Ty is a non-opaque struct, we can convert the pointer to the struct // into a pointer to its first member. // FIXME: This could be extended to support arrays as well. Type *Ty = cast(Ptr->getType())->getElementType(); - if (!isa(Ty)) + if (!isa(Ty) || cast(Ty)->isOpaque()) break; IntegerType *IdxTy = IntegerType::get(Ty->getContext(), 32); @@ -210,11 +210,7 @@ static Constant *getInitializer(Constant *C) { Constant *Evaluator::ComputeLoadResult(Constant *P) { // If this memory location has been recently stored, use the stored value: it // is the most up-to-date. - auto findMemLoc = [this](Constant *Ptr) { - DenseMap::const_iterator I = - MutatedMemory.find(Ptr); - return I != MutatedMemory.end() ? I->second : nullptr; - }; + auto findMemLoc = [this](Constant *Ptr) { return MutatedMemory.lookup(Ptr); }; if (Constant *Val = findMemLoc(P)) return Val; @@ -551,6 +547,10 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst, LLVM_DEBUG(dbgs() << "Skipping sideeffect intrinsic.\n"); ++CurInst; continue; + } else if (II->getIntrinsicID() == Intrinsic::pseudoprobe) { + LLVM_DEBUG(dbgs() << "Skipping pseudoprobe intrinsic.\n"); + ++CurInst; + continue; } LLVM_DEBUG(dbgs() << "Unknown intrinsic. Can not evaluate.\n"); diff --git a/llvm/lib/Transforms/Utils/FixIrreducible.cpp b/llvm/lib/Transforms/Utils/FixIrreducible.cpp index 460ba9e97fc6..44af95eef67d 100644 --- a/llvm/lib/Transforms/Utils/FixIrreducible.cpp +++ b/llvm/lib/Transforms/Utils/FixIrreducible.cpp @@ -66,6 +66,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/FixIrreducible.h" #include "llvm/ADT/SCCIterator.h" #include "llvm/Analysis/LoopIterator.h" #include "llvm/InitializePasses.h" @@ -104,7 +105,7 @@ FunctionPass *llvm::createFixIrreduciblePass() { return new FixIrreducible(); } INITIALIZE_PASS_BEGIN(FixIrreducible, "fix-irreducible", "Convert irreducible control-flow into natural loops", false /* Only looks at CFG */, false /* Analysis Pass */) -INITIALIZE_PASS_DEPENDENCY(LowerSwitch) +INITIALIZE_PASS_DEPENDENCY(LowerSwitchLegacyPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_END(FixIrreducible, "fix-irreducible", @@ -304,11 +305,9 @@ static bool makeReducible(LoopInfo &LI, DominatorTree &DT, Graph &&G) { return Changed; } -bool FixIrreducible::runOnFunction(Function &F) { +static bool FixIrreducibleImpl(Function &F, LoopInfo &LI, DominatorTree &DT) { LLVM_DEBUG(dbgs() << "===== Fix irreducible control-flow in function: " << F.getName() << "\n"); - auto &LI = getAnalysis().getLoopInfo(); - auto &DT = getAnalysis().getDomTree(); bool Changed = false; SmallVector WorkList; @@ -318,13 +317,10 @@ bool FixIrreducible::runOnFunction(Function &F) { // Any SCCs reduced are now already in the list of top-level loops, so simply // add them all to the worklist. - for (auto L : LI) { - WorkList.push_back(L); - } + append_range(WorkList, LI); while (!WorkList.empty()) { - auto L = WorkList.back(); - WorkList.pop_back(); + auto L = WorkList.pop_back_val(); LLVM_DEBUG(dbgs() << "visiting loop with header " << L->getHeader()->getName() << "\n"); Changed |= makeReducible(LI, DT, *L); @@ -335,3 +331,21 @@ bool FixIrreducible::runOnFunction(Function &F) { return Changed; } + +bool FixIrreducible::runOnFunction(Function &F) { + auto &LI = getAnalysis().getLoopInfo(); + auto &DT = getAnalysis().getDomTree(); + return FixIrreducibleImpl(F, LI, DT); +} + +PreservedAnalyses FixIrreduciblePass::run(Function &F, + FunctionAnalysisManager &AM) { + auto &LI = AM.getResult(F); + auto &DT = AM.getResult(F); + if (!FixIrreducibleImpl(F, LI, DT)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + return PA; +} diff --git a/llvm/lib/Transforms/Utils/FunctionComparator.cpp b/llvm/lib/Transforms/Utils/FunctionComparator.cpp index 101cb232d8ae..2696557a719f 100644 --- a/llvm/lib/Transforms/Utils/FunctionComparator.cpp +++ b/llvm/lib/Transforms/Utils/FunctionComparator.cpp @@ -124,12 +124,17 @@ int FunctionComparator::cmpAttrs(const AttributeList L, Type *TyL = LA.getValueAsType(); Type *TyR = RA.getValueAsType(); - if (TyL && TyR) - return cmpTypes(TyL, TyR); + if (TyL && TyR) { + if (int Res = cmpTypes(TyL, TyR)) + return Res; + continue; + } // Two pointers, at least one null, so the comparison result is // independent of the value of a real pointer. - return cmpNumbers((uint64_t)TyL, (uint64_t)TyR); + if (int Res = cmpNumbers((uint64_t)TyL, (uint64_t)TyR)) + return Res; + continue; } if (LA < RA) return -1; @@ -286,6 +291,7 @@ int FunctionComparator::cmpConstants(const Constant *L, switch (L->getValueID()) { case Value::UndefValueVal: + case Value::PoisonValueVal: case Value::ConstantTokenNoneVal: return TypesRes; case Value::ConstantIntVal: { @@ -488,12 +494,13 @@ int FunctionComparator::cmpTypes(Type *TyL, Type *TyR) const { case Type::ScalableVectorTyID: { auto *STyL = cast(TyL); auto *STyR = cast(TyR); - if (STyL->getElementCount().Scalable != STyR->getElementCount().Scalable) - return cmpNumbers(STyL->getElementCount().Scalable, - STyR->getElementCount().Scalable); - if (STyL->getElementCount().Min != STyR->getElementCount().Min) - return cmpNumbers(STyL->getElementCount().Min, - STyR->getElementCount().Min); + if (STyL->getElementCount().isScalable() != + STyR->getElementCount().isScalable()) + return cmpNumbers(STyL->getElementCount().isScalable(), + STyR->getElementCount().isScalable()); + if (STyL->getElementCount() != STyR->getElementCount()) + return cmpNumbers(STyL->getElementCount().getKnownMinValue(), + STyR->getElementCount().getKnownMinValue()); return cmpTypes(STyL->getElementType(), STyR->getElementType()); } } diff --git a/llvm/lib/Transforms/Utils/GlobalStatus.cpp b/llvm/lib/Transforms/Utils/GlobalStatus.cpp index fe58f0e0fe40..f782396be7b6 100644 --- a/llvm/lib/Transforms/Utils/GlobalStatus.cpp +++ b/llvm/lib/Transforms/Utils/GlobalStatus.cpp @@ -136,7 +136,8 @@ static bool analyzeGlobalAux(const Value *V, GlobalStatus &GS, GS.StoredType = GlobalStatus::Stored; } } - } else if (isa(I) || isa(I)) { + } else if (isa(I) || isa(I) || + isa(I)) { // Skip over bitcasts and GEPs; we don't care about the type or offset // of the pointer. if (analyzeGlobalAux(I, GS, VisitedUsers)) diff --git a/llvm/lib/Transforms/Utils/GuardUtils.cpp b/llvm/lib/Transforms/Utils/GuardUtils.cpp index 4cfc9358499a..4dbcbf80d3da 100644 --- a/llvm/lib/Transforms/Utils/GuardUtils.cpp +++ b/llvm/lib/Transforms/Utils/GuardUtils.cpp @@ -30,7 +30,7 @@ static cl::opt PredicatePassBranchWeight( void llvm::makeGuardControlFlowExplicit(Function *DeoptIntrinsic, CallInst *Guard, bool UseWC) { OperandBundleDef DeoptOB(*Guard->getOperandBundle(LLVMContext::OB_deopt)); - SmallVector Args(std::next(Guard->arg_begin()), Guard->arg_end()); + SmallVector Args(drop_begin(Guard->args())); auto *CheckBB = Guard->getParent(); auto *DeoptBlockTerm = diff --git a/llvm/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp b/llvm/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp deleted file mode 100644 index ea93f99d69e3..000000000000 --- a/llvm/lib/Transforms/Utils/ImportedFunctionsInliningStatistics.cpp +++ /dev/null @@ -1,202 +0,0 @@ -//===-- ImportedFunctionsInliningStats.cpp ----------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// Generating inliner statistics for imported functions, mostly useful for -// ThinLTO. -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Utils/ImportedFunctionsInliningStatistics.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/Module.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -using namespace llvm; - -ImportedFunctionsInliningStatistics::InlineGraphNode & -ImportedFunctionsInliningStatistics::createInlineGraphNode(const Function &F) { - - auto &ValueLookup = NodesMap[F.getName()]; - if (!ValueLookup) { - ValueLookup = std::make_unique(); - ValueLookup->Imported = F.hasMetadata("thinlto_src_module"); - } - return *ValueLookup; -} - -void ImportedFunctionsInliningStatistics::recordInline(const Function &Caller, - const Function &Callee) { - - InlineGraphNode &CallerNode = createInlineGraphNode(Caller); - InlineGraphNode &CalleeNode = createInlineGraphNode(Callee); - CalleeNode.NumberOfInlines++; - - if (!CallerNode.Imported && !CalleeNode.Imported) { - // Direct inline from not imported callee to not imported caller, so we - // don't have to add this to graph. It might be very helpful if you wanna - // get the inliner statistics in compile step where there are no imported - // functions. In this case the graph would be empty. - CalleeNode.NumberOfRealInlines++; - return; - } - - CallerNode.InlinedCallees.push_back(&CalleeNode); - if (!CallerNode.Imported) { - // We could avoid second lookup, but it would make the code ultra ugly. - auto It = NodesMap.find(Caller.getName()); - assert(It != NodesMap.end() && "The node should be already there."); - // Save Caller as a starting node for traversal. The string has to be one - // from map because Caller can disappear (and function name with it). - NonImportedCallers.push_back(It->first()); - } -} - -void ImportedFunctionsInliningStatistics::setModuleInfo(const Module &M) { - ModuleName = M.getName(); - for (const auto &F : M.functions()) { - if (F.isDeclaration()) - continue; - AllFunctions++; - ImportedFunctions += int(F.hasMetadata("thinlto_src_module")); - } -} -static std::string getStatString(const char *Msg, int32_t Fraction, int32_t All, - const char *PercentageOfMsg, - bool LineEnd = true) { - double Result = 0; - if (All != 0) - Result = 100 * static_cast(Fraction) / All; - - std::stringstream Str; - Str << std::setprecision(4) << Msg << ": " << Fraction << " [" << Result - << "% of " << PercentageOfMsg << "]"; - if (LineEnd) - Str << "\n"; - return Str.str(); -} - -void ImportedFunctionsInliningStatistics::dump(const bool Verbose) { - calculateRealInlines(); - NonImportedCallers.clear(); - - int32_t InlinedImportedFunctionsCount = 0; - int32_t InlinedNotImportedFunctionsCount = 0; - - int32_t InlinedImportedFunctionsToImportingModuleCount = 0; - int32_t InlinedNotImportedFunctionsToImportingModuleCount = 0; - - const auto SortedNodes = getSortedNodes(); - std::string Out; - Out.reserve(5000); - raw_string_ostream Ostream(Out); - - Ostream << "------- Dumping inliner stats for [" << ModuleName - << "] -------\n"; - - if (Verbose) - Ostream << "-- List of inlined functions:\n"; - - for (const auto &Node : SortedNodes) { - assert(Node->second->NumberOfInlines >= Node->second->NumberOfRealInlines); - if (Node->second->NumberOfInlines == 0) - continue; - - if (Node->second->Imported) { - InlinedImportedFunctionsCount++; - InlinedImportedFunctionsToImportingModuleCount += - int(Node->second->NumberOfRealInlines > 0); - } else { - InlinedNotImportedFunctionsCount++; - InlinedNotImportedFunctionsToImportingModuleCount += - int(Node->second->NumberOfRealInlines > 0); - } - - if (Verbose) - Ostream << "Inlined " - << (Node->second->Imported ? "imported " : "not imported ") - << "function [" << Node->first() << "]" - << ": #inlines = " << Node->second->NumberOfInlines - << ", #inlines_to_importing_module = " - << Node->second->NumberOfRealInlines << "\n"; - } - - auto InlinedFunctionsCount = - InlinedImportedFunctionsCount + InlinedNotImportedFunctionsCount; - auto NotImportedFuncCount = AllFunctions - ImportedFunctions; - auto ImportedNotInlinedIntoModule = - ImportedFunctions - InlinedImportedFunctionsToImportingModuleCount; - - Ostream << "-- Summary:\n" - << "All functions: " << AllFunctions - << ", imported functions: " << ImportedFunctions << "\n" - << getStatString("inlined functions", InlinedFunctionsCount, - AllFunctions, "all functions") - << getStatString("imported functions inlined anywhere", - InlinedImportedFunctionsCount, ImportedFunctions, - "imported functions") - << getStatString("imported functions inlined into importing module", - InlinedImportedFunctionsToImportingModuleCount, - ImportedFunctions, "imported functions", - /*LineEnd=*/false) - << getStatString(", remaining", ImportedNotInlinedIntoModule, - ImportedFunctions, "imported functions") - << getStatString("non-imported functions inlined anywhere", - InlinedNotImportedFunctionsCount, - NotImportedFuncCount, "non-imported functions") - << getStatString( - "non-imported functions inlined into importing module", - InlinedNotImportedFunctionsToImportingModuleCount, - NotImportedFuncCount, "non-imported functions"); - Ostream.flush(); - dbgs() << Out; -} - -void ImportedFunctionsInliningStatistics::calculateRealInlines() { - // Removing duplicated Callers. - llvm::sort(NonImportedCallers); - NonImportedCallers.erase( - std::unique(NonImportedCallers.begin(), NonImportedCallers.end()), - NonImportedCallers.end()); - - for (const auto &Name : NonImportedCallers) { - auto &Node = *NodesMap[Name]; - if (!Node.Visited) - dfs(Node); - } -} - -void ImportedFunctionsInliningStatistics::dfs(InlineGraphNode &GraphNode) { - assert(!GraphNode.Visited); - GraphNode.Visited = true; - for (auto *const InlinedFunctionNode : GraphNode.InlinedCallees) { - InlinedFunctionNode->NumberOfRealInlines++; - if (!InlinedFunctionNode->Visited) - dfs(*InlinedFunctionNode); - } -} - -ImportedFunctionsInliningStatistics::SortedNodesTy -ImportedFunctionsInliningStatistics::getSortedNodes() { - SortedNodesTy SortedNodes; - SortedNodes.reserve(NodesMap.size()); - for (const NodesMapTy::value_type& Node : NodesMap) - SortedNodes.push_back(&Node); - - llvm::sort(SortedNodes, [&](const SortedNodesTy::value_type &Lhs, - const SortedNodesTy::value_type &Rhs) { - if (Lhs->second->NumberOfInlines != Rhs->second->NumberOfInlines) - return Lhs->second->NumberOfInlines > Rhs->second->NumberOfInlines; - if (Lhs->second->NumberOfRealInlines != Rhs->second->NumberOfRealInlines) - return Lhs->second->NumberOfRealInlines > - Rhs->second->NumberOfRealInlines; - return Lhs->first() < Rhs->first(); - }); - return SortedNodes; -} diff --git a/llvm/lib/Transforms/Utils/InjectTLIMappings.cpp b/llvm/lib/Transforms/Utils/InjectTLIMappings.cpp index 9d8f59d62d6d..a2b72e4e7f03 100644 --- a/llvm/lib/Transforms/Utils/InjectTLIMappings.cpp +++ b/llvm/lib/Transforms/Utils/InjectTLIMappings.cpp @@ -16,6 +16,7 @@ #include "llvm/Analysis/DemandedBits.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/IntrinsicInst.h" @@ -77,7 +78,8 @@ static void addMappingsFromTLI(const TargetLibraryInfo &TLI, CallInst &CI) { if (CI.isNoBuiltin() || !CI.getCalledFunction()) return; - const std::string ScalarName = std::string(CI.getCalledFunction()->getName()); + StringRef ScalarName = CI.getCalledFunction()->getName(); + // Nothing to be done if the TLI thinks the function is not // vectorizable. if (!TLI.isFunctionVectorizable(ScalarName)) diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index b0b7ca484798..0ac8fa537f4e 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -79,6 +79,12 @@ EnableNoAliasConversion("enable-noalias-to-md-conversion", cl::init(true), cl::Hidden, cl::desc("Convert noalias attributes to metadata during inlining.")); +static cl::opt + UseNoAliasIntrinsic("use-noalias-intrinsic-during-inlining", cl::Hidden, + cl::ZeroOrMore, cl::init(true), + cl::desc("Use the llvm.experimental.noalias.scope.decl " + "intrinsic during inlining.")); + // Disabled by default, because the added alignment assumptions may increase // compile-time and block optimizations. This option is not suitable for use // with frontends that emit comprehensive parameter alignment annotations. @@ -771,146 +777,158 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock, UnwindDest->removePredecessor(InvokeBB); } -/// When inlining a call site that has !llvm.mem.parallel_loop_access or -/// llvm.access.group metadata, that metadata should be propagated to all -/// memory-accessing cloned instructions. -static void PropagateParallelLoopAccessMetadata(CallBase &CB, - ValueToValueMapTy &VMap) { - MDNode *M = CB.getMetadata(LLVMContext::MD_mem_parallel_loop_access); - MDNode *CallAccessGroup = CB.getMetadata(LLVMContext::MD_access_group); - if (!M && !CallAccessGroup) +/// When inlining a call site that has !llvm.mem.parallel_loop_access, +/// !llvm.access.group, !alias.scope or !noalias metadata, that metadata should +/// be propagated to all memory-accessing cloned instructions. +static void PropagateCallSiteMetadata(CallBase &CB, ValueToValueMapTy &VMap) { + MDNode *MemParallelLoopAccess = + CB.getMetadata(LLVMContext::MD_mem_parallel_loop_access); + MDNode *AccessGroup = CB.getMetadata(LLVMContext::MD_access_group); + MDNode *AliasScope = CB.getMetadata(LLVMContext::MD_alias_scope); + MDNode *NoAlias = CB.getMetadata(LLVMContext::MD_noalias); + if (!MemParallelLoopAccess && !AccessGroup && !AliasScope && !NoAlias) return; for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end(); VMI != VMIE; ++VMI) { - if (!VMI->second) + // Check that key is an instruction, to skip the Argument mapping, which + // points to an instruction in the original function, not the inlined one. + if (!VMI->second || !isa(VMI->first)) continue; Instruction *NI = dyn_cast(VMI->second); if (!NI) continue; - if (M) { - if (MDNode *PM = - NI->getMetadata(LLVMContext::MD_mem_parallel_loop_access)) { - M = MDNode::concatenate(PM, M); - NI->setMetadata(LLVMContext::MD_mem_parallel_loop_access, M); - } else if (NI->mayReadOrWriteMemory()) { - NI->setMetadata(LLVMContext::MD_mem_parallel_loop_access, M); - } - } + // This metadata is only relevant for instructions that access memory. + if (!NI->mayReadOrWriteMemory()) + continue; - if (NI->mayReadOrWriteMemory()) { - MDNode *UnitedAccGroups = uniteAccessGroups( - NI->getMetadata(LLVMContext::MD_access_group), CallAccessGroup); - NI->setMetadata(LLVMContext::MD_access_group, UnitedAccGroups); + if (MemParallelLoopAccess) { + // TODO: This probably should not overwrite MemParalleLoopAccess. + MemParallelLoopAccess = MDNode::concatenate( + NI->getMetadata(LLVMContext::MD_mem_parallel_loop_access), + MemParallelLoopAccess); + NI->setMetadata(LLVMContext::MD_mem_parallel_loop_access, + MemParallelLoopAccess); } + + if (AccessGroup) + NI->setMetadata(LLVMContext::MD_access_group, uniteAccessGroups( + NI->getMetadata(LLVMContext::MD_access_group), AccessGroup)); + + if (AliasScope) + NI->setMetadata(LLVMContext::MD_alias_scope, MDNode::concatenate( + NI->getMetadata(LLVMContext::MD_alias_scope), AliasScope)); + + if (NoAlias) + NI->setMetadata(LLVMContext::MD_noalias, MDNode::concatenate( + NI->getMetadata(LLVMContext::MD_noalias), NoAlias)); } } -/// When inlining a function that contains noalias scope metadata, -/// this metadata needs to be cloned so that the inlined blocks -/// have different "unique scopes" at every call site. Were this not done, then -/// aliasing scopes from a function inlined into a caller multiple times could -/// not be differentiated (and this would lead to miscompiles because the -/// non-aliasing property communicated by the metadata could have -/// call-site-specific control dependencies). -static void CloneAliasScopeMetadata(CallBase &CB, ValueToValueMapTy &VMap) { - const Function *CalledFunc = CB.getCalledFunction(); +/// Utility for cloning !noalias and !alias.scope metadata. When a code region +/// using scoped alias metadata is inlined, the aliasing relationships may not +/// hold between the two version. It is necessary to create a deep clone of the +/// metadata, putting the two versions in separate scope domains. +class ScopedAliasMetadataDeepCloner { + using MetadataMap = DenseMap; SetVector MD; - - // Note: We could only clone the metadata if it is already used in the - // caller. I'm omitting that check here because it might confuse - // inter-procedural alias analysis passes. We can revisit this if it becomes - // an efficiency or overhead problem. - - for (const BasicBlock &I : *CalledFunc) - for (const Instruction &J : I) { - if (const MDNode *M = J.getMetadata(LLVMContext::MD_alias_scope)) + MetadataMap MDMap; + void addRecursiveMetadataUses(); + +public: + ScopedAliasMetadataDeepCloner(const Function *F); + + /// Create a new clone of the scoped alias metadata, which will be used by + /// subsequent remap() calls. + void clone(); + + /// Remap instructions in the given VMap from the original to the cloned + /// metadata. + void remap(ValueToValueMapTy &VMap); +}; + +ScopedAliasMetadataDeepCloner::ScopedAliasMetadataDeepCloner( + const Function *F) { + for (const BasicBlock &BB : *F) { + for (const Instruction &I : BB) { + if (const MDNode *M = I.getMetadata(LLVMContext::MD_alias_scope)) MD.insert(M); - if (const MDNode *M = J.getMetadata(LLVMContext::MD_noalias)) + if (const MDNode *M = I.getMetadata(LLVMContext::MD_noalias)) MD.insert(M); - } - if (MD.empty()) - return; + // We also need to clone the metadata in noalias intrinsics. + if (const auto *Decl = dyn_cast(&I)) + MD.insert(Decl->getScopeList()); + } + } + addRecursiveMetadataUses(); +} - // Walk the existing metadata, adding the complete (perhaps cyclic) chain to - // the set. +void ScopedAliasMetadataDeepCloner::addRecursiveMetadataUses() { SmallVector Queue(MD.begin(), MD.end()); while (!Queue.empty()) { const MDNode *M = cast(Queue.pop_back_val()); - for (unsigned i = 0, ie = M->getNumOperands(); i != ie; ++i) - if (const MDNode *M1 = dyn_cast(M->getOperand(i))) - if (MD.insert(M1)) - Queue.push_back(M1); + for (const Metadata *Op : M->operands()) + if (const MDNode *OpMD = dyn_cast(Op)) + if (MD.insert(OpMD)) + Queue.push_back(OpMD); } +} + +void ScopedAliasMetadataDeepCloner::clone() { + assert(MDMap.empty() && "clone() already called ?"); - // Now we have a complete set of all metadata in the chains used to specify - // the noalias scopes and the lists of those scopes. SmallVector DummyNodes; - DenseMap MDMap; for (const MDNode *I : MD) { - DummyNodes.push_back(MDTuple::getTemporary(CalledFunc->getContext(), None)); + DummyNodes.push_back(MDTuple::getTemporary(I->getContext(), None)); MDMap[I].reset(DummyNodes.back().get()); } // Create new metadata nodes to replace the dummy nodes, replacing old // metadata references with either a dummy node or an already-created new // node. + SmallVector NewOps; for (const MDNode *I : MD) { - SmallVector NewOps; - for (unsigned i = 0, ie = I->getNumOperands(); i != ie; ++i) { - const Metadata *V = I->getOperand(i); - if (const MDNode *M = dyn_cast(V)) + for (const Metadata *Op : I->operands()) { + if (const MDNode *M = dyn_cast(Op)) NewOps.push_back(MDMap[M]); else - NewOps.push_back(const_cast(V)); + NewOps.push_back(const_cast(Op)); } - MDNode *NewM = MDNode::get(CalledFunc->getContext(), NewOps); + MDNode *NewM = MDNode::get(I->getContext(), NewOps); MDTuple *TempM = cast(MDMap[I]); assert(TempM->isTemporary() && "Expected temporary node"); TempM->replaceAllUsesWith(NewM); + NewOps.clear(); } +} - // Now replace the metadata in the new inlined instructions with the - // repacements from the map. - for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end(); - VMI != VMIE; ++VMI) { - if (!VMI->second) +void ScopedAliasMetadataDeepCloner::remap(ValueToValueMapTy &VMap) { + if (MDMap.empty()) + return; // Nothing to do. + + for (auto Entry : VMap) { + // Check that key is an instruction, to skip the Argument mapping, which + // points to an instruction in the original function, not the inlined one. + if (!Entry->second || !isa(Entry->first)) continue; - Instruction *NI = dyn_cast(VMI->second); - if (!NI) + Instruction *I = dyn_cast(Entry->second); + if (!I) continue; - if (MDNode *M = NI->getMetadata(LLVMContext::MD_alias_scope)) { - MDNode *NewMD = MDMap[M]; - // If the call site also had alias scope metadata (a list of scopes to - // which instructions inside it might belong), propagate those scopes to - // the inlined instructions. - if (MDNode *CSM = CB.getMetadata(LLVMContext::MD_alias_scope)) - NewMD = MDNode::concatenate(NewMD, CSM); - NI->setMetadata(LLVMContext::MD_alias_scope, NewMD); - } else if (NI->mayReadOrWriteMemory()) { - if (MDNode *M = CB.getMetadata(LLVMContext::MD_alias_scope)) - NI->setMetadata(LLVMContext::MD_alias_scope, M); - } + if (MDNode *M = I->getMetadata(LLVMContext::MD_alias_scope)) + I->setMetadata(LLVMContext::MD_alias_scope, MDMap[M]); - if (MDNode *M = NI->getMetadata(LLVMContext::MD_noalias)) { - MDNode *NewMD = MDMap[M]; - // If the call site also had noalias metadata (a list of scopes with - // which instructions inside it don't alias), propagate those scopes to - // the inlined instructions. - if (MDNode *CSM = CB.getMetadata(LLVMContext::MD_noalias)) - NewMD = MDNode::concatenate(NewMD, CSM); - NI->setMetadata(LLVMContext::MD_noalias, NewMD); - } else if (NI->mayReadOrWriteMemory()) { - if (MDNode *M = CB.getMetadata(LLVMContext::MD_noalias)) - NI->setMetadata(LLVMContext::MD_noalias, M); - } + if (MDNode *M = I->getMetadata(LLVMContext::MD_noalias)) + I->setMetadata(LLVMContext::MD_noalias, MDMap[M]); + + if (auto *Decl = dyn_cast(I)) + Decl->setScopeList(MDMap[Decl->getScopeList()]); } } @@ -967,6 +985,17 @@ static void AddAliasScopeMetadata(CallBase &CB, ValueToValueMapTy &VMap, // property of the callee, but also all control dependencies in the caller. MDNode *NewScope = MDB.createAnonymousAliasScope(NewDomain, Name); NewScopes.insert(std::make_pair(A, NewScope)); + + if (UseNoAliasIntrinsic) { + // Introduce a llvm.experimental.noalias.scope.decl for the noalias + // argument. + MDNode *AScopeList = MDNode::get(CalledFunc->getContext(), NewScope); + auto *NoAliasDecl = + IRBuilder<>(&CB).CreateNoAliasScopeDeclaration(AScopeList); + // Ignore the result for now. The result will be used when the + // llvm.noalias intrinsic is introduced. + (void)NoAliasDecl; + } } // Iterate over all new instructions in the map; for all memory-access @@ -1037,7 +1066,7 @@ static void AddAliasScopeMetadata(CallBase &CB, ValueToValueMapTy &VMap, SmallSetVector NAPtrArgs; for (const Value *V : PtrArgs) { SmallVector Objects; - GetUnderlyingObjects(V, Objects, DL, /* LI = */ nullptr); + getUnderlyingObjects(V, Objects, /* LI = */ nullptr); for (const Value *O : Objects) ObjSet.insert(O); @@ -1245,7 +1274,7 @@ static void AddAlignmentAssumptions(CallBase &CB, InlineFunctionInfo &IFI) { Function *CalledFunc = CB.getCalledFunction(); for (Argument &Arg : CalledFunc->args()) { unsigned Align = Arg.getType()->isPointerTy() ? Arg.getParamAlignment() : 0; - if (Align && !Arg.hasPassPointeeByValueAttr() && !Arg.hasNUses(0)) { + if (Align && !Arg.hasPassPointeeByValueCopyAttr() && !Arg.hasNUses(0)) { if (!DTCalculated) { DT.recalculate(*CB.getCaller()); DTCalculated = true; @@ -1448,8 +1477,8 @@ static DebugLoc inlineDebugLoc(DebugLoc OrigDL, DILocation *InlinedAt, LLVMContext &Ctx, DenseMap &IANodes) { auto IA = DebugLoc::appendInlinedAt(OrigDL, InlinedAt, Ctx, IANodes); - return DebugLoc::get(OrigDL.getLine(), OrigDL.getCol(), OrigDL.getScope(), - IA); + return DILocation::get(Ctx, OrigDL.getLine(), OrigDL.getCol(), + OrigDL.getScope(), IA); } /// Update inlined instructions' line numbers to @@ -1573,8 +1602,7 @@ static void updateCallProfile(Function *Callee, const ValueToValueMapTy &VMap, return; auto CallSiteCount = PSI ? PSI->getProfileCount(TheCall, CallerBFI) : None; int64_t CallCount = - std::min(CallSiteCount.hasValue() ? CallSiteCount.getValue() : 0, - CalleeEntryCount.getCount()); + std::min(CallSiteCount.getValueOr(0), CalleeEntryCount.getCount()); updateProfileCallee(Callee, -CallCount, &VMap); } @@ -1765,6 +1793,14 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // Keep a list of pair (dst, src) to emit byval initializations. SmallVector, 4> ByValInit; + // When inlining a function that contains noalias scope metadata, + // this metadata needs to be cloned so that the inlined blocks + // have different "unique scopes" at every call site. + // Track the metadata that must be cloned. Do this before other changes to + // the function, so that we do not get in trouble when inlining caller == + // callee. + ScopedAliasMetadataDeepCloner SAMetadataCloner(CB.getCalledFunction()); + auto &DL = Caller->getParent()->getDataLayout(); // Calculate the vector of arguments to pass into the function cloner, which @@ -1855,11 +1891,8 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, MergedDeoptArgs.reserve(ParentDeopt->Inputs.size() + ChildOB.Inputs.size()); - MergedDeoptArgs.insert(MergedDeoptArgs.end(), - ParentDeopt->Inputs.begin(), - ParentDeopt->Inputs.end()); - MergedDeoptArgs.insert(MergedDeoptArgs.end(), ChildOB.Inputs.begin(), - ChildOB.Inputs.end()); + llvm::append_range(MergedDeoptArgs, ParentDeopt->Inputs); + llvm::append_range(MergedDeoptArgs, ChildOB.Inputs); OpDefs.emplace_back("deopt", std::move(MergedDeoptArgs)); } @@ -1885,8 +1918,9 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, fixupLineNumbers(Caller, FirstNewBlock, &CB, CalledFunc->getSubprogram() != nullptr); - // Clone existing noalias metadata if necessary. - CloneAliasScopeMetadata(CB, VMap); + // Now clone the inlined noalias scope metadata. + SAMetadataCloner.clone(); + SAMetadataCloner.remap(VMap); // Add noalias metadata if necessary. AddAliasScopeMetadata(CB, VMap, DL, CalleeAAR); @@ -1895,8 +1929,8 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // function which feed into its return value. AddReturnAttributes(CB, VMap); - // Propagate llvm.mem.parallel_loop_access if necessary. - PropagateParallelLoopAccessMetadata(CB, VMap); + // Propagate metadata on the callsite if necessary. + PropagateCallSiteMetadata(CB, VMap); // Register any cloned assumptions. if (IFI.GetAssumptionCache) @@ -2061,7 +2095,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, dyn_cast(AI->getArraySize())) { auto &DL = Caller->getParent()->getDataLayout(); Type *AllocaType = AI->getAllocatedType(); - uint64_t AllocaTypeSize = DL.getTypeAllocSize(AllocaType); + TypeSize AllocaTypeSize = DL.getTypeAllocSize(AllocaType); uint64_t AllocaArraySize = AIArraySize->getLimitedValue(); // Don't add markers for zero-sized allocas. @@ -2070,9 +2104,10 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // Check that array size doesn't saturate uint64_t and doesn't // overflow when it's multiplied by type size. - if (AllocaArraySize != std::numeric_limits::max() && + if (!AllocaTypeSize.isScalable() && + AllocaArraySize != std::numeric_limits::max() && std::numeric_limits::max() / AllocaArraySize >= - AllocaTypeSize) { + AllocaTypeSize.getFixedSize()) { AllocaSize = ConstantInt::get(Type::getInt64Ty(AI->getContext()), AllocaArraySize * AllocaTypeSize); } @@ -2198,10 +2233,9 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // match the callee's return type, we also need to change the return type of // the intrinsic. if (Caller->getReturnType() == CB.getType()) { - auto NewEnd = llvm::remove_if(Returns, [](ReturnInst *RI) { + llvm::erase_if(Returns, [](ReturnInst *RI) { return RI->getParent()->getTerminatingDeoptimizeCall() != nullptr; }); - Returns.erase(NewEnd, Returns.end()); } else { SmallVector NormalReturns; Function *NewDeoptIntrinsic = Intrinsic::getDeclaration( @@ -2225,8 +2259,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, auto *CurBB = RI->getParent(); RI->eraseFromParent(); - SmallVector CallArgs(DeoptCall->arg_begin(), - DeoptCall->arg_end()); + SmallVector CallArgs(DeoptCall->args()); SmallVector OpBundles; DeoptCall->getOperandBundlesAsDefs(OpBundles); @@ -2463,7 +2496,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // If we inlined any musttail calls and the original return is now // unreachable, delete it. It can only contain a bitcast and ret. - if (InlinedMustTailCalls && pred_begin(AfterCallBB) == pred_end(AfterCallBB)) + if (InlinedMustTailCalls && pred_empty(AfterCallBB)) AfterCallBB->eraseFromParent(); // We should always be able to fold the entry block of the function into the diff --git a/llvm/lib/Transforms/Utils/InstructionNamer.cpp b/llvm/lib/Transforms/Utils/InstructionNamer.cpp index 8e339fe46d45..f3499c9c8aed 100644 --- a/llvm/lib/Transforms/Utils/InstructionNamer.cpp +++ b/llvm/lib/Transforms/Utils/InstructionNamer.cpp @@ -13,43 +13,52 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/InstructionNamer.h" #include "llvm/IR/Function.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Transforms/Utils.h" + using namespace llvm; namespace { - struct InstNamer : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - InstNamer() : FunctionPass(ID) { - initializeInstNamerPass(*PassRegistry::getPassRegistry()); - } +void nameInstructions(Function &F) { + for (auto &Arg : F.args()) { + if (!Arg.hasName()) + Arg.setName("arg"); + } - void getAnalysisUsage(AnalysisUsage &Info) const override { - Info.setPreservesAll(); + for (BasicBlock &BB : F) { + if (!BB.hasName()) + BB.setName("bb"); + + for (Instruction &I : BB) { + if (!I.hasName() && !I.getType()->isVoidTy()) + I.setName("i"); } + } +} - bool runOnFunction(Function &F) override { - for (auto &Arg : F.args()) - if (!Arg.hasName()) - Arg.setName("arg"); +struct InstNamer : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + InstNamer() : FunctionPass(ID) { + initializeInstNamerPass(*PassRegistry::getPassRegistry()); + } - for (BasicBlock &BB : F) { - if (!BB.hasName()) - BB.setName("bb"); + void getAnalysisUsage(AnalysisUsage &Info) const override { + Info.setPreservesAll(); + } - for (Instruction &I : BB) - if (!I.hasName() && !I.getType()->isVoidTy()) - I.setName("i"); - } - return true; - } - }; + bool runOnFunction(Function &F) override { + nameInstructions(F); + return true; + } +}; char InstNamer::ID = 0; -} + } // namespace INITIALIZE_PASS(InstNamer, "instnamer", "Assign names to anonymous instructions", false, false) @@ -61,3 +70,9 @@ char &llvm::InstructionNamerID = InstNamer::ID; FunctionPass *llvm::createInstructionNamerPass() { return new InstNamer(); } + +PreservedAnalyses InstructionNamerPass::run(Function &F, + FunctionAnalysisManager &FAM) { + nameInstructions(F); + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Utils/LCSSA.cpp b/llvm/lib/Transforms/Utils/LCSSA.cpp index b1a1c564d217..7437701f5339 100644 --- a/llvm/lib/Transforms/Utils/LCSSA.cpp +++ b/llvm/lib/Transforms/Utils/LCSSA.cpp @@ -40,6 +40,7 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PredIteratorCache.h" @@ -77,12 +78,15 @@ static bool isExitBlock(BasicBlock *BB, /// rewrite the uses. bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, const DominatorTree &DT, const LoopInfo &LI, - ScalarEvolution *SE) { + ScalarEvolution *SE, IRBuilderBase &Builder, + SmallVectorImpl *PHIsToRemove) { SmallVector UsesToRewrite; - SmallSetVector PHIsToRemove; + SmallSetVector LocalPHIsToRemove; PredIteratorCache PredCache; bool Changed = false; + IRBuilderBase::InsertPointGuard InsertPtGuard(Builder); + // Cache the Loop ExitBlocks across this loop. We expect to get a lot of // instructions within the same loops, computing the exit blocks is // expensive, and we're not mutating the loop structure. @@ -107,6 +111,10 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, for (Use &U : I->uses()) { Instruction *User = cast(U.getUser()); BasicBlock *UserBB = User->getParent(); + + // For practical purposes, we consider that the use in a PHI + // occurs in the respective predecessor block. For more info, + // see the `phi` doc in LangRef and the LCSSA doc. if (auto *PN = dyn_cast(User)) UserBB = PN->getIncomingBlock(U); @@ -151,12 +159,17 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, // If we already inserted something for this BB, don't reprocess it. if (SSAUpdate.HasValueForBlock(ExitBB)) continue; - - PHINode *PN = PHINode::Create(I->getType(), PredCache.size(ExitBB), - I->getName() + ".lcssa", &ExitBB->front()); + Builder.SetInsertPoint(&ExitBB->front()); + PHINode *PN = Builder.CreatePHI(I->getType(), PredCache.size(ExitBB), + I->getName() + ".lcssa"); // Get the debug location from the original instruction. PN->setDebugLoc(I->getDebugLoc()); - // Add inputs from inside the loop for this PHI. + + // Add inputs from inside the loop for this PHI. This is valid + // because `I` dominates `ExitBB` (checked above). This implies + // that every incoming block/edge is dominated by `I` as well, + // i.e. we can add uses of `I` to those incoming edges/append to the incoming + // blocks without violating the SSA dominance property. for (BasicBlock *Pred : PredCache.get(ExitBB)) { PN->addIncoming(I, Pred); @@ -190,15 +203,19 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, // Rewrite all uses outside the loop in terms of the new PHIs we just // inserted. for (Use *UseToRewrite : UsesToRewrite) { - // If this use is in an exit block, rewrite to use the newly inserted PHI. - // This is required for correctness because SSAUpdate doesn't handle uses - // in the same block. It assumes the PHI we inserted is at the end of the - // block. Instruction *User = cast(UseToRewrite->getUser()); BasicBlock *UserBB = User->getParent(); + + // For practical purposes, we consider that the use in a PHI + // occurs in the respective predecessor block. For more info, + // see the `phi` doc in LangRef and the LCSSA doc. if (auto *PN = dyn_cast(User)) UserBB = PN->getIncomingBlock(*UseToRewrite); + // If this use is in an exit block, rewrite to use the newly inserted PHI. + // This is required for correctness because SSAUpdate doesn't handle uses + // in the same block. It assumes the PHI we inserted is at the end of the + // block. if (isa(UserBB->begin()) && isExitBlock(UserBB, ExitBlocks)) { UseToRewrite->set(&UserBB->front()); continue; @@ -248,27 +265,29 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, Worklist.push_back(PostProcessPN); // Keep track of PHI nodes that we want to remove because they did not have - // any uses rewritten. If the new PHI is used, store it so that we can - // try to propagate dbg.value intrinsics to it. - SmallVector NeedDbgValues; + // any uses rewritten. for (PHINode *PN : AddedPHIs) if (PN->use_empty()) - PHIsToRemove.insert(PN); - else - NeedDbgValues.push_back(PN); - insertDebugValuesForPHIs(InstBB, NeedDbgValues); + LocalPHIsToRemove.insert(PN); + Changed = true; } - // Remove PHI nodes that did not have any uses rewritten. We need to redo the - // use_empty() check here, because even if the PHI node wasn't used when added - // to PHIsToRemove, later added PHI nodes can be using it. This cleanup is - // not guaranteed to handle trees/cycles of PHI nodes that only are used by - // each other. Such situations has only been noticed when the input IR - // contains unreachable code, and leaving some extra redundant PHI nodes in - // such situations is considered a minor problem. - for (PHINode *PN : PHIsToRemove) - if (PN->use_empty()) - PN->eraseFromParent(); + + // Remove PHI nodes that did not have any uses rewritten or add them to + // PHIsToRemove, so the caller can remove them after some additional cleanup. + // We need to redo the use_empty() check here, because even if the PHI node + // wasn't used when added to LocalPHIsToRemove, later added PHI nodes can be + // using it. This cleanup is not guaranteed to handle trees/cycles of PHI + // nodes that only are used by each other. Such situations has only been + // noticed when the input IR contains unreachable code, and leaving some extra + // redundant PHI nodes in such situations is considered a minor problem. + if (PHIsToRemove) { + PHIsToRemove->append(LocalPHIsToRemove.begin(), LocalPHIsToRemove.end()); + } else { + for (PHINode *PN : LocalPHIsToRemove) + if (PN->use_empty()) + PN->eraseFromParent(); + } return Changed; } @@ -276,12 +295,9 @@ bool llvm::formLCSSAForInstructions(SmallVectorImpl &Worklist, static void computeBlocksDominatingExits( Loop &L, const DominatorTree &DT, SmallVector &ExitBlocks, SmallSetVector &BlocksDominatingExits) { - SmallVector BBWorklist; - // We start from the exit blocks, as every block trivially dominates itself // (not strictly). - for (BasicBlock *BB : ExitBlocks) - BBWorklist.push_back(BB); + SmallVector BBWorklist(ExitBlocks); while (!BBWorklist.empty()) { BasicBlock *BB = BBWorklist.pop_back_val(); @@ -369,7 +385,9 @@ bool llvm::formLCSSA(Loop &L, const DominatorTree &DT, const LoopInfo *LI, Worklist.push_back(&I); } } - Changed = formLCSSAForInstructions(Worklist, DT, *LI, SE); + + IRBuilder<> Builder(L.getHeader()->getContext()); + Changed = formLCSSAForInstructions(Worklist, DT, *LI, SE, Builder); // If we modified the code, remove any caches about the loop from SCEV to // avoid dangling entries. diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index da40c342af3a..477ea458c763 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -91,6 +91,24 @@ using namespace llvm::PatternMatch; #define DEBUG_TYPE "local" STATISTIC(NumRemoved, "Number of unreachable basic blocks removed"); +STATISTIC(NumPHICSEs, "Number of PHI's that got CSE'd"); + +static cl::opt PHICSEDebugHash( + "phicse-debug-hash", +#ifdef EXPENSIVE_CHECKS + cl::init(true), +#else + cl::init(false), +#endif + cl::Hidden, + cl::desc("Perform extra assertion checking to verify that PHINodes's hash " + "function is well-behaved w.r.t. its isEqual predicate")); + +static cl::opt PHICSENumPHISmallSize( + "phicse-num-phi-smallsize", cl::init(32), cl::Hidden, + cl::desc( + "When the basic block contains not more than this number of PHI nodes, " + "perform a (faster!) exhaustive search instead of set-driven one.")); // Max recursion depth for collectBitParts used when detecting bswap and // bitreverse idioms @@ -116,27 +134,10 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, // Branch - See if we are conditional jumping on constant if (auto *BI = dyn_cast(T)) { if (BI->isUnconditional()) return false; // Can't optimize uncond branch + BasicBlock *Dest1 = BI->getSuccessor(0); BasicBlock *Dest2 = BI->getSuccessor(1); - if (auto *Cond = dyn_cast(BI->getCondition())) { - // Are we branching on constant? - // YES. Change to unconditional branch... - BasicBlock *Destination = Cond->getZExtValue() ? Dest1 : Dest2; - BasicBlock *OldDest = Cond->getZExtValue() ? Dest2 : Dest1; - - // Let the basic block know that we are letting go of it. Based on this, - // it will adjust it's PHI nodes. - OldDest->removePredecessor(BB); - - // Replace the conditional branch with an unconditional one. - Builder.CreateBr(Destination); - BI->eraseFromParent(); - if (DTU) - DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, OldDest}}); - return true; - } - if (Dest2 == Dest1) { // Conditional branch to same location? // This branch matches something like this: // br bool %cond, label %Dest, label %Dest @@ -154,6 +155,25 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI); return true; } + + if (auto *Cond = dyn_cast(BI->getCondition())) { + // Are we branching on constant? + // YES. Change to unconditional branch... + BasicBlock *Destination = Cond->getZExtValue() ? Dest1 : Dest2; + BasicBlock *OldDest = Cond->getZExtValue() ? Dest2 : Dest1; + + // Let the basic block know that we are letting go of it. Based on this, + // it will adjust it's PHI nodes. + OldDest->removePredecessor(BB); + + // Replace the conditional branch with an unconditional one. + Builder.CreateBr(Destination); + BI->eraseFromParent(); + if (DTU) + DTU->applyUpdates({{DominatorTree::Delete, BB, OldDest}}); + return true; + } + return false; } @@ -170,6 +190,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, TheOnlyDest = SI->case_begin()->getCaseSuccessor(); } + bool Changed = false; + // Figure out which case it goes to. for (auto i = SI->case_begin(), e = SI->case_end(); i != e;) { // Found case matching a constant operand? @@ -208,9 +230,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, DefaultDest->removePredecessor(ParentBB); i = SI->removeCase(i); e = SI->case_end(); - if (DTU) - DTU->applyUpdatesPermissive( - {{DominatorTree::Delete, ParentBB, DefaultDest}}); + Changed = true; continue; } @@ -236,19 +256,19 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, // Insert the new branch. Builder.CreateBr(TheOnlyDest); BasicBlock *BB = SI->getParent(); - std::vector Updates; - if (DTU) - Updates.reserve(SI->getNumSuccessors() - 1); + + SmallSetVector RemovedSuccessors; // Remove entries from PHI nodes which we no longer branch to... + BasicBlock *SuccToKeep = TheOnlyDest; for (BasicBlock *Succ : successors(SI)) { + if (DTU && Succ != TheOnlyDest) + RemovedSuccessors.insert(Succ); // Found case matching a constant operand? - if (Succ == TheOnlyDest) { - TheOnlyDest = nullptr; // Don't modify the first branch to TheOnlyDest + if (Succ == SuccToKeep) { + SuccToKeep = nullptr; // Don't modify the first branch to TheOnlyDest } else { Succ->removePredecessor(BB); - if (DTU) - Updates.push_back({DominatorTree::Delete, BB, Succ}); } } @@ -257,8 +277,13 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, SI->eraseFromParent(); if (DeleteDeadConditions) RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI); - if (DTU) - DTU->applyUpdatesPermissive(Updates); + if (DTU) { + std::vector Updates; + Updates.reserve(RemovedSuccessors.size()); + for (auto *RemovedSuccessor : RemovedSuccessors) + Updates.push_back({DominatorTree::Delete, BB, RemovedSuccessor}); + DTU->applyUpdates(Updates); + } return true; } @@ -296,7 +321,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, SI->eraseFromParent(); return true; } - return false; + return Changed; } if (auto *IBI = dyn_cast(T)) { @@ -304,22 +329,20 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, if (auto *BA = dyn_cast(IBI->getAddress()->stripPointerCasts())) { BasicBlock *TheOnlyDest = BA->getBasicBlock(); - std::vector Updates; - if (DTU) - Updates.reserve(IBI->getNumDestinations() - 1); + SmallSetVector RemovedSuccessors; // Insert the new branch. Builder.CreateBr(TheOnlyDest); + BasicBlock *SuccToKeep = TheOnlyDest; for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) { - if (IBI->getDestination(i) == TheOnlyDest) { - TheOnlyDest = nullptr; + BasicBlock *DestBB = IBI->getDestination(i); + if (DTU && DestBB != TheOnlyDest) + RemovedSuccessors.insert(DestBB); + if (IBI->getDestination(i) == SuccToKeep) { + SuccToKeep = nullptr; } else { - BasicBlock *ParentBB = IBI->getParent(); - BasicBlock *DestBB = IBI->getDestination(i); - DestBB->removePredecessor(ParentBB); - if (DTU) - Updates.push_back({DominatorTree::Delete, ParentBB, DestBB}); + DestBB->removePredecessor(BB); } } Value *Address = IBI->getAddress(); @@ -336,13 +359,18 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, // If we didn't find our destination in the IBI successor list, then we // have undefined behavior. Replace the unconditional branch with an // 'unreachable' instruction. - if (TheOnlyDest) { + if (SuccToKeep) { BB->getTerminator()->eraseFromParent(); new UnreachableInst(BB->getContext(), BB); } - if (DTU) - DTU->applyUpdatesPermissive(Updates); + if (DTU) { + std::vector Updates; + Updates.reserve(RemovedSuccessors.size()); + for (auto *RemovedSuccessor : RemovedSuccessors) + Updates.push_back({DominatorTree::Delete, BB, RemovedSuccessor}); + DTU->applyUpdates(Updates); + } return true; } } @@ -392,6 +420,14 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I, return true; } + if (auto *CB = dyn_cast(I)) { + // Treat calls that may not return as alive. + // TODO: Remove the intrinsic escape hatch once all intrinsics set + // willreturn properly. + if (!CB->willReturn() && !isa(I)) + return false; + } + if (!I->mayHaveSideEffects()) return true; @@ -453,21 +489,24 @@ bool llvm::wouldInstructionBeTriviallyDead(Instruction *I, /// trivially dead, delete them too, recursively. Return true if any /// instructions were deleted. bool llvm::RecursivelyDeleteTriviallyDeadInstructions( - Value *V, const TargetLibraryInfo *TLI, MemorySSAUpdater *MSSAU) { + Value *V, const TargetLibraryInfo *TLI, MemorySSAUpdater *MSSAU, + std::function AboutToDeleteCallback) { Instruction *I = dyn_cast(V); if (!I || !isInstructionTriviallyDead(I, TLI)) return false; SmallVector DeadInsts; DeadInsts.push_back(I); - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU); + RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU, + AboutToDeleteCallback); return true; } bool llvm::RecursivelyDeleteTriviallyDeadInstructionsPermissive( SmallVectorImpl &DeadInsts, const TargetLibraryInfo *TLI, - MemorySSAUpdater *MSSAU) { + MemorySSAUpdater *MSSAU, + std::function AboutToDeleteCallback) { unsigned S = 0, E = DeadInsts.size(), Alive = 0; for (; S != E; ++S) { auto *I = cast(DeadInsts[S]); @@ -478,13 +517,15 @@ bool llvm::RecursivelyDeleteTriviallyDeadInstructionsPermissive( } if (Alive == E) return false; - RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU); + RecursivelyDeleteTriviallyDeadInstructions(DeadInsts, TLI, MSSAU, + AboutToDeleteCallback); return true; } void llvm::RecursivelyDeleteTriviallyDeadInstructions( SmallVectorImpl &DeadInsts, const TargetLibraryInfo *TLI, - MemorySSAUpdater *MSSAU) { + MemorySSAUpdater *MSSAU, + std::function AboutToDeleteCallback) { // Process the dead instruction list until empty. while (!DeadInsts.empty()) { Value *V = DeadInsts.pop_back_val(); @@ -498,6 +539,9 @@ void llvm::RecursivelyDeleteTriviallyDeadInstructions( // Don't lose the debug info while deleting the instructions. salvageDebugInfo(*I); + if (AboutToDeleteCallback) + AboutToDeleteCallback(I); + // Null out all of the instruction's operands to see if any operand becomes // dead as we go. for (Use &OpU : I->operands()) { @@ -675,34 +719,6 @@ bool llvm::SimplifyInstructionsInBlock(BasicBlock *BB, // Control Flow Graph Restructuring. // -void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred, - DomTreeUpdater *DTU) { - // This only adjusts blocks with PHI nodes. - if (!isa(BB->begin())) - return; - - // Remove the entries for Pred from the PHI nodes in BB, but do not simplify - // them down. This will leave us with single entry phi nodes and other phis - // that can be removed. - BB->removePredecessor(Pred, true); - - WeakTrackingVH PhiIt = &BB->front(); - while (PHINode *PN = dyn_cast(PhiIt)) { - PhiIt = &*++BasicBlock::iterator(cast(PhiIt)); - Value *OldPhiIt = PhiIt; - - if (!recursivelySimplifyInstruction(PN)) - continue; - - // If recursive simplification ended up deleting the next PHI node we would - // iterate to, then our iterator is invalid, restart scanning from the top - // of the block. - if (PhiIt != OldPhiIt) PhiIt = &BB->front(); - } - if (DTU) - DTU->applyUpdatesPermissive({{DominatorTree::Delete, Pred, BB}}); -} - void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DomTreeUpdater *DTU) { @@ -727,13 +743,13 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, SmallVector Updates; if (DTU) { - Updates.push_back({DominatorTree::Delete, PredBB, DestBB}); for (auto I = pred_begin(PredBB), E = pred_end(PredBB); I != E; ++I) { - Updates.push_back({DominatorTree::Delete, *I, PredBB}); // This predecessor of PredBB may already have DestBB as a successor. - if (llvm::find(successors(*I), DestBB) == succ_end(*I)) + if (!llvm::is_contained(successors(*I), DestBB)) Updates.push_back({DominatorTree::Insert, *I, DestBB}); + Updates.push_back({DominatorTree::Delete, *I, PredBB}); } + Updates.push_back({DominatorTree::Delete, PredBB, DestBB}); } // Zap anything that took the address of DestBB. Not doing this will give the @@ -1038,14 +1054,16 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, SmallVector Updates; if (DTU) { - Updates.push_back({DominatorTree::Delete, BB, Succ}); // All predecessors of BB will be moved to Succ. - for (auto I = pred_begin(BB), E = pred_end(BB); I != E; ++I) { - Updates.push_back({DominatorTree::Delete, *I, BB}); + SmallSetVector Predecessors(pred_begin(BB), pred_end(BB)); + Updates.reserve(Updates.size() + 2 * Predecessors.size()); + for (auto *Predecessor : Predecessors) { // This predecessor of BB may already have Succ as a successor. - if (llvm::find(successors(*I), Succ) == succ_end(*I)) - Updates.push_back({DominatorTree::Insert, *I, Succ}); + if (!llvm::is_contained(successors(Predecessor), Succ)) + Updates.push_back({DominatorTree::Insert, Predecessor, Succ}); + Updates.push_back({DominatorTree::Delete, Predecessor, BB}); } + Updates.push_back({DominatorTree::Delete, BB, Succ}); } if (isa(Succ->begin())) { @@ -1101,7 +1119,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, "applying corresponding DTU updates."); if (DTU) { - DTU->applyUpdatesPermissive(Updates); + DTU->applyUpdates(Updates); DTU->deleteBB(BB); } else { BB->eraseFromParent(); // Delete the old basic block. @@ -1109,7 +1127,39 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, return true; } -bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { +static bool EliminateDuplicatePHINodesNaiveImpl(BasicBlock *BB) { + // This implementation doesn't currently consider undef operands + // specially. Theoretically, two phis which are identical except for + // one having an undef where the other doesn't could be collapsed. + + bool Changed = false; + + // Examine each PHI. + // Note that increment of I must *NOT* be in the iteration_expression, since + // we don't want to immediately advance when we restart from the beginning. + for (auto I = BB->begin(); PHINode *PN = dyn_cast(I);) { + ++I; + // Is there an identical PHI node in this basic block? + // Note that we only look in the upper square's triangle, + // we already checked that the lower triangle PHI's aren't identical. + for (auto J = I; PHINode *DuplicatePN = dyn_cast(J); ++J) { + if (!DuplicatePN->isIdenticalToWhenDefined(PN)) + continue; + // A duplicate. Replace this PHI with the base PHI. + ++NumPHICSEs; + DuplicatePN->replaceAllUsesWith(PN); + DuplicatePN->eraseFromParent(); + Changed = true; + + // The RAUW can change PHIs that we already visited. + I = BB->begin(); + break; // Start over from the beginning. + } + } + return Changed; +} + +static bool EliminateDuplicatePHINodesSetBasedImpl(BasicBlock *BB) { // This implementation doesn't currently consider undef operands // specially. Theoretically, two phis which are identical except for // one having an undef where the other doesn't could be collapsed. @@ -1123,7 +1173,13 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { return DenseMapInfo::getTombstoneKey(); } - static unsigned getHashValue(PHINode *PN) { + static bool isSentinel(PHINode *PN) { + return PN == getEmptyKey() || PN == getTombstoneKey(); + } + + // WARNING: this logic must be kept in sync with + // Instruction::isIdenticalToWhenDefined()! + static unsigned getHashValueImpl(PHINode *PN) { // Compute a hash value on the operands. Instcombine will likely have // sorted them, which helps expose duplicates, but we have to check all // the operands to be safe in case instcombine hasn't run. @@ -1132,16 +1188,37 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { hash_combine_range(PN->block_begin(), PN->block_end()))); } - static bool isEqual(PHINode *LHS, PHINode *RHS) { - if (LHS == getEmptyKey() || LHS == getTombstoneKey() || - RHS == getEmptyKey() || RHS == getTombstoneKey()) + static unsigned getHashValue(PHINode *PN) { +#ifndef NDEBUG + // If -phicse-debug-hash was specified, return a constant -- this + // will force all hashing to collide, so we'll exhaustively search + // the table for a match, and the assertion in isEqual will fire if + // there's a bug causing equal keys to hash differently. + if (PHICSEDebugHash) + return 0; +#endif + return getHashValueImpl(PN); + } + + static bool isEqualImpl(PHINode *LHS, PHINode *RHS) { + if (isSentinel(LHS) || isSentinel(RHS)) return LHS == RHS; return LHS->isIdenticalTo(RHS); } + + static bool isEqual(PHINode *LHS, PHINode *RHS) { + // These comparisons are nontrivial, so assert that equality implies + // hash equality (DenseMap demands this as an invariant). + bool Result = isEqualImpl(LHS, RHS); + assert(!Result || (isSentinel(LHS) && LHS == RHS) || + getHashValueImpl(LHS) == getHashValueImpl(RHS)); + return Result; + } }; // Set of unique PHINodes. DenseSet PHISet; + PHISet.reserve(4 * PHICSENumPHISmallSize); // Examine each PHI. bool Changed = false; @@ -1149,6 +1226,7 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { auto Inserted = PHISet.insert(PN); if (!Inserted.second) { // A duplicate. Replace this PHI with its duplicate. + ++NumPHICSEs; PN->replaceAllUsesWith(*Inserted.first); PN->eraseFromParent(); Changed = true; @@ -1163,54 +1241,63 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { return Changed; } -/// enforceKnownAlignment - If the specified pointer points to an object that -/// we control, modify the object's alignment to PrefAlign. This isn't -/// often possible though. If alignment is important, a more reliable approach -/// is to simply align all global variables and allocation instructions to -/// their preferred alignment from the beginning. -static Align enforceKnownAlignment(Value *V, Align Alignment, Align PrefAlign, - const DataLayout &DL) { - assert(PrefAlign > Alignment); +bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) { + if ( +#ifndef NDEBUG + !PHICSEDebugHash && +#endif + hasNItemsOrLess(BB->phis(), PHICSENumPHISmallSize)) + return EliminateDuplicatePHINodesNaiveImpl(BB); + return EliminateDuplicatePHINodesSetBasedImpl(BB); +} +/// If the specified pointer points to an object that we control, try to modify +/// the object's alignment to PrefAlign. Returns a minimum known alignment of +/// the value after the operation, which may be lower than PrefAlign. +/// +/// Increating value alignment isn't often possible though. If alignment is +/// important, a more reliable approach is to simply align all global variables +/// and allocation instructions to their preferred alignment from the beginning. +static Align tryEnforceAlignment(Value *V, Align PrefAlign, + const DataLayout &DL) { V = V->stripPointerCasts(); if (AllocaInst *AI = dyn_cast(V)) { - // TODO: ideally, computeKnownBits ought to have used - // AllocaInst::getAlignment() in its computation already, making - // the below max redundant. But, as it turns out, - // stripPointerCasts recurses through infinite layers of bitcasts, - // while computeKnownBits is not allowed to traverse more than 6 - // levels. - Alignment = std::max(AI->getAlign(), Alignment); - if (PrefAlign <= Alignment) - return Alignment; + // TODO: Ideally, this function would not be called if PrefAlign is smaller + // than the current alignment, as the known bits calculation should have + // already taken it into account. However, this is not always the case, + // as computeKnownBits() has a depth limit, while stripPointerCasts() + // doesn't. + Align CurrentAlign = AI->getAlign(); + if (PrefAlign <= CurrentAlign) + return CurrentAlign; // If the preferred alignment is greater than the natural stack alignment // then don't round up. This avoids dynamic stack realignment. if (DL.exceedsNaturalStackAlignment(PrefAlign)) - return Alignment; + return CurrentAlign; AI->setAlignment(PrefAlign); return PrefAlign; } if (auto *GO = dyn_cast(V)) { // TODO: as above, this shouldn't be necessary. - Alignment = max(GO->getAlign(), Alignment); - if (PrefAlign <= Alignment) - return Alignment; + Align CurrentAlign = GO->getPointerAlignment(DL); + if (PrefAlign <= CurrentAlign) + return CurrentAlign; // If there is a large requested alignment and we can, bump up the alignment // of the global. If the memory we set aside for the global may not be the // memory used by the final program then it is impossible for us to reliably // enforce the preferred alignment. if (!GO->canIncreaseAlignment()) - return Alignment; + return CurrentAlign; GO->setAlignment(PrefAlign); return PrefAlign; } - return Alignment; + return Align(1); } Align llvm::getOrEnforceKnownAlignment(Value *V, MaybeAlign PrefAlign, @@ -1232,7 +1319,7 @@ Align llvm::getOrEnforceKnownAlignment(Value *V, MaybeAlign PrefAlign, Align Alignment = Align(1ull << std::min(Known.getBitWidth() - 1, TrailZ)); if (PrefAlign && *PrefAlign > Alignment) - Alignment = enforceKnownAlignment(V, Alignment, *PrefAlign, DL); + Alignment = std::max(Alignment, tryEnforceAlignment(V, *PrefAlign, DL)); // We don't need to make any adjustment. return Alignment; @@ -1270,16 +1357,22 @@ static bool PhiHasDebugValue(DILocalVariable *DIVar, /// least n bits. static bool valueCoversEntireFragment(Type *ValTy, DbgVariableIntrinsic *DII) { const DataLayout &DL = DII->getModule()->getDataLayout(); - uint64_t ValueSize = DL.getTypeAllocSizeInBits(ValTy); - if (auto FragmentSize = DII->getFragmentSizeInBits()) - return ValueSize >= *FragmentSize; + TypeSize ValueSize = DL.getTypeAllocSizeInBits(ValTy); + if (Optional FragmentSize = DII->getFragmentSizeInBits()) { + assert(!ValueSize.isScalable() && + "Fragments don't work on scalable types."); + return ValueSize.getFixedSize() >= *FragmentSize; + } // We can't always calculate the size of the DI variable (e.g. if it is a // VLA). Try to use the size of the alloca that the dbg intrinsic describes // intead. if (DII->isAddressOfVariable()) if (auto *AI = dyn_cast_or_null(DII->getVariableLocation())) - if (auto FragmentSize = AI->getAllocationSizeInBits(DL)) - return ValueSize >= *FragmentSize; + if (Optional FragmentSize = AI->getAllocationSizeInBits(DL)) { + assert(ValueSize.isScalable() == FragmentSize->isScalable() && + "Both sizes should agree on the scalable flag."); + return TypeSize::isKnownGE(ValueSize, *FragmentSize); + } // Could not determine size of variable. Conservatively return false. return false; } @@ -1294,7 +1387,7 @@ static DebugLoc getDebugValueLoc(DbgVariableIntrinsic *DII, Instruction *Src) { MDNode *Scope = DeclareLoc.getScope(); DILocation *InlinedAt = DeclareLoc.getInlinedAt(); // Produce an unknown location with the correct scope / inlinedAt fields. - return DebugLoc::get(0, 0, Scope, InlinedAt); + return DILocation::get(DII->getContext(), 0, 0, Scope, InlinedAt); } /// Inserts a llvm.dbg.value intrinsic before a store to an alloca'd value @@ -1911,8 +2004,10 @@ bool llvm::replaceAllDbgUsesWith(Instruction &From, Value &To, return false; } -unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { +std::pair +llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { unsigned NumDeadInst = 0; + unsigned NumDeadDbgInst = 0; // Delete the instructions backwards, as it has a reduced likelihood of // having to update as many def-use and use-def chains. Instruction *EndInst = BB->getTerminator(); // Last not to be deleted. @@ -1925,30 +2020,31 @@ unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { EndInst = Inst; continue; } - if (!isa(Inst)) + if (isa(Inst)) + ++NumDeadDbgInst; + else ++NumDeadInst; Inst->eraseFromParent(); } - return NumDeadInst; + return {NumDeadInst, NumDeadDbgInst}; } unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap, bool PreserveLCSSA, DomTreeUpdater *DTU, MemorySSAUpdater *MSSAU) { BasicBlock *BB = I->getParent(); - std::vector Updates; if (MSSAU) MSSAU->changeToUnreachable(I); + SmallSetVector UniqueSuccessors; + // Loop over all of the successors, removing BB's entry from any PHI // nodes. - if (DTU) - Updates.reserve(BB->getTerminator()->getNumSuccessors()); for (BasicBlock *Successor : successors(BB)) { Successor->removePredecessor(BB, PreserveLCSSA); if (DTU) - Updates.push_back({DominatorTree::Delete, BB, Successor}); + UniqueSuccessors.insert(Successor); } // Insert a call to llvm.trap right before this. This turns the undefined // behavior into a hard fail instead of falling through into random code. @@ -1970,13 +2066,18 @@ unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap, BB->getInstList().erase(BBI++); ++NumInstrsRemoved; } - if (DTU) - DTU->applyUpdatesPermissive(Updates); + if (DTU) { + SmallVector Updates; + Updates.reserve(UniqueSuccessors.size()); + for (BasicBlock *UniqueSuccessor : UniqueSuccessors) + Updates.push_back({DominatorTree::Delete, BB, UniqueSuccessor}); + DTU->applyUpdates(Updates); + } return NumInstrsRemoved; } CallInst *llvm::createCallMatchingInvoke(InvokeInst *II) { - SmallVector Args(II->arg_begin(), II->arg_end()); + SmallVector Args(II->args()); SmallVector OpBundles; II->getOperandBundlesAsDefs(OpBundles); CallInst *NewCall = CallInst::Create(II->getFunctionType(), @@ -2017,7 +2118,7 @@ void llvm::changeToCall(InvokeInst *II, DomTreeUpdater *DTU) { UnwindDestBB->removePredecessor(BB); II->eraseFromParent(); if (DTU) - DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, UnwindDestBB}}); + DTU->applyUpdates({{DominatorTree::Delete, BB, UnwindDestBB}}); } BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI, @@ -2033,7 +2134,7 @@ BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI, BB->getInstList().pop_back(); // Create the new invoke instruction. - SmallVector InvokeArgs(CI->arg_begin(), CI->arg_end()); + SmallVector InvokeArgs(CI->args()); SmallVector OpBundles; CI->getOperandBundlesAsDefs(OpBundles); @@ -2164,8 +2265,7 @@ static bool markAliveBlocks(Function &F, UnwindDestBB->removePredecessor(II->getParent()); II->eraseFromParent(); if (DTU) - DTU->applyUpdatesPermissive( - {{DominatorTree::Delete, BB, UnwindDestBB}}); + DTU->applyUpdates({{DominatorTree::Delete, BB, UnwindDestBB}}); } else changeToCall(II, DTU); Changed = true; @@ -2194,6 +2294,7 @@ static bool markAliveBlocks(Function &F, } }; + SmallMapVector NumPerSuccessorCases; // Set of unique CatchPads. SmallDenseMap> @@ -2203,14 +2304,22 @@ static bool markAliveBlocks(Function &F, E = CatchSwitch->handler_end(); I != E; ++I) { BasicBlock *HandlerBB = *I; + ++NumPerSuccessorCases[HandlerBB]; auto *CatchPad = cast(HandlerBB->getFirstNonPHI()); if (!HandlerSet.insert({CatchPad, Empty}).second) { + --NumPerSuccessorCases[HandlerBB]; CatchSwitch->removeHandler(I); --I; --E; Changed = true; } } + std::vector Updates; + for (const std::pair &I : NumPerSuccessorCases) + if (I.second == 0) + Updates.push_back({DominatorTree::Delete, BB, I.first}); + if (DTU) + DTU->applyUpdates(Updates); } Changed |= ConstantFoldTerminator(BB, true, nullptr, DTU); @@ -2254,7 +2363,7 @@ void llvm::removeUnwindEdge(BasicBlock *BB, DomTreeUpdater *DTU) { TI->replaceAllUsesWith(NewTI); TI->eraseFromParent(); if (DTU) - DTU->applyUpdatesPermissive({{DominatorTree::Delete, BB, UnwindDest}}); + DTU->applyUpdates({{DominatorTree::Delete, BB, UnwindDest}}); } /// removeUnreachableBlocks - Remove blocks that are not reachable, even @@ -2270,28 +2379,39 @@ bool llvm::removeUnreachableBlocks(Function &F, DomTreeUpdater *DTU, return Changed; assert(Reachable.size() < F.size()); - NumRemoved += F.size() - Reachable.size(); - SmallSetVector DeadBlockSet; + // Are there any blocks left to actually delete? + SmallSetVector BlocksToRemove; for (BasicBlock &BB : F) { // Skip reachable basic blocks if (Reachable.count(&BB)) continue; - DeadBlockSet.insert(&BB); + // Skip already-deleted blocks + if (DTU && DTU->isBBPendingDeletion(&BB)) + continue; + BlocksToRemove.insert(&BB); } + if (BlocksToRemove.empty()) + return Changed; + + Changed = true; + NumRemoved += BlocksToRemove.size(); + if (MSSAU) - MSSAU->removeBlocks(DeadBlockSet); + MSSAU->removeBlocks(BlocksToRemove); - // Loop over all of the basic blocks that are not reachable, dropping all of + // Loop over all of the basic blocks that are up for removal, dropping all of // their internal references. Update DTU if available. std::vector Updates; - for (auto *BB : DeadBlockSet) { + for (auto *BB : BlocksToRemove) { + SmallSetVector UniqueSuccessors; for (BasicBlock *Successor : successors(BB)) { - if (!DeadBlockSet.count(Successor)) + // Only remove references to BB in reachable successors of BB. + if (Reachable.count(Successor)) Successor->removePredecessor(BB); if (DTU) - Updates.push_back({DominatorTree::Delete, BB, Successor}); + UniqueSuccessors.insert(Successor); } BB->dropAllReferences(); if (DTU) { @@ -2305,27 +2425,22 @@ bool llvm::removeUnreachableBlocks(Function &F, DomTreeUpdater *DTU, new UnreachableInst(BB->getContext(), BB); assert(succ_empty(BB) && "The successor list of BB isn't empty before " "applying corresponding DTU updates."); + Updates.reserve(Updates.size() + UniqueSuccessors.size()); + for (auto *UniqueSuccessor : UniqueSuccessors) + Updates.push_back({DominatorTree::Delete, BB, UniqueSuccessor}); } } if (DTU) { - DTU->applyUpdatesPermissive(Updates); - bool Deleted = false; - for (auto *BB : DeadBlockSet) { - if (DTU->isBBPendingDeletion(BB)) - --NumRemoved; - else - Deleted = true; + DTU->applyUpdates(Updates); + for (auto *BB : BlocksToRemove) DTU->deleteBB(BB); - } - if (!Deleted) - return false; } else { - for (auto *BB : DeadBlockSet) + for (auto *BB : BlocksToRemove) BB->eraseFromParent(); } - return true; + return Changed; } void llvm::combineMetadata(Instruction *K, const Instruction *J, @@ -2570,10 +2685,13 @@ bool llvm::callsGCLeafFunction(const CallBase *Call, if (F->hasFnAttribute("gc-leaf-function")) return true; - if (auto IID = F->getIntrinsicID()) + if (auto IID = F->getIntrinsicID()) { // Most LLVM intrinsics do not take safepoints. return IID != Intrinsic::experimental_gc_statepoint && - IID != Intrinsic::experimental_deoptimize; + IID != Intrinsic::experimental_deoptimize && + IID != Intrinsic::memcpy_element_unordered_atomic && + IID != Intrinsic::memmove_element_unordered_atomic; + } } // Lib calls can be materialized by some passes, and won't be @@ -2701,7 +2819,7 @@ struct BitPart { /// Analyze the specified subexpression and see if it is capable of providing /// pieces of a bswap or bitreverse. The subexpression provides a potential -/// piece of a bswap or bitreverse if it can be proven that each non-zero bit in +/// piece of a bswap or bitreverse if it can be proved that each non-zero bit in /// the output of the expression came from a corresponding bit in some other /// value. This function is recursive, and the end result is a mapping of /// bitnumber to bitnumber. It is the caller's responsibility to validate that @@ -2713,6 +2831,10 @@ struct BitPart { /// BitPart is returned with Provider set to %X and Provenance[24-31] set to /// [0-7]. /// +/// For vector types, all analysis is performed at the per-element level. No +/// cross-element analysis is supported (shuffle/insertion/reduction), and all +/// constant masks must be splatted across all elements. +/// /// To avoid revisiting values, the BitPart results are memoized into the /// provided map. To avoid unnecessary copying of BitParts, BitParts are /// constructed in-place in the \c BPS map. Because of this \c BPS needs to @@ -2730,7 +2852,7 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, return I->second; auto &Result = BPS[V] = None; - auto BitWidth = cast(V->getType())->getBitWidth(); + auto BitWidth = V->getType()->getScalarSizeInBits(); // Prevent stack overflow by limiting the recursion depth if (Depth == BitPartRecursionMaxDepth) { @@ -2738,13 +2860,16 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, return Result; } - if (Instruction *I = dyn_cast(V)) { + if (auto *I = dyn_cast(V)) { + Value *X, *Y; + const APInt *C; + // If this is an or instruction, it may be an inner node of the bswap. - if (I->getOpcode() == Instruction::Or) { - auto &A = collectBitParts(I->getOperand(0), MatchBSwaps, - MatchBitReversals, BPS, Depth + 1); - auto &B = collectBitParts(I->getOperand(1), MatchBSwaps, - MatchBitReversals, BPS, Depth + 1); + if (match(V, m_Or(m_Value(X), m_Value(Y)))) { + const auto &A = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); + const auto &B = + collectBitParts(Y, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); if (!A || !B) return Result; @@ -2753,31 +2878,31 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, return Result; Result = BitPart(A->Provider, BitWidth); - for (unsigned i = 0; i < A->Provenance.size(); ++i) { - if (A->Provenance[i] != BitPart::Unset && - B->Provenance[i] != BitPart::Unset && - A->Provenance[i] != B->Provenance[i]) + for (unsigned BitIdx = 0; BitIdx < BitWidth; ++BitIdx) { + if (A->Provenance[BitIdx] != BitPart::Unset && + B->Provenance[BitIdx] != BitPart::Unset && + A->Provenance[BitIdx] != B->Provenance[BitIdx]) return Result = None; - if (A->Provenance[i] == BitPart::Unset) - Result->Provenance[i] = B->Provenance[i]; + if (A->Provenance[BitIdx] == BitPart::Unset) + Result->Provenance[BitIdx] = B->Provenance[BitIdx]; else - Result->Provenance[i] = A->Provenance[i]; + Result->Provenance[BitIdx] = A->Provenance[BitIdx]; } return Result; } // If this is a logical shift by a constant, recurse then shift the result. - if (I->isLogicalShift() && isa(I->getOperand(1))) { - unsigned BitShift = - cast(I->getOperand(1))->getLimitedValue(~0U); + if (match(V, m_LogicalShift(m_Value(X), m_APInt(C)))) { + const APInt &BitShift = *C; + // Ensure the shift amount is defined. - if (BitShift > BitWidth) + if (BitShift.uge(BitWidth)) return Result; - auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps, - MatchBitReversals, BPS, Depth + 1); + const auto &Res = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); if (!Res) return Result; Result = Res; @@ -2785,11 +2910,11 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, // Perform the "shift" on BitProvenance. auto &P = Result->Provenance; if (I->getOpcode() == Instruction::Shl) { - P.erase(std::prev(P.end(), BitShift), P.end()); - P.insert(P.begin(), BitShift, BitPart::Unset); + P.erase(std::prev(P.end(), BitShift.getZExtValue()), P.end()); + P.insert(P.begin(), BitShift.getZExtValue(), BitPart::Unset); } else { - P.erase(P.begin(), std::next(P.begin(), BitShift)); - P.insert(P.end(), BitShift, BitPart::Unset); + P.erase(P.begin(), std::next(P.begin(), BitShift.getZExtValue())); + P.insert(P.end(), BitShift.getZExtValue(), BitPart::Unset); } return Result; @@ -2797,44 +2922,102 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, // If this is a logical 'and' with a mask that clears bits, recurse then // unset the appropriate bits. - if (I->getOpcode() == Instruction::And && - isa(I->getOperand(1))) { - APInt Bit(I->getType()->getPrimitiveSizeInBits(), 1); - const APInt &AndMask = cast(I->getOperand(1))->getValue(); + if (match(V, m_And(m_Value(X), m_APInt(C)))) { + const APInt &AndMask = *C; // Check that the mask allows a multiple of 8 bits for a bswap, for an // early exit. unsigned NumMaskedBits = AndMask.countPopulation(); - if (!MatchBitReversals && NumMaskedBits % 8 != 0) + if (!MatchBitReversals && (NumMaskedBits % 8) != 0) return Result; - auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps, - MatchBitReversals, BPS, Depth + 1); + const auto &Res = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); if (!Res) return Result; Result = Res; - for (unsigned i = 0; i < BitWidth; ++i, Bit <<= 1) + for (unsigned BitIdx = 0; BitIdx < BitWidth; ++BitIdx) // If the AndMask is zero for this bit, clear the bit. - if ((AndMask & Bit) == 0) - Result->Provenance[i] = BitPart::Unset; + if (AndMask[BitIdx] == 0) + Result->Provenance[BitIdx] = BitPart::Unset; return Result; } // If this is a zext instruction zero extend the result. - if (I->getOpcode() == Instruction::ZExt) { - auto &Res = collectBitParts(I->getOperand(0), MatchBSwaps, - MatchBitReversals, BPS, Depth + 1); + if (match(V, m_ZExt(m_Value(X)))) { + const auto &Res = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); if (!Res) return Result; Result = BitPart(Res->Provider, BitWidth); - auto NarrowBitWidth = - cast(cast(I)->getSrcTy())->getBitWidth(); - for (unsigned i = 0; i < NarrowBitWidth; ++i) - Result->Provenance[i] = Res->Provenance[i]; - for (unsigned i = NarrowBitWidth; i < BitWidth; ++i) - Result->Provenance[i] = BitPart::Unset; + auto NarrowBitWidth = X->getType()->getScalarSizeInBits(); + for (unsigned BitIdx = 0; BitIdx < NarrowBitWidth; ++BitIdx) + Result->Provenance[BitIdx] = Res->Provenance[BitIdx]; + for (unsigned BitIdx = NarrowBitWidth; BitIdx < BitWidth; ++BitIdx) + Result->Provenance[BitIdx] = BitPart::Unset; + return Result; + } + + // BITREVERSE - most likely due to us previous matching a partial + // bitreverse. + if (match(V, m_BitReverse(m_Value(X)))) { + const auto &Res = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); + if (!Res) + return Result; + + Result = BitPart(Res->Provider, BitWidth); + for (unsigned BitIdx = 0; BitIdx < BitWidth; ++BitIdx) + Result->Provenance[(BitWidth - 1) - BitIdx] = Res->Provenance[BitIdx]; + return Result; + } + + // BSWAP - most likely due to us previous matching a partial bswap. + if (match(V, m_BSwap(m_Value(X)))) { + const auto &Res = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); + if (!Res) + return Result; + + unsigned ByteWidth = BitWidth / 8; + Result = BitPart(Res->Provider, BitWidth); + for (unsigned ByteIdx = 0; ByteIdx < ByteWidth; ++ByteIdx) { + unsigned ByteBitOfs = ByteIdx * 8; + for (unsigned BitIdx = 0; BitIdx < 8; ++BitIdx) + Result->Provenance[(BitWidth - 8 - ByteBitOfs) + BitIdx] = + Res->Provenance[ByteBitOfs + BitIdx]; + } + return Result; + } + + // Funnel 'double' shifts take 3 operands, 2 inputs and the shift + // amount (modulo). + // fshl(X,Y,Z): (X << (Z % BW)) | (Y >> (BW - (Z % BW))) + // fshr(X,Y,Z): (X << (BW - (Z % BW))) | (Y >> (Z % BW)) + if (match(V, m_FShl(m_Value(X), m_Value(Y), m_APInt(C))) || + match(V, m_FShr(m_Value(X), m_Value(Y), m_APInt(C)))) { + // We can treat fshr as a fshl by flipping the modulo amount. + unsigned ModAmt = C->urem(BitWidth); + if (cast(I)->getIntrinsicID() == Intrinsic::fshr) + ModAmt = BitWidth - ModAmt; + + const auto &LHS = + collectBitParts(X, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); + const auto &RHS = + collectBitParts(Y, MatchBSwaps, MatchBitReversals, BPS, Depth + 1); + + // Check we have both sources and they are from the same provider. + if (!LHS || !RHS || !LHS->Provider || LHS->Provider != RHS->Provider) + return Result; + + unsigned StartBitRHS = BitWidth - ModAmt; + Result = BitPart(LHS->Provider, BitWidth); + for (unsigned BitIdx = 0; BitIdx < StartBitRHS; ++BitIdx) + Result->Provenance[BitIdx + ModAmt] = LHS->Provenance[BitIdx]; + for (unsigned BitIdx = 0; BitIdx < ModAmt; ++BitIdx) + Result->Provenance[BitIdx] = RHS->Provenance[BitIdx + StartBitRHS]; return Result; } } @@ -2842,8 +3025,8 @@ collectBitParts(Value *V, bool MatchBSwaps, bool MatchBitReversals, // Okay, we got to something that isn't a shift, 'or' or 'and'. This must be // the input value to the bswap/bitreverse. Result = BitPart(V, BitWidth); - for (unsigned i = 0; i < BitWidth; ++i) - Result->Provenance[i] = i; + for (unsigned BitIdx = 0; BitIdx < BitWidth; ++BitIdx) + Result->Provenance[BitIdx] = BitIdx; return Result; } @@ -2870,65 +3053,92 @@ bool llvm::recognizeBSwapOrBitReverseIdiom( return false; if (!MatchBSwaps && !MatchBitReversals) return false; - IntegerType *ITy = dyn_cast(I->getType()); - if (!ITy || ITy->getBitWidth() > 128) - return false; // Can't do vectors or integers > 128 bits. - unsigned BW = ITy->getBitWidth(); - - unsigned DemandedBW = BW; - IntegerType *DemandedTy = ITy; - if (I->hasOneUse()) { - if (TruncInst *Trunc = dyn_cast(I->user_back())) { - DemandedTy = cast(Trunc->getType()); - DemandedBW = DemandedTy->getBitWidth(); - } - } + Type *ITy = I->getType(); + if (!ITy->isIntOrIntVectorTy() || ITy->getScalarSizeInBits() > 128) + return false; // Can't do integer/elements > 128 bits. + + Type *DemandedTy = ITy; + if (I->hasOneUse()) + if (auto *Trunc = dyn_cast(I->user_back())) + DemandedTy = Trunc->getType(); // Try to find all the pieces corresponding to the bswap. std::map> BPS; auto Res = collectBitParts(I, MatchBSwaps, MatchBitReversals, BPS, 0); if (!Res) return false; - auto &BitProvenance = Res->Provenance; + ArrayRef BitProvenance = Res->Provenance; + assert(all_of(BitProvenance, + [](int8_t I) { return I == BitPart::Unset || 0 <= I; }) && + "Illegal bit provenance index"); + + // If the upper bits are zero, then attempt to perform as a truncated op. + if (BitProvenance.back() == BitPart::Unset) { + while (!BitProvenance.empty() && BitProvenance.back() == BitPart::Unset) + BitProvenance = BitProvenance.drop_back(); + if (BitProvenance.empty()) + return false; // TODO - handle null value? + DemandedTy = Type::getIntNTy(I->getContext(), BitProvenance.size()); + if (auto *IVecTy = dyn_cast(ITy)) + DemandedTy = VectorType::get(DemandedTy, IVecTy); + } + + // Check BitProvenance hasn't found a source larger than the result type. + unsigned DemandedBW = DemandedTy->getScalarSizeInBits(); + if (DemandedBW > ITy->getScalarSizeInBits()) + return false; // Now, is the bit permutation correct for a bswap or a bitreverse? We can // only byteswap values with an even number of bytes. - bool OKForBSwap = DemandedBW % 16 == 0, OKForBitReverse = true; - for (unsigned i = 0; i < DemandedBW; ++i) { - OKForBSwap &= - bitTransformIsCorrectForBSwap(BitProvenance[i], i, DemandedBW); - OKForBitReverse &= - bitTransformIsCorrectForBitReverse(BitProvenance[i], i, DemandedBW); + APInt DemandedMask = APInt::getAllOnesValue(DemandedBW); + bool OKForBSwap = MatchBSwaps && (DemandedBW % 16) == 0; + bool OKForBitReverse = MatchBitReversals; + for (unsigned BitIdx = 0; + (BitIdx < DemandedBW) && (OKForBSwap || OKForBitReverse); ++BitIdx) { + if (BitProvenance[BitIdx] == BitPart::Unset) { + DemandedMask.clearBit(BitIdx); + continue; + } + OKForBSwap &= bitTransformIsCorrectForBSwap(BitProvenance[BitIdx], BitIdx, + DemandedBW); + OKForBitReverse &= bitTransformIsCorrectForBitReverse(BitProvenance[BitIdx], + BitIdx, DemandedBW); } Intrinsic::ID Intrin; - if (OKForBSwap && MatchBSwaps) + if (OKForBSwap) Intrin = Intrinsic::bswap; - else if (OKForBitReverse && MatchBitReversals) + else if (OKForBitReverse) Intrin = Intrinsic::bitreverse; else return false; - if (ITy != DemandedTy) { - Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, DemandedTy); - Value *Provider = Res->Provider; - IntegerType *ProviderTy = cast(Provider->getType()); - // We may need to truncate the provider. - if (DemandedTy != ProviderTy) { - auto *Trunc = CastInst::Create(Instruction::Trunc, Provider, DemandedTy, - "trunc", I); - InsertedInsts.push_back(Trunc); - Provider = Trunc; - } - auto *CI = CallInst::Create(F, Provider, "rev", I); - InsertedInsts.push_back(CI); - auto *ExtInst = CastInst::Create(Instruction::ZExt, CI, ITy, "zext", I); + Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, DemandedTy); + Value *Provider = Res->Provider; + + // We may need to truncate the provider. + if (DemandedTy != Provider->getType()) { + auto *Trunc = + CastInst::CreateIntegerCast(Provider, DemandedTy, false, "trunc", I); + InsertedInsts.push_back(Trunc); + Provider = Trunc; + } + + Instruction *Result = CallInst::Create(F, Provider, "rev", I); + InsertedInsts.push_back(Result); + + if (!DemandedMask.isAllOnesValue()) { + auto *Mask = ConstantInt::get(DemandedTy, DemandedMask); + Result = BinaryOperator::Create(Instruction::And, Result, Mask, "mask", I); + InsertedInsts.push_back(Result); + } + + // We may need to zeroextend back to the result type. + if (ITy != Result->getType()) { + auto *ExtInst = CastInst::CreateIntegerCast(Result, ITy, false, "zext", I); InsertedInsts.push_back(ExtInst); - return true; } - Function *F = Intrinsic::getDeclaration(I->getModule(), Intrin, ITy); - InsertedInsts.push_back(CallInst::Create(F, Res->Provider, "rev", I)); return true; } @@ -3020,44 +3230,6 @@ bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) { } } -using AllocaForValueMapTy = DenseMap; -AllocaInst *llvm::findAllocaForValue(Value *V, - AllocaForValueMapTy &AllocaForValue) { - if (AllocaInst *AI = dyn_cast(V)) - return AI; - // See if we've already calculated (or started to calculate) alloca for a - // given value. - AllocaForValueMapTy::iterator I = AllocaForValue.find(V); - if (I != AllocaForValue.end()) - return I->second; - // Store 0 while we're calculating alloca for value V to avoid - // infinite recursion if the value references itself. - AllocaForValue[V] = nullptr; - AllocaInst *Res = nullptr; - if (CastInst *CI = dyn_cast(V)) - Res = findAllocaForValue(CI->getOperand(0), AllocaForValue); - else if (PHINode *PN = dyn_cast(V)) { - for (Value *IncValue : PN->incoming_values()) { - // Allow self-referencing phi-nodes. - if (IncValue == PN) - continue; - AllocaInst *IncValueAI = findAllocaForValue(IncValue, AllocaForValue); - // AI for incoming values should exist and should all be equal. - if (IncValueAI == nullptr || (Res != nullptr && IncValueAI != Res)) - return nullptr; - Res = IncValueAI; - } - } else if (GetElementPtrInst *EP = dyn_cast(V)) { - Res = findAllocaForValue(EP->getPointerOperand(), AllocaForValue); - } else { - LLVM_DEBUG(dbgs() << "Alloca search cancelled on unknown instruction: " - << *V << "\n"); - } - if (Res) - AllocaForValue[V] = Res; - return Res; -} - Value *llvm::invertCondition(Value *Condition) { // First: Check if it's a constant if (Constant *C = dyn_cast(Condition)) diff --git a/llvm/lib/Transforms/Utils/LoopPeel.cpp b/llvm/lib/Transforms/Utils/LoopPeel.cpp new file mode 100644 index 000000000000..cb5fee7d28e6 --- /dev/null +++ b/llvm/lib/Transforms/Utils/LoopPeel.cpp @@ -0,0 +1,847 @@ +//===- LoopPeel.cpp -------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Loop Peeling Utilities. +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/LoopPeel.h" +#include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/LoopIterator.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/ScalarEvolutionExpressions.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instruction.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/MDBuilder.h" +#include "llvm/IR/Metadata.h" +#include "llvm/IR/PatternMatch.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" +#include "llvm/Transforms/Utils/LoopSimplify.h" +#include "llvm/Transforms/Utils/LoopUtils.h" +#include "llvm/Transforms/Utils/UnrollLoop.h" +#include "llvm/Transforms/Utils/ValueMapper.h" +#include +#include +#include +#include + +using namespace llvm; +using namespace llvm::PatternMatch; + +#define DEBUG_TYPE "loop-peel" + +STATISTIC(NumPeeled, "Number of loops peeled"); + +static cl::opt UnrollPeelCount( + "unroll-peel-count", cl::Hidden, + cl::desc("Set the unroll peeling count, for testing purposes")); + +static cl::opt + UnrollAllowPeeling("unroll-allow-peeling", cl::init(true), cl::Hidden, + cl::desc("Allows loops to be peeled when the dynamic " + "trip count is known to be low.")); + +static cl::opt + UnrollAllowLoopNestsPeeling("unroll-allow-loop-nests-peeling", + cl::init(false), cl::Hidden, + cl::desc("Allows loop nests to be peeled.")); + +static cl::opt UnrollPeelMaxCount( + "unroll-peel-max-count", cl::init(7), cl::Hidden, + cl::desc("Max average trip count which will cause loop peeling.")); + +static cl::opt UnrollForcePeelCount( + "unroll-force-peel-count", cl::init(0), cl::Hidden, + cl::desc("Force a peel count regardless of profiling information.")); + +static cl::opt UnrollPeelMultiDeoptExit( + "unroll-peel-multi-deopt-exit", cl::init(true), cl::Hidden, + cl::desc("Allow peeling of loops with multiple deopt exits.")); + +static const char *PeeledCountMetaData = "llvm.loop.peeled.count"; + +// Designates that a Phi is estimated to become invariant after an "infinite" +// number of loop iterations (i.e. only may become an invariant if the loop is +// fully unrolled). +static const unsigned InfiniteIterationsToInvariance = + std::numeric_limits::max(); + +// Check whether we are capable of peeling this loop. +bool llvm::canPeel(Loop *L) { + // Make sure the loop is in simplified form + if (!L->isLoopSimplifyForm()) + return false; + + if (UnrollPeelMultiDeoptExit) { + SmallVector Exits; + L->getUniqueNonLatchExitBlocks(Exits); + + if (!Exits.empty()) { + // Latch's terminator is a conditional branch, Latch is exiting and + // all non Latch exits ends up with deoptimize. + const BasicBlock *Latch = L->getLoopLatch(); + const BranchInst *T = dyn_cast(Latch->getTerminator()); + return T && T->isConditional() && L->isLoopExiting(Latch) && + all_of(Exits, [](const BasicBlock *BB) { + return BB->getTerminatingDeoptimizeCall(); + }); + } + } + + // Only peel loops that contain a single exit + if (!L->getExitingBlock() || !L->getUniqueExitBlock()) + return false; + + // Don't try to peel loops where the latch is not the exiting block. + // This can be an indication of two different things: + // 1) The loop is not rotated. + // 2) The loop contains irreducible control flow that involves the latch. + const BasicBlock *Latch = L->getLoopLatch(); + if (Latch != L->getExitingBlock()) + return false; + + // Peeling is only supported if the latch is a branch. + if (!isa(Latch->getTerminator())) + return false; + + return true; +} + +// This function calculates the number of iterations after which the given Phi +// becomes an invariant. The pre-calculated values are memorized in the map. The +// function (shortcut is I) is calculated according to the following definition: +// Given %x = phi , ..., [%y, %back.edge]. +// If %y is a loop invariant, then I(%x) = 1. +// If %y is a Phi from the loop header, I(%x) = I(%y) + 1. +// Otherwise, I(%x) is infinite. +// TODO: Actually if %y is an expression that depends only on Phi %z and some +// loop invariants, we can estimate I(%x) = I(%z) + 1. The example +// looks like: +// %x = phi(0, %a), <-- becomes invariant starting from 3rd iteration. +// %y = phi(0, 5), +// %a = %y + 1. +static unsigned calculateIterationsToInvariance( + PHINode *Phi, Loop *L, BasicBlock *BackEdge, + SmallDenseMap &IterationsToInvariance) { + assert(Phi->getParent() == L->getHeader() && + "Non-loop Phi should not be checked for turning into invariant."); + assert(BackEdge == L->getLoopLatch() && "Wrong latch?"); + // If we already know the answer, take it from the map. + auto I = IterationsToInvariance.find(Phi); + if (I != IterationsToInvariance.end()) + return I->second; + + // Otherwise we need to analyze the input from the back edge. + Value *Input = Phi->getIncomingValueForBlock(BackEdge); + // Place infinity to map to avoid infinite recursion for cycled Phis. Such + // cycles can never stop on an invariant. + IterationsToInvariance[Phi] = InfiniteIterationsToInvariance; + unsigned ToInvariance = InfiniteIterationsToInvariance; + + if (L->isLoopInvariant(Input)) + ToInvariance = 1u; + else if (PHINode *IncPhi = dyn_cast(Input)) { + // Only consider Phis in header block. + if (IncPhi->getParent() != L->getHeader()) + return InfiniteIterationsToInvariance; + // If the input becomes an invariant after X iterations, then our Phi + // becomes an invariant after X + 1 iterations. + unsigned InputToInvariance = calculateIterationsToInvariance( + IncPhi, L, BackEdge, IterationsToInvariance); + if (InputToInvariance != InfiniteIterationsToInvariance) + ToInvariance = InputToInvariance + 1u; + } + + // If we found that this Phi lies in an invariant chain, update the map. + if (ToInvariance != InfiniteIterationsToInvariance) + IterationsToInvariance[Phi] = ToInvariance; + return ToInvariance; +} + +// Return the number of iterations to peel off that make conditions in the +// body true/false. For example, if we peel 2 iterations off the loop below, +// the condition i < 2 can be evaluated at compile time. +// for (i = 0; i < n; i++) +// if (i < 2) +// .. +// else +// .. +// } +static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount, + ScalarEvolution &SE) { + assert(L.isLoopSimplifyForm() && "Loop needs to be in loop simplify form"); + unsigned DesiredPeelCount = 0; + + for (auto *BB : L.blocks()) { + auto *BI = dyn_cast(BB->getTerminator()); + if (!BI || BI->isUnconditional()) + continue; + + // Ignore loop exit condition. + if (L.getLoopLatch() == BB) + continue; + + Value *Condition = BI->getCondition(); + Value *LeftVal, *RightVal; + CmpInst::Predicate Pred; + if (!match(Condition, m_ICmp(Pred, m_Value(LeftVal), m_Value(RightVal)))) + continue; + + const SCEV *LeftSCEV = SE.getSCEV(LeftVal); + const SCEV *RightSCEV = SE.getSCEV(RightVal); + + // Do not consider predicates that are known to be true or false + // independently of the loop iteration. + if (SE.isKnownPredicate(Pred, LeftSCEV, RightSCEV) || + SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), LeftSCEV, + RightSCEV)) + continue; + + // Check if we have a condition with one AddRec and one non AddRec + // expression. Normalize LeftSCEV to be the AddRec. + if (!isa(LeftSCEV)) { + if (isa(RightSCEV)) { + std::swap(LeftSCEV, RightSCEV); + Pred = ICmpInst::getSwappedPredicate(Pred); + } else + continue; + } + + const SCEVAddRecExpr *LeftAR = cast(LeftSCEV); + + // Avoid huge SCEV computations in the loop below, make sure we only + // consider AddRecs of the loop we are trying to peel. + if (!LeftAR->isAffine() || LeftAR->getLoop() != &L) + continue; + if (!(ICmpInst::isEquality(Pred) && LeftAR->hasNoSelfWrap()) && + !SE.getMonotonicPredicateType(LeftAR, Pred)) + continue; + + // Check if extending the current DesiredPeelCount lets us evaluate Pred + // or !Pred in the loop body statically. + unsigned NewPeelCount = DesiredPeelCount; + + const SCEV *IterVal = LeftAR->evaluateAtIteration( + SE.getConstant(LeftSCEV->getType(), NewPeelCount), SE); + + // If the original condition is not known, get the negated predicate + // (which holds on the else branch) and check if it is known. This allows + // us to peel of iterations that make the original condition false. + if (!SE.isKnownPredicate(Pred, IterVal, RightSCEV)) + Pred = ICmpInst::getInversePredicate(Pred); + + const SCEV *Step = LeftAR->getStepRecurrence(SE); + const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step); + auto PeelOneMoreIteration = [&IterVal, &NextIterVal, &SE, Step, + &NewPeelCount]() { + IterVal = NextIterVal; + NextIterVal = SE.getAddExpr(IterVal, Step); + NewPeelCount++; + }; + + auto CanPeelOneMoreIteration = [&NewPeelCount, &MaxPeelCount]() { + return NewPeelCount < MaxPeelCount; + }; + + while (CanPeelOneMoreIteration() && + SE.isKnownPredicate(Pred, IterVal, RightSCEV)) + PeelOneMoreIteration(); + + // With *that* peel count, does the predicate !Pred become known in the + // first iteration of the loop body after peeling? + if (!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal, + RightSCEV)) + continue; // If not, give up. + + // However, for equality comparisons, that isn't always sufficient to + // eliminate the comparsion in loop body, we may need to peel one more + // iteration. See if that makes !Pred become unknown again. + if (ICmpInst::isEquality(Pred) && + !SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), NextIterVal, + RightSCEV) && + !SE.isKnownPredicate(Pred, IterVal, RightSCEV) && + SE.isKnownPredicate(Pred, NextIterVal, RightSCEV)) { + if (!CanPeelOneMoreIteration()) + continue; // Need to peel one more iteration, but can't. Give up. + PeelOneMoreIteration(); // Great! + } + + DesiredPeelCount = std::max(DesiredPeelCount, NewPeelCount); + } + + return DesiredPeelCount; +} + +// Return the number of iterations we want to peel off. +void llvm::computePeelCount(Loop *L, unsigned LoopSize, + TargetTransformInfo::PeelingPreferences &PP, + unsigned &TripCount, ScalarEvolution &SE, + unsigned Threshold) { + assert(LoopSize > 0 && "Zero loop size is not allowed!"); + // Save the PP.PeelCount value set by the target in + // TTI.getPeelingPreferences or by the flag -unroll-peel-count. + unsigned TargetPeelCount = PP.PeelCount; + PP.PeelCount = 0; + if (!canPeel(L)) + return; + + // Only try to peel innermost loops by default. + // The constraint can be relaxed by the target in TTI.getUnrollingPreferences + // or by the flag -unroll-allow-loop-nests-peeling. + if (!PP.AllowLoopNestsPeeling && !L->isInnermost()) + return; + + // If the user provided a peel count, use that. + bool UserPeelCount = UnrollForcePeelCount.getNumOccurrences() > 0; + if (UserPeelCount) { + LLVM_DEBUG(dbgs() << "Force-peeling first " << UnrollForcePeelCount + << " iterations.\n"); + PP.PeelCount = UnrollForcePeelCount; + PP.PeelProfiledIterations = true; + return; + } + + // Skip peeling if it's disabled. + if (!PP.AllowPeeling) + return; + + unsigned AlreadyPeeled = 0; + if (auto Peeled = getOptionalIntLoopAttribute(L, PeeledCountMetaData)) + AlreadyPeeled = *Peeled; + // Stop if we already peeled off the maximum number of iterations. + if (AlreadyPeeled >= UnrollPeelMaxCount) + return; + + // Here we try to get rid of Phis which become invariants after 1, 2, ..., N + // iterations of the loop. For this we compute the number for iterations after + // which every Phi is guaranteed to become an invariant, and try to peel the + // maximum number of iterations among these values, thus turning all those + // Phis into invariants. + // First, check that we can peel at least one iteration. + if (2 * LoopSize <= Threshold && UnrollPeelMaxCount > 0) { + // Store the pre-calculated values here. + SmallDenseMap IterationsToInvariance; + // Now go through all Phis to calculate their the number of iterations they + // need to become invariants. + // Start the max computation with the UP.PeelCount value set by the target + // in TTI.getUnrollingPreferences or by the flag -unroll-peel-count. + unsigned DesiredPeelCount = TargetPeelCount; + BasicBlock *BackEdge = L->getLoopLatch(); + assert(BackEdge && "Loop is not in simplified form?"); + for (auto BI = L->getHeader()->begin(); isa(&*BI); ++BI) { + PHINode *Phi = cast(&*BI); + unsigned ToInvariance = calculateIterationsToInvariance( + Phi, L, BackEdge, IterationsToInvariance); + if (ToInvariance != InfiniteIterationsToInvariance) + DesiredPeelCount = std::max(DesiredPeelCount, ToInvariance); + } + + // Pay respect to limitations implied by loop size and the max peel count. + unsigned MaxPeelCount = UnrollPeelMaxCount; + MaxPeelCount = std::min(MaxPeelCount, Threshold / LoopSize - 1); + + DesiredPeelCount = std::max(DesiredPeelCount, + countToEliminateCompares(*L, MaxPeelCount, SE)); + + if (DesiredPeelCount > 0) { + DesiredPeelCount = std::min(DesiredPeelCount, MaxPeelCount); + // Consider max peel count limitation. + assert(DesiredPeelCount > 0 && "Wrong loop size estimation?"); + if (DesiredPeelCount + AlreadyPeeled <= UnrollPeelMaxCount) { + LLVM_DEBUG(dbgs() << "Peel " << DesiredPeelCount + << " iteration(s) to turn" + << " some Phis into invariants.\n"); + PP.PeelCount = DesiredPeelCount; + PP.PeelProfiledIterations = false; + return; + } + } + } + + // Bail if we know the statically calculated trip count. + // In this case we rather prefer partial unrolling. + if (TripCount) + return; + + // Do not apply profile base peeling if it is disabled. + if (!PP.PeelProfiledIterations) + return; + // If we don't know the trip count, but have reason to believe the average + // trip count is low, peeling should be beneficial, since we will usually + // hit the peeled section. + // We only do this in the presence of profile information, since otherwise + // our estimates of the trip count are not reliable enough. + if (L->getHeader()->getParent()->hasProfileData()) { + Optional PeelCount = getLoopEstimatedTripCount(L); + if (!PeelCount) + return; + + LLVM_DEBUG(dbgs() << "Profile-based estimated trip count is " << *PeelCount + << "\n"); + + if (*PeelCount) { + if ((*PeelCount + AlreadyPeeled <= UnrollPeelMaxCount) && + (LoopSize * (*PeelCount + 1) <= Threshold)) { + LLVM_DEBUG(dbgs() << "Peeling first " << *PeelCount + << " iterations.\n"); + PP.PeelCount = *PeelCount; + return; + } + LLVM_DEBUG(dbgs() << "Requested peel count: " << *PeelCount << "\n"); + LLVM_DEBUG(dbgs() << "Already peel count: " << AlreadyPeeled << "\n"); + LLVM_DEBUG(dbgs() << "Max peel count: " << UnrollPeelMaxCount << "\n"); + LLVM_DEBUG(dbgs() << "Peel cost: " << LoopSize * (*PeelCount + 1) + << "\n"); + LLVM_DEBUG(dbgs() << "Max peel cost: " << Threshold << "\n"); + } + } +} + +/// Update the branch weights of the latch of a peeled-off loop +/// iteration. +/// This sets the branch weights for the latch of the recently peeled off loop +/// iteration correctly. +/// Let F is a weight of the edge from latch to header. +/// Let E is a weight of the edge from latch to exit. +/// F/(F+E) is a probability to go to loop and E/(F+E) is a probability to +/// go to exit. +/// Then, Estimated TripCount = F / E. +/// For I-th (counting from 0) peeled off iteration we set the the weights for +/// the peeled latch as (TC - I, 1). It gives us reasonable distribution, +/// The probability to go to exit 1/(TC-I) increases. At the same time +/// the estimated trip count of remaining loop reduces by I. +/// To avoid dealing with division rounding we can just multiple both part +/// of weights to E and use weight as (F - I * E, E). +/// +/// \param Header The copy of the header block that belongs to next iteration. +/// \param LatchBR The copy of the latch branch that belongs to this iteration. +/// \param[in,out] FallThroughWeight The weight of the edge from latch to +/// header before peeling (in) and after peeled off one iteration (out). +static void updateBranchWeights(BasicBlock *Header, BranchInst *LatchBR, + uint64_t ExitWeight, + uint64_t &FallThroughWeight) { + // FallThroughWeight is 0 means that there is no branch weights on original + // latch block or estimated trip count is zero. + if (!FallThroughWeight) + return; + + unsigned HeaderIdx = (LatchBR->getSuccessor(0) == Header ? 0 : 1); + MDBuilder MDB(LatchBR->getContext()); + MDNode *WeightNode = + HeaderIdx ? MDB.createBranchWeights(ExitWeight, FallThroughWeight) + : MDB.createBranchWeights(FallThroughWeight, ExitWeight); + LatchBR->setMetadata(LLVMContext::MD_prof, WeightNode); + FallThroughWeight = + FallThroughWeight > ExitWeight ? FallThroughWeight - ExitWeight : 1; +} + +/// Initialize the weights. +/// +/// \param Header The header block. +/// \param LatchBR The latch branch. +/// \param[out] ExitWeight The weight of the edge from Latch to Exit. +/// \param[out] FallThroughWeight The weight of the edge from Latch to Header. +static void initBranchWeights(BasicBlock *Header, BranchInst *LatchBR, + uint64_t &ExitWeight, + uint64_t &FallThroughWeight) { + uint64_t TrueWeight, FalseWeight; + if (!LatchBR->extractProfMetadata(TrueWeight, FalseWeight)) + return; + unsigned HeaderIdx = LatchBR->getSuccessor(0) == Header ? 0 : 1; + ExitWeight = HeaderIdx ? TrueWeight : FalseWeight; + FallThroughWeight = HeaderIdx ? FalseWeight : TrueWeight; +} + +/// Update the weights of original Latch block after peeling off all iterations. +/// +/// \param Header The header block. +/// \param LatchBR The latch branch. +/// \param ExitWeight The weight of the edge from Latch to Exit. +/// \param FallThroughWeight The weight of the edge from Latch to Header. +static void fixupBranchWeights(BasicBlock *Header, BranchInst *LatchBR, + uint64_t ExitWeight, + uint64_t FallThroughWeight) { + // FallThroughWeight is 0 means that there is no branch weights on original + // latch block or estimated trip count is zero. + if (!FallThroughWeight) + return; + + // Sets the branch weights on the loop exit. + MDBuilder MDB(LatchBR->getContext()); + unsigned HeaderIdx = LatchBR->getSuccessor(0) == Header ? 0 : 1; + MDNode *WeightNode = + HeaderIdx ? MDB.createBranchWeights(ExitWeight, FallThroughWeight) + : MDB.createBranchWeights(FallThroughWeight, ExitWeight); + LatchBR->setMetadata(LLVMContext::MD_prof, WeightNode); +} + +/// Clones the body of the loop L, putting it between \p InsertTop and \p +/// InsertBot. +/// \param IterNumber The serial number of the iteration currently being +/// peeled off. +/// \param ExitEdges The exit edges of the original loop. +/// \param[out] NewBlocks A list of the blocks in the newly created clone +/// \param[out] VMap The value map between the loop and the new clone. +/// \param LoopBlocks A helper for DFS-traversal of the loop. +/// \param LVMap A value-map that maps instructions from the original loop to +/// instructions in the last peeled-off iteration. +static void cloneLoopBlocks( + Loop *L, unsigned IterNumber, BasicBlock *InsertTop, BasicBlock *InsertBot, + SmallVectorImpl> &ExitEdges, + SmallVectorImpl &NewBlocks, LoopBlocksDFS &LoopBlocks, + ValueToValueMapTy &VMap, ValueToValueMapTy &LVMap, DominatorTree *DT, + LoopInfo *LI) { + BasicBlock *Header = L->getHeader(); + BasicBlock *Latch = L->getLoopLatch(); + BasicBlock *PreHeader = L->getLoopPreheader(); + + Function *F = Header->getParent(); + LoopBlocksDFS::RPOIterator BlockBegin = LoopBlocks.beginRPO(); + LoopBlocksDFS::RPOIterator BlockEnd = LoopBlocks.endRPO(); + Loop *ParentLoop = L->getParentLoop(); + + // For each block in the original loop, create a new copy, + // and update the value map with the newly created values. + for (LoopBlocksDFS::RPOIterator BB = BlockBegin; BB != BlockEnd; ++BB) { + BasicBlock *NewBB = CloneBasicBlock(*BB, VMap, ".peel", F); + NewBlocks.push_back(NewBB); + + // If an original block is an immediate child of the loop L, its copy + // is a child of a ParentLoop after peeling. If a block is a child of + // a nested loop, it is handled in the cloneLoop() call below. + if (ParentLoop && LI->getLoopFor(*BB) == L) + ParentLoop->addBasicBlockToLoop(NewBB, *LI); + + VMap[*BB] = NewBB; + + // If dominator tree is available, insert nodes to represent cloned blocks. + if (DT) { + if (Header == *BB) + DT->addNewBlock(NewBB, InsertTop); + else { + DomTreeNode *IDom = DT->getNode(*BB)->getIDom(); + // VMap must contain entry for IDom, as the iteration order is RPO. + DT->addNewBlock(NewBB, cast(VMap[IDom->getBlock()])); + } + } + } + + // Recursively create the new Loop objects for nested loops, if any, + // to preserve LoopInfo. + for (Loop *ChildLoop : *L) { + cloneLoop(ChildLoop, ParentLoop, VMap, LI, nullptr); + } + + // Hook-up the control flow for the newly inserted blocks. + // The new header is hooked up directly to the "top", which is either + // the original loop preheader (for the first iteration) or the previous + // iteration's exiting block (for every other iteration) + InsertTop->getTerminator()->setSuccessor(0, cast(VMap[Header])); + + // Similarly, for the latch: + // The original exiting edge is still hooked up to the loop exit. + // The backedge now goes to the "bottom", which is either the loop's real + // header (for the last peeled iteration) or the copied header of the next + // iteration (for every other iteration) + BasicBlock *NewLatch = cast(VMap[Latch]); + BranchInst *LatchBR = cast(NewLatch->getTerminator()); + for (unsigned idx = 0, e = LatchBR->getNumSuccessors(); idx < e; ++idx) + if (LatchBR->getSuccessor(idx) == Header) { + LatchBR->setSuccessor(idx, InsertBot); + break; + } + if (DT) + DT->changeImmediateDominator(InsertBot, NewLatch); + + // The new copy of the loop body starts with a bunch of PHI nodes + // that pick an incoming value from either the preheader, or the previous + // loop iteration. Since this copy is no longer part of the loop, we + // resolve this statically: + // For the first iteration, we use the value from the preheader directly. + // For any other iteration, we replace the phi with the value generated by + // the immediately preceding clone of the loop body (which represents + // the previous iteration). + for (BasicBlock::iterator I = Header->begin(); isa(I); ++I) { + PHINode *NewPHI = cast(VMap[&*I]); + if (IterNumber == 0) { + VMap[&*I] = NewPHI->getIncomingValueForBlock(PreHeader); + } else { + Value *LatchVal = NewPHI->getIncomingValueForBlock(Latch); + Instruction *LatchInst = dyn_cast(LatchVal); + if (LatchInst && L->contains(LatchInst)) + VMap[&*I] = LVMap[LatchInst]; + else + VMap[&*I] = LatchVal; + } + cast(VMap[Header])->getInstList().erase(NewPHI); + } + + // Fix up the outgoing values - we need to add a value for the iteration + // we've just created. Note that this must happen *after* the incoming + // values are adjusted, since the value going out of the latch may also be + // a value coming into the header. + for (auto Edge : ExitEdges) + for (PHINode &PHI : Edge.second->phis()) { + Value *LatchVal = PHI.getIncomingValueForBlock(Edge.first); + Instruction *LatchInst = dyn_cast(LatchVal); + if (LatchInst && L->contains(LatchInst)) + LatchVal = VMap[LatchVal]; + PHI.addIncoming(LatchVal, cast(VMap[Edge.first])); + } + + // LastValueMap is updated with the values for the current loop + // which are used the next time this function is called. + for (auto KV : VMap) + LVMap[KV.first] = KV.second; +} + +TargetTransformInfo::PeelingPreferences llvm::gatherPeelingPreferences( + Loop *L, ScalarEvolution &SE, const TargetTransformInfo &TTI, + Optional UserAllowPeeling, + Optional UserAllowProfileBasedPeeling, bool UnrollingSpecficValues) { + TargetTransformInfo::PeelingPreferences PP; + + // Set the default values. + PP.PeelCount = 0; + PP.AllowPeeling = true; + PP.AllowLoopNestsPeeling = false; + PP.PeelProfiledIterations = true; + + // Get the target specifc values. + TTI.getPeelingPreferences(L, SE, PP); + + // User specified values using cl::opt. + if (UnrollingSpecficValues) { + if (UnrollPeelCount.getNumOccurrences() > 0) + PP.PeelCount = UnrollPeelCount; + if (UnrollAllowPeeling.getNumOccurrences() > 0) + PP.AllowPeeling = UnrollAllowPeeling; + if (UnrollAllowLoopNestsPeeling.getNumOccurrences() > 0) + PP.AllowLoopNestsPeeling = UnrollAllowLoopNestsPeeling; + } + + // User specifed values provided by argument. + if (UserAllowPeeling.hasValue()) + PP.AllowPeeling = *UserAllowPeeling; + if (UserAllowProfileBasedPeeling.hasValue()) + PP.PeelProfiledIterations = *UserAllowProfileBasedPeeling; + + return PP; +} + +/// Peel off the first \p PeelCount iterations of loop \p L. +/// +/// Note that this does not peel them off as a single straight-line block. +/// Rather, each iteration is peeled off separately, and needs to check the +/// exit condition. +/// For loops that dynamically execute \p PeelCount iterations or less +/// this provides a benefit, since the peeled off iterations, which account +/// for the bulk of dynamic execution, can be further simplified by scalar +/// optimizations. +bool llvm::peelLoop(Loop *L, unsigned PeelCount, LoopInfo *LI, + ScalarEvolution *SE, DominatorTree *DT, AssumptionCache *AC, + bool PreserveLCSSA) { + assert(PeelCount > 0 && "Attempt to peel out zero iterations?"); + assert(canPeel(L) && "Attempt to peel a loop which is not peelable?"); + + LoopBlocksDFS LoopBlocks(L); + LoopBlocks.perform(LI); + + BasicBlock *Header = L->getHeader(); + BasicBlock *PreHeader = L->getLoopPreheader(); + BasicBlock *Latch = L->getLoopLatch(); + SmallVector, 4> ExitEdges; + L->getExitEdges(ExitEdges); + + DenseMap ExitIDom; + if (DT) { + // We'd like to determine the idom of exit block after peeling one + // iteration. + // Let Exit is exit block. + // Let ExitingSet - is a set of predecessors of Exit block. They are exiting + // blocks. + // Let Latch' and ExitingSet' are copies after a peeling. + // We'd like to find an idom'(Exit) - idom of Exit after peeling. + // It is an evident that idom'(Exit) will be the nearest common dominator + // of ExitingSet and ExitingSet'. + // idom(Exit) is a nearest common dominator of ExitingSet. + // idom(Exit)' is a nearest common dominator of ExitingSet'. + // Taking into account that we have a single Latch, Latch' will dominate + // Header and idom(Exit). + // So the idom'(Exit) is nearest common dominator of idom(Exit)' and Latch'. + // All these basic blocks are in the same loop, so what we find is + // (nearest common dominator of idom(Exit) and Latch)'. + // In the loop below we remember nearest common dominator of idom(Exit) and + // Latch to update idom of Exit later. + assert(L->hasDedicatedExits() && "No dedicated exits?"); + for (auto Edge : ExitEdges) { + if (ExitIDom.count(Edge.second)) + continue; + BasicBlock *BB = DT->findNearestCommonDominator( + DT->getNode(Edge.second)->getIDom()->getBlock(), Latch); + assert(L->contains(BB) && "IDom is not in a loop"); + ExitIDom[Edge.second] = BB; + } + } + + Function *F = Header->getParent(); + + // Set up all the necessary basic blocks. It is convenient to split the + // preheader into 3 parts - two blocks to anchor the peeled copy of the loop + // body, and a new preheader for the "real" loop. + + // Peeling the first iteration transforms. + // + // PreHeader: + // ... + // Header: + // LoopBody + // If (cond) goto Header + // Exit: + // + // into + // + // InsertTop: + // LoopBody + // If (!cond) goto Exit + // InsertBot: + // NewPreHeader: + // ... + // Header: + // LoopBody + // If (cond) goto Header + // Exit: + // + // Each following iteration will split the current bottom anchor in two, + // and put the new copy of the loop body between these two blocks. That is, + // after peeling another iteration from the example above, we'll split + // InsertBot, and get: + // + // InsertTop: + // LoopBody + // If (!cond) goto Exit + // InsertBot: + // LoopBody + // If (!cond) goto Exit + // InsertBot.next: + // NewPreHeader: + // ... + // Header: + // LoopBody + // If (cond) goto Header + // Exit: + + BasicBlock *InsertTop = SplitEdge(PreHeader, Header, DT, LI); + BasicBlock *InsertBot = + SplitBlock(InsertTop, InsertTop->getTerminator(), DT, LI); + BasicBlock *NewPreHeader = + SplitBlock(InsertBot, InsertBot->getTerminator(), DT, LI); + + InsertTop->setName(Header->getName() + ".peel.begin"); + InsertBot->setName(Header->getName() + ".peel.next"); + NewPreHeader->setName(PreHeader->getName() + ".peel.newph"); + + ValueToValueMapTy LVMap; + + // If we have branch weight information, we'll want to update it for the + // newly created branches. + BranchInst *LatchBR = + cast(cast(Latch)->getTerminator()); + uint64_t ExitWeight = 0, FallThroughWeight = 0; + initBranchWeights(Header, LatchBR, ExitWeight, FallThroughWeight); + + // For each peeled-off iteration, make a copy of the loop. + for (unsigned Iter = 0; Iter < PeelCount; ++Iter) { + SmallVector NewBlocks; + ValueToValueMapTy VMap; + + cloneLoopBlocks(L, Iter, InsertTop, InsertBot, ExitEdges, NewBlocks, + LoopBlocks, VMap, LVMap, DT, LI); + + // Remap to use values from the current iteration instead of the + // previous one. + remapInstructionsInBlocks(NewBlocks, VMap); + + if (DT) { + // Latches of the cloned loops dominate over the loop exit, so idom of the + // latter is the first cloned loop body, as original PreHeader dominates + // the original loop body. + if (Iter == 0) + for (auto Exit : ExitIDom) + DT->changeImmediateDominator(Exit.first, + cast(LVMap[Exit.second])); +#ifdef EXPENSIVE_CHECKS + assert(DT->verify(DominatorTree::VerificationLevel::Fast)); +#endif + } + + auto *LatchBRCopy = cast(VMap[LatchBR]); + updateBranchWeights(InsertBot, LatchBRCopy, ExitWeight, FallThroughWeight); + // Remove Loop metadata from the latch branch instruction + // because it is not the Loop's latch branch anymore. + LatchBRCopy->setMetadata(LLVMContext::MD_loop, nullptr); + + InsertTop = InsertBot; + InsertBot = SplitBlock(InsertBot, InsertBot->getTerminator(), DT, LI); + InsertBot->setName(Header->getName() + ".peel.next"); + + F->getBasicBlockList().splice(InsertTop->getIterator(), + F->getBasicBlockList(), + NewBlocks[0]->getIterator(), F->end()); + } + + // Now adjust the phi nodes in the loop header to get their initial values + // from the last peeled-off iteration instead of the preheader. + for (BasicBlock::iterator I = Header->begin(); isa(I); ++I) { + PHINode *PHI = cast(I); + Value *NewVal = PHI->getIncomingValueForBlock(Latch); + Instruction *LatchInst = dyn_cast(NewVal); + if (LatchInst && L->contains(LatchInst)) + NewVal = LVMap[LatchInst]; + + PHI->setIncomingValueForBlock(NewPreHeader, NewVal); + } + + fixupBranchWeights(Header, LatchBR, ExitWeight, FallThroughWeight); + + // Update Metadata for count of peeled off iterations. + unsigned AlreadyPeeled = 0; + if (auto Peeled = getOptionalIntLoopAttribute(L, PeeledCountMetaData)) + AlreadyPeeled = *Peeled; + addStringMetadataToLoop(L, PeeledCountMetaData, AlreadyPeeled + PeelCount); + + if (Loop *ParentLoop = L->getParentLoop()) + L = ParentLoop; + + // We modified the loop, update SE. + SE->forgetTopmostLoop(L); + + // Finally DomtTree must be correct. + assert(DT->verify(DominatorTree::VerificationLevel::Fast)); + + // FIXME: Incrementally update loop-simplify + simplifyLoop(L, DT, LI, SE, AC, nullptr, PreserveLCSSA); + + NumPeeled++; + + return true; +} diff --git a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp index 8804bba975b6..b678efdc8d88 100644 --- a/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopRotationUtils.cpp @@ -12,7 +12,6 @@ #include "llvm/Transforms/Utils/LoopRotationUtils.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/CodeMetrics.h" @@ -36,6 +35,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" +#include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/SSAUpdater.h" @@ -44,6 +44,8 @@ using namespace llvm; #define DEBUG_TYPE "loop-rotate" +STATISTIC(NumNotRotatedDueToHeaderSize, + "Number of loops not rotated due to the header size"); STATISTIC(NumRotated, "Number of loops rotated"); static cl::opt @@ -64,15 +66,17 @@ class LoopRotate { const SimplifyQuery &SQ; bool RotationOnly; bool IsUtilMode; + bool PrepareForLTO; public: LoopRotate(unsigned MaxHeaderSize, LoopInfo *LI, const TargetTransformInfo *TTI, AssumptionCache *AC, DominatorTree *DT, ScalarEvolution *SE, MemorySSAUpdater *MSSAU, - const SimplifyQuery &SQ, bool RotationOnly, bool IsUtilMode) + const SimplifyQuery &SQ, bool RotationOnly, bool IsUtilMode, + bool PrepareForLTO) : MaxHeaderSize(MaxHeaderSize), LI(LI), TTI(TTI), AC(AC), DT(DT), SE(SE), MSSAU(MSSAU), SQ(SQ), RotationOnly(RotationOnly), - IsUtilMode(IsUtilMode) {} + IsUtilMode(IsUtilMode), PrepareForLTO(PrepareForLTO) {} bool processLoop(Loop *L); private: @@ -300,7 +304,7 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { CodeMetrics::collectEphemeralValues(L, AC, EphValues); CodeMetrics Metrics; - Metrics.analyzeBasicBlock(OrigHeader, *TTI, EphValues); + Metrics.analyzeBasicBlock(OrigHeader, *TTI, EphValues, PrepareForLTO); if (Metrics.notDuplicatable) { LLVM_DEBUG( dbgs() << "LoopRotation: NOT rotating - contains non-duplicatable" @@ -320,8 +324,14 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { << " instructions, which is more than the threshold (" << MaxHeaderSize << " instructions): "; L->dump()); + ++NumNotRotatedDueToHeaderSize; return Rotated; } + + // When preparing for LTO, avoid rotating loops with calls that could be + // inlined during the LTO stage. + if (PrepareForLTO && Metrics.NumInlineCandidates > 0) + return Rotated; } // Now, this loop is suitable for rotation. @@ -391,6 +401,14 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { break; } + // Remember the local noalias scope declarations in the header. After the + // rotation, they must be duplicated and the scope must be cloned. This + // avoids unwanted interaction across iterations. + SmallVector NoAliasDeclInstructions; + for (Instruction &I : *OrigHeader) + if (auto *Decl = dyn_cast(&I)) + NoAliasDeclInstructions.push_back(Decl); + while (I != E) { Instruction *Inst = &*I++; @@ -451,6 +469,69 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { } } + if (!NoAliasDeclInstructions.empty()) { + // There are noalias scope declarations: + // (general): + // Original: OrigPre { OrigHeader NewHeader ... Latch } + // after: (OrigPre+OrigHeader') { NewHeader ... Latch OrigHeader } + // + // with D: llvm.experimental.noalias.scope.decl, + // U: !noalias or !alias.scope depending on D + // ... { D U1 U2 } can transform into: + // (0) : ... { D U1 U2 } // no relevant rotation for this part + // (1) : ... D' { U1 U2 D } // D is part of OrigHeader + // (2) : ... D' U1' { U2 D U1 } // D, U1 are part of OrigHeader + // + // We now want to transform: + // (1) -> : ... D' { D U1 U2 D'' } + // (2) -> : ... D' U1' { D U2 D'' U1'' } + // D: original llvm.experimental.noalias.scope.decl + // D', U1': duplicate with replaced scopes + // D'', U1'': different duplicate with replaced scopes + // This ensures a safe fallback to 'may_alias' introduced by the rotate, + // as U1'' and U1' scopes will not be compatible wrt to the local restrict + + // Clone the llvm.experimental.noalias.decl again for the NewHeader. + Instruction *NewHeaderInsertionPoint = &(*NewHeader->getFirstNonPHI()); + for (NoAliasScopeDeclInst *NAD : NoAliasDeclInstructions) { + LLVM_DEBUG(dbgs() << " Cloning llvm.experimental.noalias.scope.decl:" + << *NAD << "\n"); + Instruction *NewNAD = NAD->clone(); + NewNAD->insertBefore(NewHeaderInsertionPoint); + } + + // Scopes must now be duplicated, once for OrigHeader and once for + // OrigPreHeader'. + { + auto &Context = NewHeader->getContext(); + + SmallVector NoAliasDeclScopes; + for (NoAliasScopeDeclInst *NAD : NoAliasDeclInstructions) + NoAliasDeclScopes.push_back(NAD->getScopeList()); + + LLVM_DEBUG(dbgs() << " Updating OrigHeader scopes\n"); + cloneAndAdaptNoAliasScopes(NoAliasDeclScopes, {OrigHeader}, Context, + "h.rot"); + LLVM_DEBUG(OrigHeader->dump()); + + // Keep the compile time impact low by only adapting the inserted block + // of instructions in the OrigPreHeader. This might result in slightly + // more aliasing between these instructions and those that were already + // present, but it will be much faster when the original PreHeader is + // large. + LLVM_DEBUG(dbgs() << " Updating part of OrigPreheader scopes\n"); + auto *FirstDecl = + cast(ValueMap[*NoAliasDeclInstructions.begin()]); + auto *LastInst = &OrigPreheader->back(); + cloneAndAdaptNoAliasScopes(NoAliasDeclScopes, FirstDecl, LastInst, + Context, "pre.rot"); + LLVM_DEBUG(OrigPreheader->dump()); + + LLVM_DEBUG(dbgs() << " Updated NewHeader:\n"); + LLVM_DEBUG(NewHeader->dump()); + } + } + // Along with all the other instructions, we just cloned OrigHeader's // terminator into OrigPreHeader. Fix up the PHI nodes in each of OrigHeader's // successors by duplicating their incoming values for OrigHeader. @@ -496,12 +577,13 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { Updates.push_back({DominatorTree::Insert, OrigPreheader, Exit}); Updates.push_back({DominatorTree::Insert, OrigPreheader, NewHeader}); Updates.push_back({DominatorTree::Delete, OrigPreheader, OrigHeader}); - DT->applyUpdates(Updates); if (MSSAU) { - MSSAU->applyUpdates(Updates, *DT); + MSSAU->applyUpdates(Updates, *DT, /*UpdateDT=*/true); if (VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); + } else { + DT->applyUpdates(Updates); } } @@ -575,7 +657,10 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) { // connected by an unconditional branch. This is just a cleanup so the // emitted code isn't too gross in this common case. DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); - MergeBlockIntoPredecessor(OrigHeader, &DTU, LI, MSSAU); + BasicBlock *PredBB = OrigHeader->getUniquePredecessor(); + bool DidMerge = MergeBlockIntoPredecessor(OrigHeader, &DTU, LI, MSSAU); + if (DidMerge) + RemoveRedundantDbgInstrs(PredBB); if (MSSAU && VerifyMemorySSA) MSSAU->getMemorySSA()->verifyMemorySSA(); @@ -739,13 +824,8 @@ bool llvm::LoopRotation(Loop *L, LoopInfo *LI, const TargetTransformInfo *TTI, ScalarEvolution *SE, MemorySSAUpdater *MSSAU, const SimplifyQuery &SQ, bool RotationOnly = true, unsigned Threshold = unsigned(-1), - bool IsUtilMode = true) { - if (MSSAU && VerifyMemorySSA) - MSSAU->getMemorySSA()->verifyMemorySSA(); + bool IsUtilMode = true, bool PrepareForLTO) { LoopRotate LR(Threshold, LI, TTI, AC, DT, SE, MSSAU, SQ, RotationOnly, - IsUtilMode); - if (MSSAU && VerifyMemorySSA) - MSSAU->getMemorySSA()->verifyMemorySSA(); - + IsUtilMode, PrepareForLTO); return LR.processLoop(L); } diff --git a/llvm/lib/Transforms/Utils/LoopSimplify.cpp b/llvm/lib/Transforms/Utils/LoopSimplify.cpp index a8445e94e55a..2e104334ad96 100644 --- a/llvm/lib/Transforms/Utils/LoopSimplify.cpp +++ b/llvm/lib/Transforms/Utils/LoopSimplify.cpp @@ -163,7 +163,7 @@ BasicBlock *llvm::InsertPreheaderForLoop(Loop *L, DominatorTree *DT, /// if it's not already in there. Stop predecessor traversal when we reach /// StopBlock. static void addBlockAndPredsToSet(BasicBlock *InputBB, BasicBlock *StopBlock, - std::set &Blocks) { + SmallPtrSetImpl &Blocks) { SmallVector Worklist; Worklist.push_back(InputBB); do { @@ -171,10 +171,7 @@ static void addBlockAndPredsToSet(BasicBlock *InputBB, BasicBlock *StopBlock, if (Blocks.insert(BB).second && BB != StopBlock) // If BB is not already processed and it is not a stop block then // insert its predecessor in the work list - for (pred_iterator I = pred_begin(BB), E = pred_end(BB); I != E; ++I) { - BasicBlock *WBB = *I; - Worklist.push_back(WBB); - } + append_range(Worklist, predecessors(BB)); } while (!Worklist.empty()); } @@ -308,9 +305,8 @@ static Loop *separateNestedLoop(Loop *L, BasicBlock *Preheader, // Determine which blocks should stay in L and which should be moved out to // the Outer loop now. - std::set BlocksInL; - for (pred_iterator PI=pred_begin(Header), E = pred_end(Header); PI!=E; ++PI) { - BasicBlock *P = *PI; + SmallPtrSet BlocksInL; + for (BasicBlock *P : predecessors(Header)) { if (DT->dominates(Header, P)) addBlockAndPredsToSet(P, Header, BlocksInL); } @@ -683,7 +679,7 @@ ReprocessLoop: // The block has now been cleared of all instructions except for // a comparison and a conditional branch. SimplifyCFG may be able // to fold it now. - if (!FoldBranchToCommonDest(BI, MSSAU)) + if (!FoldBranchToCommonDest(BI, /*DTU=*/nullptr, MSSAU)) continue; // Success. The block is now dead, so remove it from the loop, @@ -691,7 +687,7 @@ ReprocessLoop: LLVM_DEBUG(dbgs() << "LoopSimplify: Eliminating exiting block " << ExitingBlock->getName() << "\n"); - assert(pred_begin(ExitingBlock) == pred_end(ExitingBlock)); + assert(pred_empty(ExitingBlock)); Changed = true; LI->removeBlock(ExitingBlock); @@ -836,8 +832,8 @@ bool LoopSimplify::runOnFunction(Function &F) { bool PreserveLCSSA = mustPreserveAnalysisID(LCSSAID); // Simplify each loop nest in the function. - for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I) - Changed |= simplifyLoop(*I, DT, LI, SE, AC, MSSAU.get(), PreserveLCSSA); + for (auto *L : *LI) + Changed |= simplifyLoop(L, DT, LI, SE, AC, MSSAU.get(), PreserveLCSSA); #ifndef NDEBUG if (PreserveLCSSA) { @@ -866,9 +862,9 @@ PreservedAnalyses LoopSimplifyPass::run(Function &F, // Note that we don't preserve LCSSA in the new PM, if you need it run LCSSA // after simplifying the loops. MemorySSA is preserved if it exists. - for (LoopInfo::iterator I = LI->begin(), E = LI->end(); I != E; ++I) + for (auto *L : *LI) Changed |= - simplifyLoop(*I, DT, LI, SE, AC, MSSAU.get(), /*PreserveLCSSA*/ false); + simplifyLoop(L, DT, LI, SE, AC, MSSAU.get(), /*PreserveLCSSA*/ false); if (!Changed) return PreservedAnalyses::all(); diff --git a/llvm/lib/Transforms/Utils/LoopUnroll.cpp b/llvm/lib/Transforms/Utils/LoopUnroll.cpp index 3875c631f839..d4cd57405239 100644 --- a/llvm/lib/Transforms/Utils/LoopUnroll.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnroll.cpp @@ -59,6 +59,7 @@ #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/LoopPeel.h" #include "llvm/Transforms/Utils/LoopSimplify.h" #include "llvm/Transforms/Utils/LoopUtils.h" #include "llvm/Transforms/Utils/SimplifyIndVar.h" @@ -108,14 +109,15 @@ UnrollVerifyDomtree("unroll-verify-domtree", cl::Hidden, /// insert a phi-node, otherwise LCSSA will be broken. /// The function is just a helper function for llvm::UnrollLoop that returns /// true if this situation occurs, indicating that LCSSA needs to be fixed. -static bool needToInsertPhisForLCSSA(Loop *L, std::vector Blocks, +static bool needToInsertPhisForLCSSA(Loop *L, + const std::vector &Blocks, LoopInfo *LI) { for (BasicBlock *BB : Blocks) { if (LI->getLoopFor(BB) == L) continue; for (Instruction &I : *BB) { for (Use &U : I.operands()) { - if (auto Def = dyn_cast(U)) { + if (const auto *Def = dyn_cast(U)) { Loop *DefLoop = LI->getLoopFor(Def->getParent()); if (!DefLoop) continue; @@ -286,14 +288,12 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, OptimizationRemarkEmitter *ORE, bool PreserveLCSSA, Loop **RemainderLoop) { - BasicBlock *Preheader = L->getLoopPreheader(); - if (!Preheader) { + if (!L->getLoopPreheader()) { LLVM_DEBUG(dbgs() << " Can't unroll; loop preheader-insertion failed.\n"); return LoopUnrollResult::Unmodified; } - BasicBlock *LatchBlock = L->getLoopLatch(); - if (!LatchBlock) { + if (!L->getLoopLatch()) { LLVM_DEBUG(dbgs() << " Can't unroll; loop exit-block-insertion failed.\n"); return LoopUnrollResult::Unmodified; } @@ -304,37 +304,7 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, return LoopUnrollResult::Unmodified; } - // The current loop unroll pass can unroll loops that have - // (1) single latch; and - // (2a) latch is unconditional; or - // (2b) latch is conditional and is an exiting block - // FIXME: The implementation can be extended to work with more complicated - // cases, e.g. loops with multiple latches. - BasicBlock *Header = L->getHeader(); - BranchInst *LatchBI = dyn_cast(LatchBlock->getTerminator()); - - // A conditional branch which exits the loop, which can be optimized to an - // unconditional branch in the unrolled loop in some cases. - BranchInst *ExitingBI = nullptr; - bool LatchIsExiting = L->isLoopExiting(LatchBlock); - if (LatchIsExiting) - ExitingBI = LatchBI; - else if (BasicBlock *ExitingBlock = L->getExitingBlock()) - ExitingBI = dyn_cast(ExitingBlock->getTerminator()); - if (!LatchBI || (LatchBI->isConditional() && !LatchIsExiting)) { - LLVM_DEBUG( - dbgs() << "Can't unroll; a conditional latch must exit the loop"); - return LoopUnrollResult::Unmodified; - } - LLVM_DEBUG({ - if (ExitingBI) - dbgs() << " Exiting Block = " << ExitingBI->getParent()->getName() - << "\n"; - else - dbgs() << " No single exiting block\n"; - }); - - if (Header->hasAddressTaken()) { + if (L->getHeader()->hasAddressTaken()) { // The loop-rotate pass can be helpful to avoid this in many cases. LLVM_DEBUG( dbgs() << " Won't unroll loop: address of header block is taken.\n"); @@ -363,20 +333,6 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, // Are we eliminating the loop control altogether? bool CompletelyUnroll = ULO.Count == ULO.TripCount; - SmallVector ExitBlocks; - L->getExitBlocks(ExitBlocks); - std::vector OriginalLoopBlocks = L->getBlocks(); - - // Go through all exits of L and see if there are any phi-nodes there. We just - // conservatively assume that they're inserted to preserve LCSSA form, which - // means that complete unrolling might break this form. We need to either fix - // it in-place after the transformation, or entirely rebuild LCSSA. TODO: For - // now we just recompute LCSSA for the outer loop, but it should be possible - // to fix it in-place. - bool NeedToFixLCSSA = PreserveLCSSA && CompletelyUnroll && - any_of(ExitBlocks, [](const BasicBlock *BB) { - return isa(BB->begin()); - }); // We assume a run-time trip count if the compiler cannot // figure out the loop trip count and the unroll-runtime @@ -401,12 +357,63 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, BasicBlock *ExitingBlock = L->getLoopLatch(); assert(ExitingBlock && "Loop without exiting block?"); assert(L->isLoopExiting(ExitingBlock) && "Latch is not exiting?"); - Preheader = L->getLoopPreheader(); ULO.TripCount = SE->getSmallConstantTripCount(L, ExitingBlock); ULO.TripMultiple = SE->getSmallConstantTripMultiple(L, ExitingBlock); } } + // All these values should be taken only after peeling because they might have + // changed. + BasicBlock *Preheader = L->getLoopPreheader(); + BasicBlock *Header = L->getHeader(); + BasicBlock *LatchBlock = L->getLoopLatch(); + SmallVector ExitBlocks; + L->getExitBlocks(ExitBlocks); + std::vector OriginalLoopBlocks = L->getBlocks(); + + // Go through all exits of L and see if there are any phi-nodes there. We just + // conservatively assume that they're inserted to preserve LCSSA form, which + // means that complete unrolling might break this form. We need to either fix + // it in-place after the transformation, or entirely rebuild LCSSA. TODO: For + // now we just recompute LCSSA for the outer loop, but it should be possible + // to fix it in-place. + bool NeedToFixLCSSA = + PreserveLCSSA && CompletelyUnroll && + any_of(ExitBlocks, + [](const BasicBlock *BB) { return isa(BB->begin()); }); + + // The current loop unroll pass can unroll loops that have + // (1) single latch; and + // (2a) latch is unconditional; or + // (2b) latch is conditional and is an exiting block + // FIXME: The implementation can be extended to work with more complicated + // cases, e.g. loops with multiple latches. + BranchInst *LatchBI = dyn_cast(LatchBlock->getTerminator()); + + // A conditional branch which exits the loop, which can be optimized to an + // unconditional branch in the unrolled loop in some cases. + BranchInst *ExitingBI = nullptr; + bool LatchIsExiting = L->isLoopExiting(LatchBlock); + if (LatchIsExiting) + ExitingBI = LatchBI; + else if (BasicBlock *ExitingBlock = L->getExitingBlock()) + ExitingBI = dyn_cast(ExitingBlock->getTerminator()); + if (!LatchBI || (LatchBI->isConditional() && !LatchIsExiting)) { + // If the peeling guard is changed this assert may be relaxed or even + // deleted. + assert(!Peeled && "Peeling guard changed!"); + LLVM_DEBUG( + dbgs() << "Can't unroll; a conditional latch must exit the loop"); + return LoopUnrollResult::Unmodified; + } + LLVM_DEBUG({ + if (ExitingBI) + dbgs() << " Exiting Block = " << ExitingBI->getParent()->getName() + << "\n"; + else + dbgs() << " No single exiting block\n"; + }); + // Loops containing convergent instructions must have a count that divides // their TripMultiple. LLVM_DEBUG( @@ -583,6 +590,11 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, << DIL->getFilename() << " Line: " << DIL->getLine()); } + // Identify what noalias metadata is inside the loop: if it is inside the + // loop, the associated metadata must be cloned for each iteration. + SmallVector LoopLocalNoAliasDeclScopes; + identifyNoAliasScopesToClone(L->getBlocks(), LoopLocalNoAliasDeclScopes); + for (unsigned It = 1; It != ULO.Count; ++It) { SmallVector NewBlocks; SmallDenseMap NewLoops; @@ -676,6 +688,15 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, AC->registerAssumption(II); } } + + { + // Identify what other metadata depends on the cloned version. After + // cloning, replace the metadata with the corrected version for both + // memory instructions and noalias intrinsics. + std::string ext = (Twine("It") + Twine(It)).str(); + cloneAndAdaptNoAliasScopes(LoopLocalNoAliasDeclScopes, NewBlocks, + Header->getContext(), ext); + } } // Loop over the PHI nodes in the original block, setting incoming values. @@ -863,9 +884,7 @@ LoopUnrollResult llvm::UnrollLoop(Loop *L, UnrollLoopOptions ULO, LoopInfo *LI, if (MergeBlockIntoPredecessor(Dest, &DTU, LI)) { // Dest has been folded into Fold. Update our worklists accordingly. std::replace(Latches.begin(), Latches.end(), Dest, Fold); - UnrolledLoopBlocks.erase(std::remove(UnrolledLoopBlocks.begin(), - UnrolledLoopBlocks.end(), Dest), - UnrolledLoopBlocks.end()); + llvm::erase_value(UnrolledLoopBlocks, Dest); } } } diff --git a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp index dd628f3e7e0c..6e32a2b865aa 100644 --- a/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnrollAndJam.cpp @@ -148,8 +148,7 @@ static bool processHeaderPhiOperands(BasicBlock *Header, BasicBlock *Latch, } while (!Worklist.empty()) { - Instruction *I = Worklist.back(); - Worklist.pop_back(); + Instruction *I = Worklist.pop_back_val(); if (!Visit(I)) return false; @@ -459,14 +458,6 @@ llvm::UnrollAndJamLoop(Loop *L, unsigned Count, unsigned TripCount, // finish up connecting the blocks and phi nodes. At this point LastValueMap // is the last unrolled iterations values. - // Update Phis in BB from OldBB to point to NewBB - auto updatePHIBlocks = [](BasicBlock *BB, BasicBlock *OldBB, - BasicBlock *NewBB) { - for (PHINode &Phi : BB->phis()) { - int I = Phi.getBasicBlockIndex(OldBB); - Phi.setIncomingBlock(I, NewBB); - } - }; // Update Phis in BB from OldBB to point to NewBB and use the latest value // from LastValueMap auto updatePHIBlocksAndValues = [](BasicBlock *BB, BasicBlock *OldBB, @@ -525,10 +516,10 @@ llvm::UnrollAndJamLoop(Loop *L, unsigned Count, unsigned TripCount, cast(SubLoopBlocksLast.back()->getTerminator()); SubTerm->setSuccessor(!SubLoopContinueOnTrue, SubLoopBlocksFirst[0]); SubTerm->setSuccessor(SubLoopContinueOnTrue, AftBlocksFirst[0]); - updatePHIBlocks(SubLoopBlocksFirst[0], ForeBlocksLast[0], - ForeBlocksLast.back()); - updatePHIBlocks(SubLoopBlocksFirst[0], SubLoopBlocksLast[0], - SubLoopBlocksLast.back()); + SubLoopBlocksFirst[0]->replacePhiUsesWith(ForeBlocksLast[0], + ForeBlocksLast.back()); + SubLoopBlocksFirst[0]->replacePhiUsesWith(SubLoopBlocksLast[0], + SubLoopBlocksLast.back()); for (unsigned It = 1; It != Count; It++) { // Replace the conditional branch of the previous iteration subloop with an @@ -538,10 +529,10 @@ llvm::UnrollAndJamLoop(Loop *L, unsigned Count, unsigned TripCount, BranchInst::Create(SubLoopBlocksFirst[It], SubTerm); SubTerm->eraseFromParent(); - updatePHIBlocks(SubLoopBlocksFirst[It], ForeBlocksLast[It], - ForeBlocksLast.back()); - updatePHIBlocks(SubLoopBlocksFirst[It], SubLoopBlocksLast[It], - SubLoopBlocksLast.back()); + SubLoopBlocksFirst[It]->replacePhiUsesWith(ForeBlocksLast[It], + ForeBlocksLast.back()); + SubLoopBlocksFirst[It]->replacePhiUsesWith(SubLoopBlocksLast[It], + SubLoopBlocksLast.back()); movePHIs(SubLoopBlocksFirst[It], SubLoopBlocksFirst[0]); } @@ -555,8 +546,8 @@ llvm::UnrollAndJamLoop(Loop *L, unsigned Count, unsigned TripCount, assert(AftTerm->getSuccessor(ContinueOnTrue) == LoopExit && "Expecting the ContinueOnTrue successor of AftTerm to be LoopExit"); } - updatePHIBlocks(AftBlocksFirst[0], SubLoopBlocksLast[0], - SubLoopBlocksLast.back()); + AftBlocksFirst[0]->replacePhiUsesWith(SubLoopBlocksLast[0], + SubLoopBlocksLast.back()); for (unsigned It = 1; It != Count; It++) { // Replace the conditional branch of the previous iteration subloop with an @@ -566,8 +557,8 @@ llvm::UnrollAndJamLoop(Loop *L, unsigned Count, unsigned TripCount, BranchInst::Create(AftBlocksFirst[It], AftTerm); AftTerm->eraseFromParent(); - updatePHIBlocks(AftBlocksFirst[It], SubLoopBlocksLast[It], - SubLoopBlocksLast.back()); + AftBlocksFirst[It]->replacePhiUsesWith(SubLoopBlocksLast[It], + SubLoopBlocksLast.back()); movePHIs(AftBlocksFirst[It], AftBlocksFirst[0]); } diff --git a/llvm/lib/Transforms/Utils/LoopUnrollPeel.cpp b/llvm/lib/Transforms/Utils/LoopUnrollPeel.cpp deleted file mode 100644 index c653aacbee6c..000000000000 --- a/llvm/lib/Transforms/Utils/LoopUnrollPeel.cpp +++ /dev/null @@ -1,798 +0,0 @@ -//===- UnrollLoopPeel.cpp - Loop peeling utilities ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements some loop unrolling utilities for peeling loops -// with dynamically inferred (from PGO) trip counts. See LoopUnroll.cpp for -// unrolling loops with compile-time constant trip counts. -// -//===----------------------------------------------------------------------===// - -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/LoopInfo.h" -#include "llvm/Analysis/LoopIterator.h" -#include "llvm/Analysis/ScalarEvolution.h" -#include "llvm/Analysis/ScalarEvolutionExpressions.h" -#include "llvm/Analysis/TargetTransformInfo.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/MDBuilder.h" -#include "llvm/IR/Metadata.h" -#include "llvm/IR/PatternMatch.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/LoopSimplify.h" -#include "llvm/Transforms/Utils/LoopUtils.h" -#include "llvm/Transforms/Utils/UnrollLoop.h" -#include "llvm/Transforms/Utils/ValueMapper.h" -#include -#include -#include -#include - -using namespace llvm; -using namespace llvm::PatternMatch; - -#define DEBUG_TYPE "loop-unroll" - -STATISTIC(NumPeeled, "Number of loops peeled"); - -static cl::opt UnrollPeelMaxCount( - "unroll-peel-max-count", cl::init(7), cl::Hidden, - cl::desc("Max average trip count which will cause loop peeling.")); - -static cl::opt UnrollForcePeelCount( - "unroll-force-peel-count", cl::init(0), cl::Hidden, - cl::desc("Force a peel count regardless of profiling information.")); - -static cl::opt UnrollPeelMultiDeoptExit( - "unroll-peel-multi-deopt-exit", cl::init(true), cl::Hidden, - cl::desc("Allow peeling of loops with multiple deopt exits.")); - -static const char *PeeledCountMetaData = "llvm.loop.peeled.count"; - -// Designates that a Phi is estimated to become invariant after an "infinite" -// number of loop iterations (i.e. only may become an invariant if the loop is -// fully unrolled). -static const unsigned InfiniteIterationsToInvariance = - std::numeric_limits::max(); - -// Check whether we are capable of peeling this loop. -bool llvm::canPeel(Loop *L) { - // Make sure the loop is in simplified form - if (!L->isLoopSimplifyForm()) - return false; - - if (UnrollPeelMultiDeoptExit) { - SmallVector Exits; - L->getUniqueNonLatchExitBlocks(Exits); - - if (!Exits.empty()) { - // Latch's terminator is a conditional branch, Latch is exiting and - // all non Latch exits ends up with deoptimize. - const BasicBlock *Latch = L->getLoopLatch(); - const BranchInst *T = dyn_cast(Latch->getTerminator()); - return T && T->isConditional() && L->isLoopExiting(Latch) && - all_of(Exits, [](const BasicBlock *BB) { - return BB->getTerminatingDeoptimizeCall(); - }); - } - } - - // Only peel loops that contain a single exit - if (!L->getExitingBlock() || !L->getUniqueExitBlock()) - return false; - - // Don't try to peel loops where the latch is not the exiting block. - // This can be an indication of two different things: - // 1) The loop is not rotated. - // 2) The loop contains irreducible control flow that involves the latch. - if (L->getLoopLatch() != L->getExitingBlock()) - return false; - - return true; -} - -// This function calculates the number of iterations after which the given Phi -// becomes an invariant. The pre-calculated values are memorized in the map. The -// function (shortcut is I) is calculated according to the following definition: -// Given %x = phi , ..., [%y, %back.edge]. -// If %y is a loop invariant, then I(%x) = 1. -// If %y is a Phi from the loop header, I(%x) = I(%y) + 1. -// Otherwise, I(%x) is infinite. -// TODO: Actually if %y is an expression that depends only on Phi %z and some -// loop invariants, we can estimate I(%x) = I(%z) + 1. The example -// looks like: -// %x = phi(0, %a), <-- becomes invariant starting from 3rd iteration. -// %y = phi(0, 5), -// %a = %y + 1. -static unsigned calculateIterationsToInvariance( - PHINode *Phi, Loop *L, BasicBlock *BackEdge, - SmallDenseMap &IterationsToInvariance) { - assert(Phi->getParent() == L->getHeader() && - "Non-loop Phi should not be checked for turning into invariant."); - assert(BackEdge == L->getLoopLatch() && "Wrong latch?"); - // If we already know the answer, take it from the map. - auto I = IterationsToInvariance.find(Phi); - if (I != IterationsToInvariance.end()) - return I->second; - - // Otherwise we need to analyze the input from the back edge. - Value *Input = Phi->getIncomingValueForBlock(BackEdge); - // Place infinity to map to avoid infinite recursion for cycled Phis. Such - // cycles can never stop on an invariant. - IterationsToInvariance[Phi] = InfiniteIterationsToInvariance; - unsigned ToInvariance = InfiniteIterationsToInvariance; - - if (L->isLoopInvariant(Input)) - ToInvariance = 1u; - else if (PHINode *IncPhi = dyn_cast(Input)) { - // Only consider Phis in header block. - if (IncPhi->getParent() != L->getHeader()) - return InfiniteIterationsToInvariance; - // If the input becomes an invariant after X iterations, then our Phi - // becomes an invariant after X + 1 iterations. - unsigned InputToInvariance = calculateIterationsToInvariance( - IncPhi, L, BackEdge, IterationsToInvariance); - if (InputToInvariance != InfiniteIterationsToInvariance) - ToInvariance = InputToInvariance + 1u; - } - - // If we found that this Phi lies in an invariant chain, update the map. - if (ToInvariance != InfiniteIterationsToInvariance) - IterationsToInvariance[Phi] = ToInvariance; - return ToInvariance; -} - -// Return the number of iterations to peel off that make conditions in the -// body true/false. For example, if we peel 2 iterations off the loop below, -// the condition i < 2 can be evaluated at compile time. -// for (i = 0; i < n; i++) -// if (i < 2) -// .. -// else -// .. -// } -static unsigned countToEliminateCompares(Loop &L, unsigned MaxPeelCount, - ScalarEvolution &SE) { - assert(L.isLoopSimplifyForm() && "Loop needs to be in loop simplify form"); - unsigned DesiredPeelCount = 0; - - for (auto *BB : L.blocks()) { - auto *BI = dyn_cast(BB->getTerminator()); - if (!BI || BI->isUnconditional()) - continue; - - // Ignore loop exit condition. - if (L.getLoopLatch() == BB) - continue; - - Value *Condition = BI->getCondition(); - Value *LeftVal, *RightVal; - CmpInst::Predicate Pred; - if (!match(Condition, m_ICmp(Pred, m_Value(LeftVal), m_Value(RightVal)))) - continue; - - const SCEV *LeftSCEV = SE.getSCEV(LeftVal); - const SCEV *RightSCEV = SE.getSCEV(RightVal); - - // Do not consider predicates that are known to be true or false - // independently of the loop iteration. - if (SE.isKnownPredicate(Pred, LeftSCEV, RightSCEV) || - SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), LeftSCEV, - RightSCEV)) - continue; - - // Check if we have a condition with one AddRec and one non AddRec - // expression. Normalize LeftSCEV to be the AddRec. - if (!isa(LeftSCEV)) { - if (isa(RightSCEV)) { - std::swap(LeftSCEV, RightSCEV); - Pred = ICmpInst::getSwappedPredicate(Pred); - } else - continue; - } - - const SCEVAddRecExpr *LeftAR = cast(LeftSCEV); - - // Avoid huge SCEV computations in the loop below, make sure we only - // consider AddRecs of the loop we are trying to peel. - if (!LeftAR->isAffine() || LeftAR->getLoop() != &L) - continue; - bool Increasing; - if (!(ICmpInst::isEquality(Pred) && LeftAR->hasNoSelfWrap()) && - !SE.isMonotonicPredicate(LeftAR, Pred, Increasing)) - continue; - (void)Increasing; - - // Check if extending the current DesiredPeelCount lets us evaluate Pred - // or !Pred in the loop body statically. - unsigned NewPeelCount = DesiredPeelCount; - - const SCEV *IterVal = LeftAR->evaluateAtIteration( - SE.getConstant(LeftSCEV->getType(), NewPeelCount), SE); - - // If the original condition is not known, get the negated predicate - // (which holds on the else branch) and check if it is known. This allows - // us to peel of iterations that make the original condition false. - if (!SE.isKnownPredicate(Pred, IterVal, RightSCEV)) - Pred = ICmpInst::getInversePredicate(Pred); - - const SCEV *Step = LeftAR->getStepRecurrence(SE); - const SCEV *NextIterVal = SE.getAddExpr(IterVal, Step); - auto PeelOneMoreIteration = [&IterVal, &NextIterVal, &SE, Step, - &NewPeelCount]() { - IterVal = NextIterVal; - NextIterVal = SE.getAddExpr(IterVal, Step); - NewPeelCount++; - }; - - auto CanPeelOneMoreIteration = [&NewPeelCount, &MaxPeelCount]() { - return NewPeelCount < MaxPeelCount; - }; - - while (CanPeelOneMoreIteration() && - SE.isKnownPredicate(Pred, IterVal, RightSCEV)) - PeelOneMoreIteration(); - - // With *that* peel count, does the predicate !Pred become known in the - // first iteration of the loop body after peeling? - if (!SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), IterVal, - RightSCEV)) - continue; // If not, give up. - - // However, for equality comparisons, that isn't always sufficient to - // eliminate the comparsion in loop body, we may need to peel one more - // iteration. See if that makes !Pred become unknown again. - if (ICmpInst::isEquality(Pred) && - !SE.isKnownPredicate(ICmpInst::getInversePredicate(Pred), NextIterVal, - RightSCEV) && - !SE.isKnownPredicate(Pred, IterVal, RightSCEV) && - SE.isKnownPredicate(Pred, NextIterVal, RightSCEV)) { - if (!CanPeelOneMoreIteration()) - continue; // Need to peel one more iteration, but can't. Give up. - PeelOneMoreIteration(); // Great! - } - - DesiredPeelCount = std::max(DesiredPeelCount, NewPeelCount); - } - - return DesiredPeelCount; -} - -// Return the number of iterations we want to peel off. -void llvm::computePeelCount(Loop *L, unsigned LoopSize, - TargetTransformInfo::UnrollingPreferences &UP, - TargetTransformInfo::PeelingPreferences &PP, - unsigned &TripCount, ScalarEvolution &SE) { - assert(LoopSize > 0 && "Zero loop size is not allowed!"); - // Save the PP.PeelCount value set by the target in - // TTI.getPeelingPreferences or by the flag -unroll-peel-count. - unsigned TargetPeelCount = PP.PeelCount; - PP.PeelCount = 0; - if (!canPeel(L)) - return; - - // Only try to peel innermost loops by default. - // The constraint can be relaxed by the target in TTI.getUnrollingPreferences - // or by the flag -unroll-allow-loop-nests-peeling. - if (!PP.AllowLoopNestsPeeling && !L->empty()) - return; - - // If the user provided a peel count, use that. - bool UserPeelCount = UnrollForcePeelCount.getNumOccurrences() > 0; - if (UserPeelCount) { - LLVM_DEBUG(dbgs() << "Force-peeling first " << UnrollForcePeelCount - << " iterations.\n"); - PP.PeelCount = UnrollForcePeelCount; - PP.PeelProfiledIterations = true; - return; - } - - // Skip peeling if it's disabled. - if (!PP.AllowPeeling) - return; - - unsigned AlreadyPeeled = 0; - if (auto Peeled = getOptionalIntLoopAttribute(L, PeeledCountMetaData)) - AlreadyPeeled = *Peeled; - // Stop if we already peeled off the maximum number of iterations. - if (AlreadyPeeled >= UnrollPeelMaxCount) - return; - - // Here we try to get rid of Phis which become invariants after 1, 2, ..., N - // iterations of the loop. For this we compute the number for iterations after - // which every Phi is guaranteed to become an invariant, and try to peel the - // maximum number of iterations among these values, thus turning all those - // Phis into invariants. - // First, check that we can peel at least one iteration. - if (2 * LoopSize <= UP.Threshold && UnrollPeelMaxCount > 0) { - // Store the pre-calculated values here. - SmallDenseMap IterationsToInvariance; - // Now go through all Phis to calculate their the number of iterations they - // need to become invariants. - // Start the max computation with the UP.PeelCount value set by the target - // in TTI.getUnrollingPreferences or by the flag -unroll-peel-count. - unsigned DesiredPeelCount = TargetPeelCount; - BasicBlock *BackEdge = L->getLoopLatch(); - assert(BackEdge && "Loop is not in simplified form?"); - for (auto BI = L->getHeader()->begin(); isa(&*BI); ++BI) { - PHINode *Phi = cast(&*BI); - unsigned ToInvariance = calculateIterationsToInvariance( - Phi, L, BackEdge, IterationsToInvariance); - if (ToInvariance != InfiniteIterationsToInvariance) - DesiredPeelCount = std::max(DesiredPeelCount, ToInvariance); - } - - // Pay respect to limitations implied by loop size and the max peel count. - unsigned MaxPeelCount = UnrollPeelMaxCount; - MaxPeelCount = std::min(MaxPeelCount, UP.Threshold / LoopSize - 1); - - DesiredPeelCount = std::max(DesiredPeelCount, - countToEliminateCompares(*L, MaxPeelCount, SE)); - - if (DesiredPeelCount > 0) { - DesiredPeelCount = std::min(DesiredPeelCount, MaxPeelCount); - // Consider max peel count limitation. - assert(DesiredPeelCount > 0 && "Wrong loop size estimation?"); - if (DesiredPeelCount + AlreadyPeeled <= UnrollPeelMaxCount) { - LLVM_DEBUG(dbgs() << "Peel " << DesiredPeelCount - << " iteration(s) to turn" - << " some Phis into invariants.\n"); - PP.PeelCount = DesiredPeelCount; - PP.PeelProfiledIterations = false; - return; - } - } - } - - // Bail if we know the statically calculated trip count. - // In this case we rather prefer partial unrolling. - if (TripCount) - return; - - // Do not apply profile base peeling if it is disabled. - if (!PP.PeelProfiledIterations) - return; - // If we don't know the trip count, but have reason to believe the average - // trip count is low, peeling should be beneficial, since we will usually - // hit the peeled section. - // We only do this in the presence of profile information, since otherwise - // our estimates of the trip count are not reliable enough. - if (L->getHeader()->getParent()->hasProfileData()) { - Optional PeelCount = getLoopEstimatedTripCount(L); - if (!PeelCount) - return; - - LLVM_DEBUG(dbgs() << "Profile-based estimated trip count is " << *PeelCount - << "\n"); - - if (*PeelCount) { - if ((*PeelCount + AlreadyPeeled <= UnrollPeelMaxCount) && - (LoopSize * (*PeelCount + 1) <= UP.Threshold)) { - LLVM_DEBUG(dbgs() << "Peeling first " << *PeelCount - << " iterations.\n"); - PP.PeelCount = *PeelCount; - return; - } - LLVM_DEBUG(dbgs() << "Requested peel count: " << *PeelCount << "\n"); - LLVM_DEBUG(dbgs() << "Already peel count: " << AlreadyPeeled << "\n"); - LLVM_DEBUG(dbgs() << "Max peel count: " << UnrollPeelMaxCount << "\n"); - LLVM_DEBUG(dbgs() << "Peel cost: " << LoopSize * (*PeelCount + 1) - << "\n"); - LLVM_DEBUG(dbgs() << "Max peel cost: " << UP.Threshold << "\n"); - } - } -} - -/// Update the branch weights of the latch of a peeled-off loop -/// iteration. -/// This sets the branch weights for the latch of the recently peeled off loop -/// iteration correctly. -/// Let F is a weight of the edge from latch to header. -/// Let E is a weight of the edge from latch to exit. -/// F/(F+E) is a probability to go to loop and E/(F+E) is a probability to -/// go to exit. -/// Then, Estimated TripCount = F / E. -/// For I-th (counting from 0) peeled off iteration we set the the weights for -/// the peeled latch as (TC - I, 1). It gives us reasonable distribution, -/// The probability to go to exit 1/(TC-I) increases. At the same time -/// the estimated trip count of remaining loop reduces by I. -/// To avoid dealing with division rounding we can just multiple both part -/// of weights to E and use weight as (F - I * E, E). -/// -/// \param Header The copy of the header block that belongs to next iteration. -/// \param LatchBR The copy of the latch branch that belongs to this iteration. -/// \param[in,out] FallThroughWeight The weight of the edge from latch to -/// header before peeling (in) and after peeled off one iteration (out). -static void updateBranchWeights(BasicBlock *Header, BranchInst *LatchBR, - uint64_t ExitWeight, - uint64_t &FallThroughWeight) { - // FallThroughWeight is 0 means that there is no branch weights on original - // latch block or estimated trip count is zero. - if (!FallThroughWeight) - return; - - unsigned HeaderIdx = (LatchBR->getSuccessor(0) == Header ? 0 : 1); - MDBuilder MDB(LatchBR->getContext()); - MDNode *WeightNode = - HeaderIdx ? MDB.createBranchWeights(ExitWeight, FallThroughWeight) - : MDB.createBranchWeights(FallThroughWeight, ExitWeight); - LatchBR->setMetadata(LLVMContext::MD_prof, WeightNode); - FallThroughWeight = - FallThroughWeight > ExitWeight ? FallThroughWeight - ExitWeight : 1; -} - -/// Initialize the weights. -/// -/// \param Header The header block. -/// \param LatchBR The latch branch. -/// \param[out] ExitWeight The weight of the edge from Latch to Exit. -/// \param[out] FallThroughWeight The weight of the edge from Latch to Header. -static void initBranchWeights(BasicBlock *Header, BranchInst *LatchBR, - uint64_t &ExitWeight, - uint64_t &FallThroughWeight) { - uint64_t TrueWeight, FalseWeight; - if (!LatchBR->extractProfMetadata(TrueWeight, FalseWeight)) - return; - unsigned HeaderIdx = LatchBR->getSuccessor(0) == Header ? 0 : 1; - ExitWeight = HeaderIdx ? TrueWeight : FalseWeight; - FallThroughWeight = HeaderIdx ? FalseWeight : TrueWeight; -} - -/// Update the weights of original Latch block after peeling off all iterations. -/// -/// \param Header The header block. -/// \param LatchBR The latch branch. -/// \param ExitWeight The weight of the edge from Latch to Exit. -/// \param FallThroughWeight The weight of the edge from Latch to Header. -static void fixupBranchWeights(BasicBlock *Header, BranchInst *LatchBR, - uint64_t ExitWeight, - uint64_t FallThroughWeight) { - // FallThroughWeight is 0 means that there is no branch weights on original - // latch block or estimated trip count is zero. - if (!FallThroughWeight) - return; - - // Sets the branch weights on the loop exit. - MDBuilder MDB(LatchBR->getContext()); - unsigned HeaderIdx = LatchBR->getSuccessor(0) == Header ? 0 : 1; - MDNode *WeightNode = - HeaderIdx ? MDB.createBranchWeights(ExitWeight, FallThroughWeight) - : MDB.createBranchWeights(FallThroughWeight, ExitWeight); - LatchBR->setMetadata(LLVMContext::MD_prof, WeightNode); -} - -/// Clones the body of the loop L, putting it between \p InsertTop and \p -/// InsertBot. -/// \param IterNumber The serial number of the iteration currently being -/// peeled off. -/// \param ExitEdges The exit edges of the original loop. -/// \param[out] NewBlocks A list of the blocks in the newly created clone -/// \param[out] VMap The value map between the loop and the new clone. -/// \param LoopBlocks A helper for DFS-traversal of the loop. -/// \param LVMap A value-map that maps instructions from the original loop to -/// instructions in the last peeled-off iteration. -static void cloneLoopBlocks( - Loop *L, unsigned IterNumber, BasicBlock *InsertTop, BasicBlock *InsertBot, - SmallVectorImpl > &ExitEdges, - SmallVectorImpl &NewBlocks, LoopBlocksDFS &LoopBlocks, - ValueToValueMapTy &VMap, ValueToValueMapTy &LVMap, DominatorTree *DT, - LoopInfo *LI) { - BasicBlock *Header = L->getHeader(); - BasicBlock *Latch = L->getLoopLatch(); - BasicBlock *PreHeader = L->getLoopPreheader(); - - Function *F = Header->getParent(); - LoopBlocksDFS::RPOIterator BlockBegin = LoopBlocks.beginRPO(); - LoopBlocksDFS::RPOIterator BlockEnd = LoopBlocks.endRPO(); - Loop *ParentLoop = L->getParentLoop(); - - // For each block in the original loop, create a new copy, - // and update the value map with the newly created values. - for (LoopBlocksDFS::RPOIterator BB = BlockBegin; BB != BlockEnd; ++BB) { - BasicBlock *NewBB = CloneBasicBlock(*BB, VMap, ".peel", F); - NewBlocks.push_back(NewBB); - - // If an original block is an immediate child of the loop L, its copy - // is a child of a ParentLoop after peeling. If a block is a child of - // a nested loop, it is handled in the cloneLoop() call below. - if (ParentLoop && LI->getLoopFor(*BB) == L) - ParentLoop->addBasicBlockToLoop(NewBB, *LI); - - VMap[*BB] = NewBB; - - // If dominator tree is available, insert nodes to represent cloned blocks. - if (DT) { - if (Header == *BB) - DT->addNewBlock(NewBB, InsertTop); - else { - DomTreeNode *IDom = DT->getNode(*BB)->getIDom(); - // VMap must contain entry for IDom, as the iteration order is RPO. - DT->addNewBlock(NewBB, cast(VMap[IDom->getBlock()])); - } - } - } - - // Recursively create the new Loop objects for nested loops, if any, - // to preserve LoopInfo. - for (Loop *ChildLoop : *L) { - cloneLoop(ChildLoop, ParentLoop, VMap, LI, nullptr); - } - - // Hook-up the control flow for the newly inserted blocks. - // The new header is hooked up directly to the "top", which is either - // the original loop preheader (for the first iteration) or the previous - // iteration's exiting block (for every other iteration) - InsertTop->getTerminator()->setSuccessor(0, cast(VMap[Header])); - - // Similarly, for the latch: - // The original exiting edge is still hooked up to the loop exit. - // The backedge now goes to the "bottom", which is either the loop's real - // header (for the last peeled iteration) or the copied header of the next - // iteration (for every other iteration) - BasicBlock *NewLatch = cast(VMap[Latch]); - BranchInst *LatchBR = cast(NewLatch->getTerminator()); - for (unsigned idx = 0, e = LatchBR->getNumSuccessors(); idx < e; ++idx) - if (LatchBR->getSuccessor(idx) == Header) { - LatchBR->setSuccessor(idx, InsertBot); - break; - } - if (DT) - DT->changeImmediateDominator(InsertBot, NewLatch); - - // The new copy of the loop body starts with a bunch of PHI nodes - // that pick an incoming value from either the preheader, or the previous - // loop iteration. Since this copy is no longer part of the loop, we - // resolve this statically: - // For the first iteration, we use the value from the preheader directly. - // For any other iteration, we replace the phi with the value generated by - // the immediately preceding clone of the loop body (which represents - // the previous iteration). - for (BasicBlock::iterator I = Header->begin(); isa(I); ++I) { - PHINode *NewPHI = cast(VMap[&*I]); - if (IterNumber == 0) { - VMap[&*I] = NewPHI->getIncomingValueForBlock(PreHeader); - } else { - Value *LatchVal = NewPHI->getIncomingValueForBlock(Latch); - Instruction *LatchInst = dyn_cast(LatchVal); - if (LatchInst && L->contains(LatchInst)) - VMap[&*I] = LVMap[LatchInst]; - else - VMap[&*I] = LatchVal; - } - cast(VMap[Header])->getInstList().erase(NewPHI); - } - - // Fix up the outgoing values - we need to add a value for the iteration - // we've just created. Note that this must happen *after* the incoming - // values are adjusted, since the value going out of the latch may also be - // a value coming into the header. - for (auto Edge : ExitEdges) - for (PHINode &PHI : Edge.second->phis()) { - Value *LatchVal = PHI.getIncomingValueForBlock(Edge.first); - Instruction *LatchInst = dyn_cast(LatchVal); - if (LatchInst && L->contains(LatchInst)) - LatchVal = VMap[LatchVal]; - PHI.addIncoming(LatchVal, cast(VMap[Edge.first])); - } - - // LastValueMap is updated with the values for the current loop - // which are used the next time this function is called. - for (auto KV : VMap) - LVMap[KV.first] = KV.second; -} - -/// Peel off the first \p PeelCount iterations of loop \p L. -/// -/// Note that this does not peel them off as a single straight-line block. -/// Rather, each iteration is peeled off separately, and needs to check the -/// exit condition. -/// For loops that dynamically execute \p PeelCount iterations or less -/// this provides a benefit, since the peeled off iterations, which account -/// for the bulk of dynamic execution, can be further simplified by scalar -/// optimizations. -bool llvm::peelLoop(Loop *L, unsigned PeelCount, LoopInfo *LI, - ScalarEvolution *SE, DominatorTree *DT, - AssumptionCache *AC, bool PreserveLCSSA) { - assert(PeelCount > 0 && "Attempt to peel out zero iterations?"); - assert(canPeel(L) && "Attempt to peel a loop which is not peelable?"); - - LoopBlocksDFS LoopBlocks(L); - LoopBlocks.perform(LI); - - BasicBlock *Header = L->getHeader(); - BasicBlock *PreHeader = L->getLoopPreheader(); - BasicBlock *Latch = L->getLoopLatch(); - SmallVector, 4> ExitEdges; - L->getExitEdges(ExitEdges); - - DenseMap ExitIDom; - if (DT) { - // We'd like to determine the idom of exit block after peeling one - // iteration. - // Let Exit is exit block. - // Let ExitingSet - is a set of predecessors of Exit block. They are exiting - // blocks. - // Let Latch' and ExitingSet' are copies after a peeling. - // We'd like to find an idom'(Exit) - idom of Exit after peeling. - // It is an evident that idom'(Exit) will be the nearest common dominator - // of ExitingSet and ExitingSet'. - // idom(Exit) is a nearest common dominator of ExitingSet. - // idom(Exit)' is a nearest common dominator of ExitingSet'. - // Taking into account that we have a single Latch, Latch' will dominate - // Header and idom(Exit). - // So the idom'(Exit) is nearest common dominator of idom(Exit)' and Latch'. - // All these basic blocks are in the same loop, so what we find is - // (nearest common dominator of idom(Exit) and Latch)'. - // In the loop below we remember nearest common dominator of idom(Exit) and - // Latch to update idom of Exit later. - assert(L->hasDedicatedExits() && "No dedicated exits?"); - for (auto Edge : ExitEdges) { - if (ExitIDom.count(Edge.second)) - continue; - BasicBlock *BB = DT->findNearestCommonDominator( - DT->getNode(Edge.second)->getIDom()->getBlock(), Latch); - assert(L->contains(BB) && "IDom is not in a loop"); - ExitIDom[Edge.second] = BB; - } - } - - Function *F = Header->getParent(); - - // Set up all the necessary basic blocks. It is convenient to split the - // preheader into 3 parts - two blocks to anchor the peeled copy of the loop - // body, and a new preheader for the "real" loop. - - // Peeling the first iteration transforms. - // - // PreHeader: - // ... - // Header: - // LoopBody - // If (cond) goto Header - // Exit: - // - // into - // - // InsertTop: - // LoopBody - // If (!cond) goto Exit - // InsertBot: - // NewPreHeader: - // ... - // Header: - // LoopBody - // If (cond) goto Header - // Exit: - // - // Each following iteration will split the current bottom anchor in two, - // and put the new copy of the loop body between these two blocks. That is, - // after peeling another iteration from the example above, we'll split - // InsertBot, and get: - // - // InsertTop: - // LoopBody - // If (!cond) goto Exit - // InsertBot: - // LoopBody - // If (!cond) goto Exit - // InsertBot.next: - // NewPreHeader: - // ... - // Header: - // LoopBody - // If (cond) goto Header - // Exit: - - BasicBlock *InsertTop = SplitEdge(PreHeader, Header, DT, LI); - BasicBlock *InsertBot = - SplitBlock(InsertTop, InsertTop->getTerminator(), DT, LI); - BasicBlock *NewPreHeader = - SplitBlock(InsertBot, InsertBot->getTerminator(), DT, LI); - - InsertTop->setName(Header->getName() + ".peel.begin"); - InsertBot->setName(Header->getName() + ".peel.next"); - NewPreHeader->setName(PreHeader->getName() + ".peel.newph"); - - ValueToValueMapTy LVMap; - - // If we have branch weight information, we'll want to update it for the - // newly created branches. - BranchInst *LatchBR = - cast(cast(Latch)->getTerminator()); - uint64_t ExitWeight = 0, FallThroughWeight = 0; - initBranchWeights(Header, LatchBR, ExitWeight, FallThroughWeight); - - // For each peeled-off iteration, make a copy of the loop. - for (unsigned Iter = 0; Iter < PeelCount; ++Iter) { - SmallVector NewBlocks; - ValueToValueMapTy VMap; - - cloneLoopBlocks(L, Iter, InsertTop, InsertBot, ExitEdges, NewBlocks, - LoopBlocks, VMap, LVMap, DT, LI); - - // Remap to use values from the current iteration instead of the - // previous one. - remapInstructionsInBlocks(NewBlocks, VMap); - - if (DT) { - // Latches of the cloned loops dominate over the loop exit, so idom of the - // latter is the first cloned loop body, as original PreHeader dominates - // the original loop body. - if (Iter == 0) - for (auto Exit : ExitIDom) - DT->changeImmediateDominator(Exit.first, - cast(LVMap[Exit.second])); -#ifdef EXPENSIVE_CHECKS - assert(DT->verify(DominatorTree::VerificationLevel::Fast)); -#endif - } - - auto *LatchBRCopy = cast(VMap[LatchBR]); - updateBranchWeights(InsertBot, LatchBRCopy, ExitWeight, FallThroughWeight); - // Remove Loop metadata from the latch branch instruction - // because it is not the Loop's latch branch anymore. - LatchBRCopy->setMetadata(LLVMContext::MD_loop, nullptr); - - InsertTop = InsertBot; - InsertBot = SplitBlock(InsertBot, InsertBot->getTerminator(), DT, LI); - InsertBot->setName(Header->getName() + ".peel.next"); - - F->getBasicBlockList().splice(InsertTop->getIterator(), - F->getBasicBlockList(), - NewBlocks[0]->getIterator(), F->end()); - } - - // Now adjust the phi nodes in the loop header to get their initial values - // from the last peeled-off iteration instead of the preheader. - for (BasicBlock::iterator I = Header->begin(); isa(I); ++I) { - PHINode *PHI = cast(I); - Value *NewVal = PHI->getIncomingValueForBlock(Latch); - Instruction *LatchInst = dyn_cast(NewVal); - if (LatchInst && L->contains(LatchInst)) - NewVal = LVMap[LatchInst]; - - PHI->setIncomingValueForBlock(NewPreHeader, NewVal); - } - - fixupBranchWeights(Header, LatchBR, ExitWeight, FallThroughWeight); - - // Update Metadata for count of peeled off iterations. - unsigned AlreadyPeeled = 0; - if (auto Peeled = getOptionalIntLoopAttribute(L, PeeledCountMetaData)) - AlreadyPeeled = *Peeled; - addStringMetadataToLoop(L, PeeledCountMetaData, AlreadyPeeled + PeelCount); - - if (Loop *ParentLoop = L->getParentLoop()) - L = ParentLoop; - - // We modified the loop, update SE. - SE->forgetTopmostLoop(L); - - // Finally DomtTree must be correct. - assert(DT->verify(DominatorTree::VerificationLevel::Fast)); - - // FIXME: Incrementally update loop-simplify - simplifyLoop(L, DT, LI, SE, AC, nullptr, PreserveLCSSA); - - NumPeeled++; - - return true; -} diff --git a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp index 2515b1676cb9..0abf62be156f 100644 --- a/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp +++ b/llvm/lib/Transforms/Utils/LoopUnrollRuntime.cpp @@ -22,11 +22,11 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/Statistic.h" -#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/LoopIterator.h" #include "llvm/Analysis/ScalarEvolution.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Dominators.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Metadata.h" #include "llvm/IR/Module.h" #include "llvm/Support/CommandLine.h" @@ -505,6 +505,32 @@ static bool canProfitablyUnrollMultiExitLoop( // know of kinds of multiexit loops that would benefit from unrolling. } +// Assign the maximum possible trip count as the back edge weight for the +// remainder loop if the original loop comes with a branch weight. +static void updateLatchBranchWeightsForRemainderLoop(Loop *OrigLoop, + Loop *RemainderLoop, + uint64_t UnrollFactor) { + uint64_t TrueWeight, FalseWeight; + BranchInst *LatchBR = + cast(OrigLoop->getLoopLatch()->getTerminator()); + if (LatchBR->extractProfMetadata(TrueWeight, FalseWeight)) { + uint64_t ExitWeight = LatchBR->getSuccessor(0) == OrigLoop->getHeader() + ? FalseWeight + : TrueWeight; + assert(UnrollFactor > 1); + uint64_t BackEdgeWeight = (UnrollFactor - 1) * ExitWeight; + BasicBlock *Header = RemainderLoop->getHeader(); + BasicBlock *Latch = RemainderLoop->getLoopLatch(); + auto *RemainderLatchBR = cast(Latch->getTerminator()); + unsigned HeaderIdx = (RemainderLatchBR->getSuccessor(0) == Header ? 0 : 1); + MDBuilder MDB(RemainderLatchBR->getContext()); + MDNode *WeightNode = + HeaderIdx ? MDB.createBranchWeights(ExitWeight, BackEdgeWeight) + : MDB.createBranchWeights(BackEdgeWeight, ExitWeight); + RemainderLatchBR->setMetadata(LLVMContext::MD_prof, WeightNode); + } +} + /// Insert code in the prolog/epilog code when unrolling a loop with a /// run-time trip-count. /// @@ -788,6 +814,11 @@ bool llvm::UnrollRuntimeLoopRemainder( InsertTop, InsertBot, NewPreHeader, NewBlocks, LoopBlocks, VMap, DT, LI); + // Assign the maximum possible trip count as the back edge weight for the + // remainder loop if the original loop comes with a branch weight. + if (remainderLoop && !UnrollRemainder) + updateLatchBranchWeightsForRemainderLoop(L, remainderLoop, Count); + // Insert the cloned blocks into the function. F->getBasicBlockList().splice(InsertBot->getIterator(), F->getBasicBlockList(), diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp index 43363736684e..f0f423e9812a 100644 --- a/llvm/lib/Transforms/Utils/LoopUtils.cpp +++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp @@ -63,6 +63,7 @@ static cl::opt ForceReductionIntrinsic( static const char *LLVMLoopDisableNonforced = "llvm.loop.disable_nonforced"; static const char *LLVMLoopDisableLICM = "llvm.licm.disable"; +static const char *LLVMLoopMustProgress = "llvm.loop.mustprogress"; bool llvm::formDedicatedExitBlocks(Loop *L, DominatorTree *DT, LoopInfo *LI, MemorySSAUpdater *MSSAU, @@ -297,10 +298,24 @@ static Optional getOptionalBoolLoopAttribute(const Loop *TheLoop, llvm_unreachable("unexpected number of options"); } -static bool getBooleanLoopAttribute(const Loop *TheLoop, StringRef Name) { +bool llvm::getBooleanLoopAttribute(const Loop *TheLoop, StringRef Name) { return getOptionalBoolLoopAttribute(TheLoop, Name).getValueOr(false); } +Optional +llvm::getOptionalElementCountLoopAttribute(Loop *TheLoop) { + Optional Width = + getOptionalIntLoopAttribute(TheLoop, "llvm.loop.vectorize.width"); + + if (Width.hasValue()) { + Optional IsScalable = getOptionalIntLoopAttribute( + TheLoop, "llvm.loop.vectorize.scalable.enable"); + return ElementCount::get(*Width, IsScalable.getValueOr(false)); + } + + return None; +} + llvm::Optional llvm::getOptionalIntLoopAttribute(Loop *TheLoop, StringRef Name) { const MDOperand *AttrMD = @@ -334,7 +349,7 @@ Optional llvm::makeFollowupLoopID( bool Changed = false; if (InheritAllAttrs || InheritSomeAttrs) { - for (const MDOperand &Existing : drop_begin(OrigLoopID->operands(), 1)) { + for (const MDOperand &Existing : drop_begin(OrigLoopID->operands())) { MDNode *Op = cast(Existing.get()); auto InheritThisAttribute = [InheritSomeAttrs, @@ -371,7 +386,7 @@ Optional llvm::makeFollowupLoopID( continue; HasAnyFollowup = true; - for (const MDOperand &Option : drop_begin(FollowupNode->operands(), 1)) { + for (const MDOperand &Option : drop_begin(FollowupNode->operands())) { MDs.push_back(Option.get()); Changed = true; } @@ -404,6 +419,10 @@ bool llvm::hasDisableLICMTransformsHint(const Loop *L) { return getBooleanLoopAttribute(L, LLVMLoopDisableLICM); } +bool llvm::hasMustProgress(const Loop *L) { + return getBooleanLoopAttribute(L, LLVMLoopMustProgress); +} + TransformationMode llvm::hasUnrollTransformation(Loop *L) { if (getBooleanLoopAttribute(L, "llvm.loop.unroll.disable")) return TM_SuppressedByUser; @@ -450,14 +469,15 @@ TransformationMode llvm::hasVectorizeTransformation(Loop *L) { if (Enable == false) return TM_SuppressedByUser; - Optional VectorizeWidth = - getOptionalIntLoopAttribute(L, "llvm.loop.vectorize.width"); + Optional VectorizeWidth = + getOptionalElementCountLoopAttribute(L); Optional InterleaveCount = getOptionalIntLoopAttribute(L, "llvm.loop.interleave.count"); // 'Forcing' vector width and interleave count to one effectively disables // this tranformation. - if (Enable == true && VectorizeWidth == 1 && InterleaveCount == 1) + if (Enable == true && VectorizeWidth && VectorizeWidth->isScalar() && + InterleaveCount == 1) return TM_SuppressedByUser; if (getBooleanLoopAttribute(L, "llvm.loop.isvectorized")) @@ -466,10 +486,10 @@ TransformationMode llvm::hasVectorizeTransformation(Loop *L) { if (Enable == true) return TM_ForcedByUser; - if (VectorizeWidth == 1 && InterleaveCount == 1) + if ((VectorizeWidth && VectorizeWidth->isScalar()) && InterleaveCount == 1) return TM_Disable; - if (VectorizeWidth > 1 || InterleaveCount > 1) + if ((VectorizeWidth && VectorizeWidth->isVector()) || InterleaveCount > 1) return TM_Enable; if (hasDisableAllTransformsHint(L)) @@ -542,10 +562,6 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE, if (SE) SE->forgetLoop(L); - auto *ExitBlock = L->getUniqueExitBlock(); - assert(ExitBlock && "Should have a unique exit block!"); - assert(L->hasDedicatedExits() && "Loop should have dedicated exits!"); - auto *OldBr = dyn_cast(Preheader->getTerminator()); assert(OldBr && "Preheader must end with a branch"); assert(OldBr->isUnconditional() && "Preheader must have a single successor"); @@ -575,48 +591,63 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE, // deleting the backedge of the outer loop). If the outer loop is indeed a // non-loop, it will be deleted in a future iteration of loop deletion pass. IRBuilder<> Builder(OldBr); - Builder.CreateCondBr(Builder.getFalse(), L->getHeader(), ExitBlock); - // Remove the old branch. The conditional branch becomes a new terminator. - OldBr->eraseFromParent(); - - // Rewrite phis in the exit block to get their inputs from the Preheader - // instead of the exiting block. - for (PHINode &P : ExitBlock->phis()) { - // Set the zero'th element of Phi to be from the preheader and remove all - // other incoming values. Given the loop has dedicated exits, all other - // incoming values must be from the exiting blocks. - int PredIndex = 0; - P.setIncomingBlock(PredIndex, Preheader); - // Removes all incoming values from all other exiting blocks (including - // duplicate values from an exiting block). - // Nuke all entries except the zero'th entry which is the preheader entry. - // NOTE! We need to remove Incoming Values in the reverse order as done - // below, to keep the indices valid for deletion (removeIncomingValues - // updates getNumIncomingValues and shifts all values down into the operand - // being deleted). - for (unsigned i = 0, e = P.getNumIncomingValues() - 1; i != e; ++i) - P.removeIncomingValue(e - i, false); - - assert((P.getNumIncomingValues() == 1 && - P.getIncomingBlock(PredIndex) == Preheader) && - "Should have exactly one value and that's from the preheader!"); - } + auto *ExitBlock = L->getUniqueExitBlock(); DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager); - if (DT) { - DTU.applyUpdates({{DominatorTree::Insert, Preheader, ExitBlock}}); - if (MSSA) { - MSSAU->applyUpdates({{DominatorTree::Insert, Preheader, ExitBlock}}, *DT); - if (VerifyMemorySSA) - MSSA->verifyMemorySSA(); + if (ExitBlock) { + assert(ExitBlock && "Should have a unique exit block!"); + assert(L->hasDedicatedExits() && "Loop should have dedicated exits!"); + + Builder.CreateCondBr(Builder.getFalse(), L->getHeader(), ExitBlock); + // Remove the old branch. The conditional branch becomes a new terminator. + OldBr->eraseFromParent(); + + // Rewrite phis in the exit block to get their inputs from the Preheader + // instead of the exiting block. + for (PHINode &P : ExitBlock->phis()) { + // Set the zero'th element of Phi to be from the preheader and remove all + // other incoming values. Given the loop has dedicated exits, all other + // incoming values must be from the exiting blocks. + int PredIndex = 0; + P.setIncomingBlock(PredIndex, Preheader); + // Removes all incoming values from all other exiting blocks (including + // duplicate values from an exiting block). + // Nuke all entries except the zero'th entry which is the preheader entry. + // NOTE! We need to remove Incoming Values in the reverse order as done + // below, to keep the indices valid for deletion (removeIncomingValues + // updates getNumIncomingValues and shifts all values down into the + // operand being deleted). + for (unsigned i = 0, e = P.getNumIncomingValues() - 1; i != e; ++i) + P.removeIncomingValue(e - i, false); + + assert((P.getNumIncomingValues() == 1 && + P.getIncomingBlock(PredIndex) == Preheader) && + "Should have exactly one value and that's from the preheader!"); + } + + if (DT) { + DTU.applyUpdates({{DominatorTree::Insert, Preheader, ExitBlock}}); + if (MSSA) { + MSSAU->applyUpdates({{DominatorTree::Insert, Preheader, ExitBlock}}, + *DT); + if (VerifyMemorySSA) + MSSA->verifyMemorySSA(); + } } - } - // Disconnect the loop body by branching directly to its exit. - Builder.SetInsertPoint(Preheader->getTerminator()); - Builder.CreateBr(ExitBlock); - // Remove the old branch. - Preheader->getTerminator()->eraseFromParent(); + // Disconnect the loop body by branching directly to its exit. + Builder.SetInsertPoint(Preheader->getTerminator()); + Builder.CreateBr(ExitBlock); + // Remove the old branch. + Preheader->getTerminator()->eraseFromParent(); + } else { + assert(L->hasNoExitBlocks() && + "Loop should have either zero or one exit blocks."); + + Builder.SetInsertPoint(OldBr); + Builder.CreateUnreachable(); + Preheader->getTerminator()->eraseFromParent(); + } if (DT) { DTU.applyUpdates({{DominatorTree::Delete, Preheader, L->getHeader()}}); @@ -635,54 +666,58 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE, llvm::SmallDenseSet, 4> DeadDebugSet; llvm::SmallVector DeadDebugInst; - // Given LCSSA form is satisfied, we should not have users of instructions - // within the dead loop outside of the loop. However, LCSSA doesn't take - // unreachable uses into account. We handle them here. - // We could do it after drop all references (in this case all users in the - // loop will be already eliminated and we have less work to do but according - // to API doc of User::dropAllReferences only valid operation after dropping - // references, is deletion. So let's substitute all usages of - // instruction from the loop with undef value of corresponding type first. - for (auto *Block : L->blocks()) - for (Instruction &I : *Block) { - auto *Undef = UndefValue::get(I.getType()); - for (Value::use_iterator UI = I.use_begin(), E = I.use_end(); UI != E;) { - Use &U = *UI; - ++UI; - if (auto *Usr = dyn_cast(U.getUser())) - if (L->contains(Usr->getParent())) - continue; - // If we have a DT then we can check that uses outside a loop only in - // unreachable block. - if (DT) - assert(!DT->isReachableFromEntry(U) && - "Unexpected user in reachable block"); - U.set(Undef); + if (ExitBlock) { + // Given LCSSA form is satisfied, we should not have users of instructions + // within the dead loop outside of the loop. However, LCSSA doesn't take + // unreachable uses into account. We handle them here. + // We could do it after drop all references (in this case all users in the + // loop will be already eliminated and we have less work to do but according + // to API doc of User::dropAllReferences only valid operation after dropping + // references, is deletion. So let's substitute all usages of + // instruction from the loop with undef value of corresponding type first. + for (auto *Block : L->blocks()) + for (Instruction &I : *Block) { + auto *Undef = UndefValue::get(I.getType()); + for (Value::use_iterator UI = I.use_begin(), E = I.use_end(); + UI != E;) { + Use &U = *UI; + ++UI; + if (auto *Usr = dyn_cast(U.getUser())) + if (L->contains(Usr->getParent())) + continue; + // If we have a DT then we can check that uses outside a loop only in + // unreachable block. + if (DT) + assert(!DT->isReachableFromEntry(U) && + "Unexpected user in reachable block"); + U.set(Undef); + } + auto *DVI = dyn_cast(&I); + if (!DVI) + continue; + auto Key = + DeadDebugSet.find({DVI->getVariable(), DVI->getExpression()}); + if (Key != DeadDebugSet.end()) + continue; + DeadDebugSet.insert({DVI->getVariable(), DVI->getExpression()}); + DeadDebugInst.push_back(DVI); } - auto *DVI = dyn_cast(&I); - if (!DVI) - continue; - auto Key = DeadDebugSet.find({DVI->getVariable(), DVI->getExpression()}); - if (Key != DeadDebugSet.end()) - continue; - DeadDebugSet.insert({DVI->getVariable(), DVI->getExpression()}); - DeadDebugInst.push_back(DVI); - } - // After the loop has been deleted all the values defined and modified - // inside the loop are going to be unavailable. - // Since debug values in the loop have been deleted, inserting an undef - // dbg.value truncates the range of any dbg.value before the loop where the - // loop used to be. This is particularly important for constant values. - DIBuilder DIB(*ExitBlock->getModule()); - Instruction *InsertDbgValueBefore = ExitBlock->getFirstNonPHI(); - assert(InsertDbgValueBefore && - "There should be a non-PHI instruction in exit block, else these " - "instructions will have no parent."); - for (auto *DVI : DeadDebugInst) - DIB.insertDbgValueIntrinsic(UndefValue::get(Builder.getInt32Ty()), - DVI->getVariable(), DVI->getExpression(), - DVI->getDebugLoc(), InsertDbgValueBefore); + // After the loop has been deleted all the values defined and modified + // inside the loop are going to be unavailable. + // Since debug values in the loop have been deleted, inserting an undef + // dbg.value truncates the range of any dbg.value before the loop where the + // loop used to be. This is particularly important for constant values. + DIBuilder DIB(*ExitBlock->getModule()); + Instruction *InsertDbgValueBefore = ExitBlock->getFirstNonPHI(); + assert(InsertDbgValueBefore && + "There should be a non-PHI instruction in exit block, else these " + "instructions will have no parent."); + for (auto *DVI : DeadDebugInst) + DIB.insertDbgValueIntrinsic(UndefValue::get(Builder.getInt32Ty()), + DVI->getVariable(), DVI->getExpression(), + DVI->getDebugLoc(), InsertDbgValueBefore); + } // Remove the block from the reference counting scheme, so that we can // delete it freely later. @@ -726,6 +761,51 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE, } } +static Loop *getOutermostLoop(Loop *L) { + while (Loop *Parent = L->getParentLoop()) + L = Parent; + return L; +} + +void llvm::breakLoopBackedge(Loop *L, DominatorTree &DT, ScalarEvolution &SE, + LoopInfo &LI, MemorySSA *MSSA) { + auto *Latch = L->getLoopLatch(); + assert(Latch && "multiple latches not yet supported"); + auto *Header = L->getHeader(); + Loop *OutermostLoop = getOutermostLoop(L); + + SE.forgetLoop(L); + + // Note: By splitting the backedge, and then explicitly making it unreachable + // we gracefully handle corner cases such as non-bottom tested loops and the + // like. We also have the benefit of being able to reuse existing well tested + // code. It might be worth special casing the common bottom tested case at + // some point to avoid code churn. + + std::unique_ptr MSSAU; + if (MSSA) + MSSAU = std::make_unique(MSSA); + + auto *BackedgeBB = SplitEdge(Latch, Header, &DT, &LI, MSSAU.get()); + + DomTreeUpdater DTU(&DT, DomTreeUpdater::UpdateStrategy::Eager); + (void)changeToUnreachable(BackedgeBB->getTerminator(), /*UseTrap*/false, + /*PreserveLCSSA*/true, &DTU, MSSAU.get()); + + // Erase (and destroy) this loop instance. Handles relinking sub-loops + // and blocks within the loop as needed. + LI.erase(L); + + // If the loop we broke had a parent, then changeToUnreachable might have + // caused a block to be removed from the parent loop (see loop_nest_lcssa + // test case in zero-btc.ll for an example), thus changing the parent's + // exit blocks. If that happened, we need to rebuild LCSSA on the outermost + // loop which might have a had a block removed. + if (OutermostLoop != L) + formLCSSARecursively(*OutermostLoop, DT, &LI, &SE); +} + + /// Checks if \p L has single exit through latch block except possibly /// "deoptimizing" exits. Returns branch instruction terminating the loop /// latch if above check is successful, nullptr otherwise. @@ -838,30 +918,29 @@ bool llvm::hasIterationCountInvariantInParent(Loop *InnerLoop, return true; } -Value *llvm::createMinMaxOp(IRBuilderBase &Builder, - RecurrenceDescriptor::MinMaxRecurrenceKind RK, - Value *Left, Value *Right) { - CmpInst::Predicate P = CmpInst::ICMP_NE; +Value *llvm::createMinMaxOp(IRBuilderBase &Builder, RecurKind RK, Value *Left, + Value *Right) { + CmpInst::Predicate Pred; switch (RK) { default: llvm_unreachable("Unknown min/max recurrence kind"); - case RecurrenceDescriptor::MRK_UIntMin: - P = CmpInst::ICMP_ULT; + case RecurKind::UMin: + Pred = CmpInst::ICMP_ULT; break; - case RecurrenceDescriptor::MRK_UIntMax: - P = CmpInst::ICMP_UGT; + case RecurKind::UMax: + Pred = CmpInst::ICMP_UGT; break; - case RecurrenceDescriptor::MRK_SIntMin: - P = CmpInst::ICMP_SLT; + case RecurKind::SMin: + Pred = CmpInst::ICMP_SLT; break; - case RecurrenceDescriptor::MRK_SIntMax: - P = CmpInst::ICMP_SGT; + case RecurKind::SMax: + Pred = CmpInst::ICMP_SGT; break; - case RecurrenceDescriptor::MRK_FloatMin: - P = CmpInst::FCMP_OLT; + case RecurKind::FMin: + Pred = CmpInst::FCMP_OLT; break; - case RecurrenceDescriptor::MRK_FloatMax: - P = CmpInst::FCMP_OGT; + case RecurKind::FMax: + Pred = CmpInst::FCMP_OGT; break; } @@ -871,17 +950,15 @@ Value *llvm::createMinMaxOp(IRBuilderBase &Builder, FastMathFlags FMF; FMF.setFast(); Builder.setFastMathFlags(FMF); - Value *Cmp = Builder.CreateCmp(P, Left, Right, "rdx.minmax.cmp"); + Value *Cmp = Builder.CreateCmp(Pred, Left, Right, "rdx.minmax.cmp"); Value *Select = Builder.CreateSelect(Cmp, Left, Right, "rdx.minmax.select"); return Select; } // Helper to generate an ordered reduction. -Value * -llvm::getOrderedReduction(IRBuilderBase &Builder, Value *Acc, Value *Src, - unsigned Op, - RecurrenceDescriptor::MinMaxRecurrenceKind MinMaxKind, - ArrayRef RedOps) { +Value *llvm::getOrderedReduction(IRBuilderBase &Builder, Value *Acc, Value *Src, + unsigned Op, RecurKind RdxKind, + ArrayRef RedOps) { unsigned VF = cast(Src->getType())->getNumElements(); // Extract and apply reduction ops in ascending order: @@ -895,9 +972,9 @@ llvm::getOrderedReduction(IRBuilderBase &Builder, Value *Acc, Value *Src, Result = Builder.CreateBinOp((Instruction::BinaryOps)Op, Result, Ext, "bin.rdx"); } else { - assert(MinMaxKind != RecurrenceDescriptor::MRK_Invalid && + assert(RecurrenceDescriptor::isMinMaxRecurrenceKind(RdxKind) && "Invalid min/max"); - Result = createMinMaxOp(Builder, MinMaxKind, Result, Ext); + Result = createMinMaxOp(Builder, RdxKind, Result, Ext); } if (!RedOps.empty()) @@ -908,10 +985,9 @@ llvm::getOrderedReduction(IRBuilderBase &Builder, Value *Acc, Value *Src, } // Helper to generate a log2 shuffle reduction. -Value * -llvm::getShuffleReduction(IRBuilderBase &Builder, Value *Src, unsigned Op, - RecurrenceDescriptor::MinMaxRecurrenceKind MinMaxKind, - ArrayRef RedOps) { +Value *llvm::getShuffleReduction(IRBuilderBase &Builder, Value *Src, + unsigned Op, RecurKind RdxKind, + ArrayRef RedOps) { unsigned VF = cast(Src->getType())->getNumElements(); // VF is a power of 2 so we can emit the reduction using log2(VF) shuffles // and vector ops, reducing the set of values being computed by half each @@ -928,17 +1004,16 @@ llvm::getShuffleReduction(IRBuilderBase &Builder, Value *Src, unsigned Op, // Fill the rest of the mask with undef. std::fill(&ShuffleMask[i / 2], ShuffleMask.end(), -1); - Value *Shuf = Builder.CreateShuffleVector( - TmpVec, UndefValue::get(TmpVec->getType()), ShuffleMask, "rdx.shuf"); + Value *Shuf = Builder.CreateShuffleVector(TmpVec, ShuffleMask, "rdx.shuf"); if (Op != Instruction::ICmp && Op != Instruction::FCmp) { // The builder propagates its fast-math-flags setting. TmpVec = Builder.CreateBinOp((Instruction::BinaryOps)Op, TmpVec, Shuf, "bin.rdx"); } else { - assert(MinMaxKind != RecurrenceDescriptor::MRK_Invalid && + assert(RecurrenceDescriptor::isMinMaxRecurrenceKind(RdxKind) && "Invalid min/max"); - TmpVec = createMinMaxOp(Builder, MinMaxKind, TmpVec, Shuf); + TmpVec = createMinMaxOp(Builder, RdxKind, TmpVec, Shuf); } if (!RedOps.empty()) propagateIRFlags(TmpVec, RedOps); @@ -952,124 +1027,62 @@ llvm::getShuffleReduction(IRBuilderBase &Builder, Value *Src, unsigned Op, return Builder.CreateExtractElement(TmpVec, Builder.getInt32(0)); } -/// Create a simple vector reduction specified by an opcode and some -/// flags (if generating min/max reductions). -Value *llvm::createSimpleTargetReduction( - IRBuilderBase &Builder, const TargetTransformInfo *TTI, unsigned Opcode, - Value *Src, TargetTransformInfo::ReductionFlags Flags, - ArrayRef RedOps) { - auto *SrcVTy = cast(Src->getType()); - - std::function BuildFunc; - using RD = RecurrenceDescriptor; - RD::MinMaxRecurrenceKind MinMaxKind = RD::MRK_Invalid; - - switch (Opcode) { - case Instruction::Add: - BuildFunc = [&]() { return Builder.CreateAddReduce(Src); }; - break; - case Instruction::Mul: - BuildFunc = [&]() { return Builder.CreateMulReduce(Src); }; - break; - case Instruction::And: - BuildFunc = [&]() { return Builder.CreateAndReduce(Src); }; - break; - case Instruction::Or: - BuildFunc = [&]() { return Builder.CreateOrReduce(Src); }; - break; - case Instruction::Xor: - BuildFunc = [&]() { return Builder.CreateXorReduce(Src); }; - break; - case Instruction::FAdd: - BuildFunc = [&]() { - auto Rdx = Builder.CreateFAddReduce( - Constant::getNullValue(SrcVTy->getElementType()), Src); - return Rdx; - }; - break; - case Instruction::FMul: - BuildFunc = [&]() { - Type *Ty = SrcVTy->getElementType(); - auto Rdx = Builder.CreateFMulReduce(ConstantFP::get(Ty, 1.0), Src); - return Rdx; - }; - break; - case Instruction::ICmp: - if (Flags.IsMaxOp) { - MinMaxKind = Flags.IsSigned ? RD::MRK_SIntMax : RD::MRK_UIntMax; - BuildFunc = [&]() { - return Builder.CreateIntMaxReduce(Src, Flags.IsSigned); - }; - } else { - MinMaxKind = Flags.IsSigned ? RD::MRK_SIntMin : RD::MRK_UIntMin; - BuildFunc = [&]() { - return Builder.CreateIntMinReduce(Src, Flags.IsSigned); - }; - } - break; - case Instruction::FCmp: - if (Flags.IsMaxOp) { - MinMaxKind = RD::MRK_FloatMax; - BuildFunc = [&]() { return Builder.CreateFPMaxReduce(Src, Flags.NoNaN); }; - } else { - MinMaxKind = RD::MRK_FloatMin; - BuildFunc = [&]() { return Builder.CreateFPMinReduce(Src, Flags.NoNaN); }; - } - break; +Value *llvm::createSimpleTargetReduction(IRBuilderBase &Builder, + const TargetTransformInfo *TTI, + Value *Src, RecurKind RdxKind, + ArrayRef RedOps) { + unsigned Opcode = RecurrenceDescriptor::getOpcode(RdxKind); + TargetTransformInfo::ReductionFlags RdxFlags; + RdxFlags.IsMaxOp = RdxKind == RecurKind::SMax || RdxKind == RecurKind::UMax || + RdxKind == RecurKind::FMax; + RdxFlags.IsSigned = RdxKind == RecurKind::SMax || RdxKind == RecurKind::SMin; + if (!ForceReductionIntrinsic && + !TTI->useReductionIntrinsic(Opcode, Src->getType(), RdxFlags)) + return getShuffleReduction(Builder, Src, Opcode, RdxKind, RedOps); + + auto *SrcVecEltTy = cast(Src->getType())->getElementType(); + switch (RdxKind) { + case RecurKind::Add: + return Builder.CreateAddReduce(Src); + case RecurKind::Mul: + return Builder.CreateMulReduce(Src); + case RecurKind::And: + return Builder.CreateAndReduce(Src); + case RecurKind::Or: + return Builder.CreateOrReduce(Src); + case RecurKind::Xor: + return Builder.CreateXorReduce(Src); + case RecurKind::FAdd: + return Builder.CreateFAddReduce(ConstantFP::getNegativeZero(SrcVecEltTy), + Src); + case RecurKind::FMul: + return Builder.CreateFMulReduce(ConstantFP::get(SrcVecEltTy, 1.0), Src); + case RecurKind::SMax: + return Builder.CreateIntMaxReduce(Src, true); + case RecurKind::SMin: + return Builder.CreateIntMinReduce(Src, true); + case RecurKind::UMax: + return Builder.CreateIntMaxReduce(Src, false); + case RecurKind::UMin: + return Builder.CreateIntMinReduce(Src, false); + case RecurKind::FMax: + return Builder.CreateFPMaxReduce(Src); + case RecurKind::FMin: + return Builder.CreateFPMinReduce(Src); default: llvm_unreachable("Unhandled opcode"); - break; } - if (ForceReductionIntrinsic || - TTI->useReductionIntrinsic(Opcode, Src->getType(), Flags)) - return BuildFunc(); - return getShuffleReduction(Builder, Src, Opcode, MinMaxKind, RedOps); } -/// Create a vector reduction using a given recurrence descriptor. Value *llvm::createTargetReduction(IRBuilderBase &B, const TargetTransformInfo *TTI, - RecurrenceDescriptor &Desc, Value *Src, - bool NoNaN) { + RecurrenceDescriptor &Desc, Value *Src) { // TODO: Support in-order reductions based on the recurrence descriptor. - using RD = RecurrenceDescriptor; - RD::RecurrenceKind RecKind = Desc.getRecurrenceKind(); - TargetTransformInfo::ReductionFlags Flags; - Flags.NoNaN = NoNaN; - // All ops in the reduction inherit fast-math-flags from the recurrence // descriptor. IRBuilderBase::FastMathFlagGuard FMFGuard(B); B.setFastMathFlags(Desc.getFastMathFlags()); - - switch (RecKind) { - case RD::RK_FloatAdd: - return createSimpleTargetReduction(B, TTI, Instruction::FAdd, Src, Flags); - case RD::RK_FloatMult: - return createSimpleTargetReduction(B, TTI, Instruction::FMul, Src, Flags); - case RD::RK_IntegerAdd: - return createSimpleTargetReduction(B, TTI, Instruction::Add, Src, Flags); - case RD::RK_IntegerMult: - return createSimpleTargetReduction(B, TTI, Instruction::Mul, Src, Flags); - case RD::RK_IntegerAnd: - return createSimpleTargetReduction(B, TTI, Instruction::And, Src, Flags); - case RD::RK_IntegerOr: - return createSimpleTargetReduction(B, TTI, Instruction::Or, Src, Flags); - case RD::RK_IntegerXor: - return createSimpleTargetReduction(B, TTI, Instruction::Xor, Src, Flags); - case RD::RK_IntegerMinMax: { - RD::MinMaxRecurrenceKind MMKind = Desc.getMinMaxRecurrenceKind(); - Flags.IsMaxOp = (MMKind == RD::MRK_SIntMax || MMKind == RD::MRK_UIntMax); - Flags.IsSigned = (MMKind == RD::MRK_SIntMax || MMKind == RD::MRK_SIntMin); - return createSimpleTargetReduction(B, TTI, Instruction::ICmp, Src, Flags); - } - case RD::RK_FloatMinMax: { - Flags.IsMaxOp = Desc.getMinMaxRecurrenceKind() == RD::MRK_FloatMax; - return createSimpleTargetReduction(B, TTI, Instruction::FCmp, Src, Flags); - } - default: - llvm_unreachable("Unhandled RecKind"); - } + return createSimpleTargetReduction(B, TTI, Src, Desc.getRecurrenceKind()); } void llvm::propagateIRFlags(Value *I, ArrayRef VL, Value *OpValue) { @@ -1145,7 +1158,7 @@ static bool isValidRewrite(ScalarEvolution *SE, Value *FromVal, Value *ToVal) { // producing an expression involving multiple pointers. Until then, we must // bail out here. // - // Retrieve the pointer operand of the GEP. Don't use GetUnderlyingObject + // Retrieve the pointer operand of the GEP. Don't use getUnderlyingObject // because it understands lcssa phis while SCEV does not. Value *FromPtr = FromVal; Value *ToPtr = ToVal; @@ -1162,7 +1175,7 @@ static bool isValidRewrite(ScalarEvolution *SE, Value *FromVal, Value *ToVal) { // SCEV may have rewritten an expression that produces the GEP's pointer // operand. That's ok as long as the pointer operand has the same base - // pointer. Unlike GetUnderlyingObject(), getPointerBase() will find the + // pointer. Unlike getUnderlyingObject(), getPointerBase() will find the // base of a recurrence. This handles the case in which SCEV expansion // converts a pointer type recurrence into a nonrecurrent pointer base // indexed by an integer recurrence. diff --git a/llvm/lib/Transforms/Utils/LoopVersioning.cpp b/llvm/lib/Transforms/Utils/LoopVersioning.cpp index 16bd08c704ee..599bd1feb2bc 100644 --- a/llvm/lib/Transforms/Utils/LoopVersioning.cpp +++ b/llvm/lib/Transforms/Utils/LoopVersioning.cpp @@ -16,8 +16,12 @@ #include "llvm/ADT/ArrayRef.h" #include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/MemorySSA.h" +#include "llvm/Analysis/ScalarEvolution.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/MDBuilder.h" +#include "llvm/IR/PassManager.h" #include "llvm/InitializePasses.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -32,29 +36,22 @@ static cl::opt cl::desc("Add no-alias annotation for instructions that " "are disambiguated by memchecks")); -LoopVersioning::LoopVersioning(const LoopAccessInfo &LAI, Loop *L, LoopInfo *LI, - DominatorTree *DT, ScalarEvolution *SE, - bool UseLAIChecks) - : VersionedLoop(L), NonVersionedLoop(nullptr), LAI(LAI), LI(LI), DT(DT), +LoopVersioning::LoopVersioning(const LoopAccessInfo &LAI, + ArrayRef Checks, Loop *L, + LoopInfo *LI, DominatorTree *DT, + ScalarEvolution *SE) + : VersionedLoop(L), NonVersionedLoop(nullptr), + AliasChecks(Checks.begin(), Checks.end()), + Preds(LAI.getPSE().getUnionPredicate()), LAI(LAI), LI(LI), DT(DT), SE(SE) { - assert(L->getExitBlock() && "No single exit block"); - assert(L->isLoopSimplifyForm() && "Loop is not in loop-simplify form"); - if (UseLAIChecks) { - setAliasChecks(LAI.getRuntimePointerChecking()->getChecks()); - setSCEVChecks(LAI.getPSE().getUnionPredicate()); - } -} - -void LoopVersioning::setAliasChecks(ArrayRef Checks) { - AliasChecks = {Checks.begin(), Checks.end()}; -} - -void LoopVersioning::setSCEVChecks(SCEVUnionPredicate Check) { - Preds = std::move(Check); + assert(L->getUniqueExitBlock() && "No single exit block"); } void LoopVersioning::versionLoop( const SmallVectorImpl &DefsUsedOutside) { + assert(VersionedLoop->isLoopSimplifyForm() && + "Loop is not in loop-simplify form"); + Instruction *FirstCheckInst; Instruction *MemRuntimeCheck; Value *SCEVRuntimeCheck; @@ -67,11 +64,10 @@ void LoopVersioning::versionLoop( addRuntimeChecks(RuntimeCheckBB->getTerminator(), VersionedLoop, AliasChecks, RtPtrChecking.getSE()); - const SCEVUnionPredicate &Pred = LAI.getPSE().getUnionPredicate(); SCEVExpander Exp(*SE, RuntimeCheckBB->getModule()->getDataLayout(), "scev.check"); SCEVRuntimeCheck = - Exp.expandCodeForPredicate(&Pred, RuntimeCheckBB->getTerminator()); + Exp.expandCodeForPredicate(&Preds, RuntimeCheckBB->getTerminator()); auto *CI = dyn_cast(SCEVRuntimeCheck); // Discard the SCEV runtime check if it is always true. @@ -122,6 +118,11 @@ void LoopVersioning::versionLoop( // Adds the necessary PHI nodes for the versioned loops based on the // loop-defined values used outside of the loop. addPHINodes(DefsUsedOutside); + formDedicatedExitBlocks(NonVersionedLoop, DT, LI, nullptr, true); + formDedicatedExitBlocks(VersionedLoop, DT, LI, nullptr, true); + assert(NonVersionedLoop->isLoopSimplifyForm() && + VersionedLoop->isLoopSimplifyForm() && + "The versioned loops should be in simplify form."); } void LoopVersioning::addPHINodes( @@ -253,47 +254,59 @@ void LoopVersioning::annotateInstWithNoAlias(Instruction *VersionedInst, } namespace { +bool runImpl(LoopInfo *LI, function_ref GetLAA, + DominatorTree *DT, ScalarEvolution *SE) { + // Build up a worklist of inner-loops to version. This is necessary as the + // act of versioning a loop creates new loops and can invalidate iterators + // across the loops. + SmallVector Worklist; + + for (Loop *TopLevelLoop : *LI) + for (Loop *L : depth_first(TopLevelLoop)) + // We only handle inner-most loops. + if (L->isInnermost()) + Worklist.push_back(L); + + // Now walk the identified inner loops. + bool Changed = false; + for (Loop *L : Worklist) { + if (!L->isLoopSimplifyForm() || !L->isRotatedForm() || + !L->getExitingBlock()) + continue; + const LoopAccessInfo &LAI = GetLAA(*L); + if (!LAI.hasConvergentOp() && + (LAI.getNumRuntimePointerChecks() || + !LAI.getPSE().getUnionPredicate().isAlwaysTrue())) { + LoopVersioning LVer(LAI, LAI.getRuntimePointerChecking()->getChecks(), L, + LI, DT, SE); + LVer.versionLoop(); + LVer.annotateLoopWithNoAlias(); + Changed = true; + } + } + + return Changed; +} + /// Also expose this is a pass. Currently this is only used for /// unit-testing. It adds all memchecks necessary to remove all may-aliasing /// array accesses from the loop. -class LoopVersioningPass : public FunctionPass { +class LoopVersioningLegacyPass : public FunctionPass { public: - LoopVersioningPass() : FunctionPass(ID) { - initializeLoopVersioningPassPass(*PassRegistry::getPassRegistry()); + LoopVersioningLegacyPass() : FunctionPass(ID) { + initializeLoopVersioningLegacyPassPass(*PassRegistry::getPassRegistry()); } bool runOnFunction(Function &F) override { auto *LI = &getAnalysis().getLoopInfo(); - auto *LAA = &getAnalysis(); + auto GetLAA = [&](Loop &L) -> const LoopAccessInfo & { + return getAnalysis().getInfo(&L); + }; + auto *DT = &getAnalysis().getDomTree(); auto *SE = &getAnalysis().getSE(); - // Build up a worklist of inner-loops to version. This is necessary as the - // act of versioning a loop creates new loops and can invalidate iterators - // across the loops. - SmallVector Worklist; - - for (Loop *TopLevelLoop : *LI) - for (Loop *L : depth_first(TopLevelLoop)) - // We only handle inner-most loops. - if (L->empty()) - Worklist.push_back(L); - - // Now walk the identified inner loops. - bool Changed = false; - for (Loop *L : Worklist) { - const LoopAccessInfo &LAI = LAA->getInfo(L); - if (L->isLoopSimplifyForm() && !LAI.hasConvergentOp() && - (LAI.getNumRuntimePointerChecks() || - !LAI.getPSE().getUnionPredicate().isAlwaysTrue())) { - LoopVersioning LVer(LAI, L, LI, DT, SE); - LVer.versionLoop(); - LVer.annotateLoopWithNoAlias(); - Changed = true; - } - } - - return Changed; + return runImpl(LI, GetLAA, DT, SE); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -312,18 +325,45 @@ public: #define LVER_OPTION "loop-versioning" #define DEBUG_TYPE LVER_OPTION -char LoopVersioningPass::ID; +char LoopVersioningLegacyPass::ID; static const char LVer_name[] = "Loop Versioning"; -INITIALIZE_PASS_BEGIN(LoopVersioningPass, LVER_OPTION, LVer_name, false, false) +INITIALIZE_PASS_BEGIN(LoopVersioningLegacyPass, LVER_OPTION, LVer_name, false, + false) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopAccessLegacyAnalysis) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass) -INITIALIZE_PASS_END(LoopVersioningPass, LVER_OPTION, LVer_name, false, false) +INITIALIZE_PASS_END(LoopVersioningLegacyPass, LVER_OPTION, LVer_name, false, + false) namespace llvm { -FunctionPass *createLoopVersioningPass() { - return new LoopVersioningPass(); +FunctionPass *createLoopVersioningLegacyPass() { + return new LoopVersioningLegacyPass(); } + +PreservedAnalyses LoopVersioningPass::run(Function &F, + FunctionAnalysisManager &AM) { + auto &SE = AM.getResult(F); + auto &LI = AM.getResult(F); + auto &TTI = AM.getResult(F); + auto &DT = AM.getResult(F); + auto &TLI = AM.getResult(F); + auto &AA = AM.getResult(F); + auto &AC = AM.getResult(F); + MemorySSA *MSSA = EnableMSSALoopDependency + ? &AM.getResult(F).getMSSA() + : nullptr; + + auto &LAM = AM.getResult(F).getManager(); + auto GetLAA = [&](Loop &L) -> const LoopAccessInfo & { + LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, + TLI, TTI, nullptr, MSSA}; + return LAM.getResult(L, AR); + }; + + if (runImpl(&LI, GetLAA, &DT, &SE)) + return PreservedAnalyses::none(); + return PreservedAnalyses::all(); } +} // namespace llvm diff --git a/llvm/lib/Transforms/Utils/LowerInvoke.cpp b/llvm/lib/Transforms/Utils/LowerInvoke.cpp index 0b225e8abc4e..fe0ff5899d8f 100644 --- a/llvm/lib/Transforms/Utils/LowerInvoke.cpp +++ b/llvm/lib/Transforms/Utils/LowerInvoke.cpp @@ -48,7 +48,7 @@ static bool runImpl(Function &F) { bool Changed = false; for (BasicBlock &BB : F) if (InvokeInst *II = dyn_cast(BB.getTerminator())) { - SmallVector CallArgs(II->arg_begin(), II->arg_end()); + SmallVector CallArgs(II->args()); SmallVector OpBundles; II->getOperandBundlesAsDefs(OpBundles); // Insert a normal call instruction... diff --git a/llvm/lib/Transforms/Utils/LowerSwitch.cpp b/llvm/lib/Transforms/Utils/LowerSwitch.cpp index 34e836d9660f..ec8d7a7074cd 100644 --- a/llvm/lib/Transforms/Utils/LowerSwitch.cpp +++ b/llvm/lib/Transforms/Utils/LowerSwitch.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/LowerSwitch.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallPtrSet.h" @@ -26,6 +27,7 @@ #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" #include "llvm/IR/Instructions.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Value.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -55,9 +57,9 @@ namespace { } // end anonymous namespace +namespace { // Return true iff R is covered by Ranges. -static bool IsInRanges(const IntRange &R, - const std::vector &Ranges) { +bool IsInRanges(const IntRange &R, const std::vector &Ranges) { // Note: Ranges must be sorted, non-overlapping and non-adjacent. // Find the first range whose High field is >= R.High, @@ -68,120 +70,34 @@ static bool IsInRanges(const IntRange &R, return I != Ranges.end() && I->Low <= R.Low; } -namespace { - - /// Replace all SwitchInst instructions with chained branch instructions. - class LowerSwitch : public FunctionPass { - public: - // Pass identification, replacement for typeid - static char ID; - - LowerSwitch() : FunctionPass(ID) { - initializeLowerSwitchPass(*PassRegistry::getPassRegistry()); - } - - bool runOnFunction(Function &F) override; - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - } - - struct CaseRange { - ConstantInt* Low; - ConstantInt* High; - BasicBlock* BB; - - CaseRange(ConstantInt *low, ConstantInt *high, BasicBlock *bb) - : Low(low), High(high), BB(bb) {} - }; - - using CaseVector = std::vector; - using CaseItr = std::vector::iterator; - - private: - void processSwitchInst(SwitchInst *SI, - SmallPtrSetImpl &DeleteList, - AssumptionCache *AC, LazyValueInfo *LVI); - - BasicBlock *switchConvert(CaseItr Begin, CaseItr End, - ConstantInt *LowerBound, ConstantInt *UpperBound, - Value *Val, BasicBlock *Predecessor, - BasicBlock *OrigBlock, BasicBlock *Default, - const std::vector &UnreachableRanges); - BasicBlock *newLeafBlock(CaseRange &Leaf, Value *Val, - ConstantInt *LowerBound, ConstantInt *UpperBound, - BasicBlock *OrigBlock, BasicBlock *Default); - unsigned Clusterify(CaseVector &Cases, SwitchInst *SI); - }; - - /// The comparison function for sorting the switch case values in the vector. - /// WARNING: Case ranges should be disjoint! - struct CaseCmp { - bool operator()(const LowerSwitch::CaseRange& C1, - const LowerSwitch::CaseRange& C2) { - const ConstantInt* CI1 = cast(C1.Low); - const ConstantInt* CI2 = cast(C2.High); - return CI1->getValue().slt(CI2->getValue()); - } - }; - -} // end anonymous namespace - -char LowerSwitch::ID = 0; - -// Publicly exposed interface to pass... -char &llvm::LowerSwitchID = LowerSwitch::ID; - -INITIALIZE_PASS_BEGIN(LowerSwitch, "lowerswitch", - "Lower SwitchInst's to branches", false, false) -INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) -INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) -INITIALIZE_PASS_END(LowerSwitch, "lowerswitch", - "Lower SwitchInst's to branches", false, false) - -// createLowerSwitchPass - Interface to this file... -FunctionPass *llvm::createLowerSwitchPass() { - return new LowerSwitch(); -} - -bool LowerSwitch::runOnFunction(Function &F) { - LazyValueInfo *LVI = &getAnalysis().getLVI(); - auto *ACT = getAnalysisIfAvailable(); - AssumptionCache *AC = ACT ? &ACT->getAssumptionCache(F) : nullptr; - - bool Changed = false; - SmallPtrSet DeleteList; - - for (Function::iterator I = F.begin(), E = F.end(); I != E; ) { - BasicBlock *Cur = &*I++; // Advance over block so we don't traverse new blocks - - // If the block is a dead Default block that will be deleted later, don't - // waste time processing it. - if (DeleteList.count(Cur)) - continue; - - if (SwitchInst *SI = dyn_cast(Cur->getTerminator())) { - Changed = true; - processSwitchInst(SI, DeleteList, AC, LVI); - } - } - - for (BasicBlock* BB: DeleteList) { - LVI->eraseBlock(BB); - DeleteDeadBlock(BB); +struct CaseRange { + ConstantInt *Low; + ConstantInt *High; + BasicBlock *BB; + + CaseRange(ConstantInt *low, ConstantInt *high, BasicBlock *bb) + : Low(low), High(high), BB(bb) {} +}; + +using CaseVector = std::vector; +using CaseItr = std::vector::iterator; + +/// The comparison function for sorting the switch case values in the vector. +/// WARNING: Case ranges should be disjoint! +struct CaseCmp { + bool operator()(const CaseRange &C1, const CaseRange &C2) { + const ConstantInt *CI1 = cast(C1.Low); + const ConstantInt *CI2 = cast(C2.High); + return CI1->getValue().slt(CI2->getValue()); } - - return Changed; -} +}; /// Used for debugging purposes. LLVM_ATTRIBUTE_USED -static raw_ostream &operator<<(raw_ostream &O, - const LowerSwitch::CaseVector &C) { +raw_ostream &operator<<(raw_ostream &O, const CaseVector &C) { O << "["; - for (LowerSwitch::CaseVector::const_iterator B = C.begin(), E = C.end(); - B != E;) { + for (CaseVector::const_iterator B = C.begin(), E = C.end(); B != E;) { O << "[" << B->Low->getValue() << ", " << B->High->getValue() << "]"; if (++B != E) O << ", "; @@ -200,9 +116,9 @@ static raw_ostream &operator<<(raw_ostream &O, /// 2) Removed if subsequent incoming values now share the same case, i.e., /// multiple outcome edges are condensed into one. This is necessary to keep the /// number of phi values equal to the number of branches to SuccBB. -static void -fixPhis(BasicBlock *SuccBB, BasicBlock *OrigBB, BasicBlock *NewBB, - const unsigned NumMergedCases = std::numeric_limits::max()) { +void FixPhis( + BasicBlock *SuccBB, BasicBlock *OrigBB, BasicBlock *NewBB, + const unsigned NumMergedCases = std::numeric_limits::max()) { for (BasicBlock::iterator I = SuccBB->begin(), IE = SuccBB->getFirstNonPHI()->getIterator(); I != IE; ++I) { @@ -233,17 +149,80 @@ fixPhis(BasicBlock *SuccBB, BasicBlock *OrigBB, BasicBlock *NewBB, } } +/// Create a new leaf block for the binary lookup tree. It checks if the +/// switch's value == the case's value. If not, then it jumps to the default +/// branch. At this point in the tree, the value can't be another valid case +/// value, so the jump to the "default" branch is warranted. +BasicBlock *NewLeafBlock(CaseRange &Leaf, Value *Val, ConstantInt *LowerBound, + ConstantInt *UpperBound, BasicBlock *OrigBlock, + BasicBlock *Default) { + Function *F = OrigBlock->getParent(); + BasicBlock *NewLeaf = BasicBlock::Create(Val->getContext(), "LeafBlock"); + F->getBasicBlockList().insert(++OrigBlock->getIterator(), NewLeaf); + + // Emit comparison + ICmpInst *Comp = nullptr; + if (Leaf.Low == Leaf.High) { + // Make the seteq instruction... + Comp = + new ICmpInst(*NewLeaf, ICmpInst::ICMP_EQ, Val, Leaf.Low, "SwitchLeaf"); + } else { + // Make range comparison + if (Leaf.Low == LowerBound) { + // Val >= Min && Val <= Hi --> Val <= Hi + Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_SLE, Val, Leaf.High, + "SwitchLeaf"); + } else if (Leaf.High == UpperBound) { + // Val <= Max && Val >= Lo --> Val >= Lo + Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_SGE, Val, Leaf.Low, + "SwitchLeaf"); + } else if (Leaf.Low->isZero()) { + // Val >= 0 && Val <= Hi --> Val <=u Hi + Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_ULE, Val, Leaf.High, + "SwitchLeaf"); + } else { + // Emit V-Lo <=u Hi-Lo + Constant *NegLo = ConstantExpr::getNeg(Leaf.Low); + Instruction *Add = BinaryOperator::CreateAdd( + Val, NegLo, Val->getName() + ".off", NewLeaf); + Constant *UpperBound = ConstantExpr::getAdd(NegLo, Leaf.High); + Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_ULE, Add, UpperBound, + "SwitchLeaf"); + } + } + + // Make the conditional branch... + BasicBlock *Succ = Leaf.BB; + BranchInst::Create(Succ, Default, Comp, NewLeaf); + + // If there were any PHI nodes in this successor, rewrite one entry + // from OrigBlock to come from NewLeaf. + for (BasicBlock::iterator I = Succ->begin(); isa(I); ++I) { + PHINode *PN = cast(I); + // Remove all but one incoming entries from the cluster + uint64_t Range = Leaf.High->getSExtValue() - Leaf.Low->getSExtValue(); + for (uint64_t j = 0; j < Range; ++j) { + PN->removeIncomingValue(OrigBlock); + } + + int BlockIdx = PN->getBasicBlockIndex(OrigBlock); + assert(BlockIdx != -1 && "Switch didn't go to this successor??"); + PN->setIncomingBlock((unsigned)BlockIdx, NewLeaf); + } + + return NewLeaf; +} + /// Convert the switch statement into a binary lookup of the case values. /// The function recursively builds this tree. LowerBound and UpperBound are /// used to keep track of the bounds for Val that have already been checked by /// a block emitted by one of the previous calls to switchConvert in the call /// stack. -BasicBlock * -LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, ConstantInt *LowerBound, - ConstantInt *UpperBound, Value *Val, - BasicBlock *Predecessor, BasicBlock *OrigBlock, - BasicBlock *Default, - const std::vector &UnreachableRanges) { +BasicBlock *SwitchConvert(CaseItr Begin, CaseItr End, ConstantInt *LowerBound, + ConstantInt *UpperBound, Value *Val, + BasicBlock *Predecessor, BasicBlock *OrigBlock, + BasicBlock *Default, + const std::vector &UnreachableRanges) { assert(LowerBound && UpperBound && "Bounds must be initialized"); unsigned Size = End - Begin; @@ -255,10 +234,10 @@ LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, ConstantInt *LowerBound, if (Begin->Low == LowerBound && Begin->High == UpperBound) { unsigned NumMergedCases = 0; NumMergedCases = UpperBound->getSExtValue() - LowerBound->getSExtValue(); - fixPhis(Begin->BB, OrigBlock, Predecessor, NumMergedCases); + FixPhis(Begin->BB, OrigBlock, Predecessor, NumMergedCases); return Begin->BB; } - return newLeafBlock(*Begin, Val, LowerBound, UpperBound, OrigBlock, + return NewLeafBlock(*Begin, Val, LowerBound, UpperBound, OrigBlock, Default); } @@ -305,12 +284,12 @@ LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, ConstantInt *LowerBound, ICmpInst* Comp = new ICmpInst(ICmpInst::ICMP_SLT, Val, Pivot.Low, "Pivot"); - BasicBlock *LBranch = switchConvert(LHS.begin(), LHS.end(), LowerBound, - NewUpperBound, Val, NewNode, OrigBlock, - Default, UnreachableRanges); - BasicBlock *RBranch = switchConvert(RHS.begin(), RHS.end(), NewLowerBound, - UpperBound, Val, NewNode, OrigBlock, - Default, UnreachableRanges); + BasicBlock *LBranch = + SwitchConvert(LHS.begin(), LHS.end(), LowerBound, NewUpperBound, Val, + NewNode, OrigBlock, Default, UnreachableRanges); + BasicBlock *RBranch = + SwitchConvert(RHS.begin(), RHS.end(), NewLowerBound, UpperBound, Val, + NewNode, OrigBlock, Default, UnreachableRanges); F->getBasicBlockList().insert(++OrigBlock->getIterator(), NewNode); NewNode->getInstList().push_back(Comp); @@ -319,78 +298,10 @@ LowerSwitch::switchConvert(CaseItr Begin, CaseItr End, ConstantInt *LowerBound, return NewNode; } -/// Create a new leaf block for the binary lookup tree. It checks if the -/// switch's value == the case's value. If not, then it jumps to the default -/// branch. At this point in the tree, the value can't be another valid case -/// value, so the jump to the "default" branch is warranted. -BasicBlock *LowerSwitch::newLeafBlock(CaseRange &Leaf, Value *Val, - ConstantInt *LowerBound, - ConstantInt *UpperBound, - BasicBlock *OrigBlock, - BasicBlock *Default) { - Function* F = OrigBlock->getParent(); - BasicBlock* NewLeaf = BasicBlock::Create(Val->getContext(), "LeafBlock"); - F->getBasicBlockList().insert(++OrigBlock->getIterator(), NewLeaf); - - // Emit comparison - ICmpInst* Comp = nullptr; - if (Leaf.Low == Leaf.High) { - // Make the seteq instruction... - Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_EQ, Val, - Leaf.Low, "SwitchLeaf"); - } else { - // Make range comparison - if (Leaf.Low == LowerBound) { - // Val >= Min && Val <= Hi --> Val <= Hi - Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_SLE, Val, Leaf.High, - "SwitchLeaf"); - } else if (Leaf.High == UpperBound) { - // Val <= Max && Val >= Lo --> Val >= Lo - Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_SGE, Val, Leaf.Low, - "SwitchLeaf"); - } else if (Leaf.Low->isZero()) { - // Val >= 0 && Val <= Hi --> Val <=u Hi - Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_ULE, Val, Leaf.High, - "SwitchLeaf"); - } else { - // Emit V-Lo <=u Hi-Lo - Constant* NegLo = ConstantExpr::getNeg(Leaf.Low); - Instruction* Add = BinaryOperator::CreateAdd(Val, NegLo, - Val->getName()+".off", - NewLeaf); - Constant *UpperBound = ConstantExpr::getAdd(NegLo, Leaf.High); - Comp = new ICmpInst(*NewLeaf, ICmpInst::ICMP_ULE, Add, UpperBound, - "SwitchLeaf"); - } - } - - // Make the conditional branch... - BasicBlock* Succ = Leaf.BB; - BranchInst::Create(Succ, Default, Comp, NewLeaf); - - // If there were any PHI nodes in this successor, rewrite one entry - // from OrigBlock to come from NewLeaf. - for (BasicBlock::iterator I = Succ->begin(); isa(I); ++I) { - PHINode* PN = cast(I); - // Remove all but one incoming entries from the cluster - uint64_t Range = Leaf.High->getSExtValue() - - Leaf.Low->getSExtValue(); - for (uint64_t j = 0; j < Range; ++j) { - PN->removeIncomingValue(OrigBlock); - } - - int BlockIdx = PN->getBasicBlockIndex(OrigBlock); - assert(BlockIdx != -1 && "Switch didn't go to this successor??"); - PN->setIncomingBlock((unsigned)BlockIdx, NewLeaf); - } - - return NewLeaf; -} - /// Transform simple list of \p SI's cases into list of CaseRange's \p Cases. /// \post \p Cases wouldn't contain references to \p SI's default BB. /// \returns Number of \p SI's cases that do not reference \p SI's default BB. -unsigned LowerSwitch::Clusterify(CaseVector& Cases, SwitchInst *SI) { +unsigned Clusterify(CaseVector &Cases, SwitchInst *SI) { unsigned NumSimpleCases = 0; // Start with "simple" cases @@ -431,9 +342,9 @@ unsigned LowerSwitch::Clusterify(CaseVector& Cases, SwitchInst *SI) { /// Replace the specified switch instruction with a sequence of chained if-then /// insts in a balanced binary search. -void LowerSwitch::processSwitchInst(SwitchInst *SI, - SmallPtrSetImpl &DeleteList, - AssumptionCache *AC, LazyValueInfo *LVI) { +void ProcessSwitchInst(SwitchInst *SI, + SmallPtrSetImpl &DeleteList, + AssumptionCache *AC, LazyValueInfo *LVI) { BasicBlock *OrigBlock = SI->getParent(); Function *F = OrigBlock->getParent(); Value *Val = SI->getCondition(); // The value we are switching on... @@ -458,7 +369,7 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI, if (Cases.empty()) { BranchInst::Create(Default, OrigBlock); // Remove all the references from Default's PHIs to OrigBlock, but one. - fixPhis(Default, OrigBlock, OrigBlock); + FixPhis(Default, OrigBlock, OrigBlock); SI->eraseFromParent(); return; } @@ -489,7 +400,7 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI, // TODO Shouldn't this create a signed range? ConstantRange KnownBitsRange = ConstantRange::fromKnownBits(Known, /*IsSigned=*/false); - const ConstantRange LVIRange = LVI->getConstantRange(Val, OrigBlock, SI); + const ConstantRange LVIRange = LVI->getConstantRange(Val, SI); ConstantRange ValRange = KnownBitsRange.intersectWith(LVIRange); // We delegate removal of unreachable non-default cases to other passes. In // the unlikely event that some of them survived, we just conservatively @@ -563,10 +474,8 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI, // cases. assert(MaxPop > 0 && PopSucc); Default = PopSucc; - Cases.erase( - llvm::remove_if( - Cases, [PopSucc](const CaseRange &R) { return R.BB == PopSucc; }), - Cases.end()); + llvm::erase_if(Cases, + [PopSucc](const CaseRange &R) { return R.BB == PopSucc; }); // If there are no cases left, just branch. if (Cases.empty()) { @@ -592,12 +501,12 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI, BranchInst::Create(Default, NewDefault); BasicBlock *SwitchBlock = - switchConvert(Cases.begin(), Cases.end(), LowerBound, UpperBound, Val, + SwitchConvert(Cases.begin(), Cases.end(), LowerBound, UpperBound, Val, OrigBlock, OrigBlock, NewDefault, UnreachableRanges); // If there are entries in any PHI nodes for the default edge, make sure // to update them as well. - fixPhis(Default, OrigBlock, NewDefault); + FixPhis(Default, OrigBlock, NewDefault); // Branch to our shiny new if-then stuff... BranchInst::Create(SwitchBlock, OrigBlock); @@ -607,6 +516,84 @@ void LowerSwitch::processSwitchInst(SwitchInst *SI, OrigBlock->getInstList().erase(SI); // If the Default block has no more predecessors just add it to DeleteList. - if (pred_begin(OldDefault) == pred_end(OldDefault)) + if (pred_empty(OldDefault)) DeleteList.insert(OldDefault); } + +bool LowerSwitch(Function &F, LazyValueInfo *LVI, AssumptionCache *AC) { + bool Changed = false; + SmallPtrSet DeleteList; + + for (Function::iterator I = F.begin(), E = F.end(); I != E;) { + BasicBlock *Cur = + &*I++; // Advance over block so we don't traverse new blocks + + // If the block is a dead Default block that will be deleted later, don't + // waste time processing it. + if (DeleteList.count(Cur)) + continue; + + if (SwitchInst *SI = dyn_cast(Cur->getTerminator())) { + Changed = true; + ProcessSwitchInst(SI, DeleteList, AC, LVI); + } + } + + for (BasicBlock *BB : DeleteList) { + LVI->eraseBlock(BB); + DeleteDeadBlock(BB); + } + + return Changed; +} + +/// Replace all SwitchInst instructions with chained branch instructions. +class LowerSwitchLegacyPass : public FunctionPass { +public: + // Pass identification, replacement for typeid + static char ID; + + LowerSwitchLegacyPass() : FunctionPass(ID) { + initializeLowerSwitchLegacyPassPass(*PassRegistry::getPassRegistry()); + } + + bool runOnFunction(Function &F) override; + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + } +}; + +} // end anonymous namespace + +char LowerSwitchLegacyPass::ID = 0; + +// Publicly exposed interface to pass... +char &llvm::LowerSwitchID = LowerSwitchLegacyPass::ID; + +INITIALIZE_PASS_BEGIN(LowerSwitchLegacyPass, "lowerswitch", + "Lower SwitchInst's to branches", false, false) +INITIALIZE_PASS_DEPENDENCY(AssumptionCacheTracker) +INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) +INITIALIZE_PASS_END(LowerSwitchLegacyPass, "lowerswitch", + "Lower SwitchInst's to branches", false, false) + +// createLowerSwitchPass - Interface to this file... +FunctionPass *llvm::createLowerSwitchPass() { + return new LowerSwitchLegacyPass(); +} + +bool LowerSwitchLegacyPass::runOnFunction(Function &F) { + LazyValueInfo *LVI = &getAnalysis().getLVI(); + auto *ACT = getAnalysisIfAvailable(); + AssumptionCache *AC = ACT ? &ACT->getAssumptionCache(F) : nullptr; + return LowerSwitch(F, LVI, AC); +} + +PreservedAnalyses LowerSwitchPass::run(Function &F, + FunctionAnalysisManager &AM) { + LazyValueInfo *LVI = &AM.getResult(F); + AssumptionCache *AC = AM.getCachedResult(F); + return LowerSwitch(F, LVI, AC) ? PreservedAnalyses::none() + : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Utils/MatrixUtils.cpp b/llvm/lib/Transforms/Utils/MatrixUtils.cpp new file mode 100644 index 000000000000..6a137630deeb --- /dev/null +++ b/llvm/lib/Transforms/Utils/MatrixUtils.cpp @@ -0,0 +1,104 @@ +//===- MatrixUtils.cpp - Utilities to lower matrix intrinsics ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Utilities for generating tiled loops for matrix operations. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/MatrixUtils.h" +#include "llvm/Analysis/DomTreeUpdater.h" +#include "llvm/Analysis/LoopInfo.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Dominators.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Type.h" + +using namespace llvm; + +BasicBlock *TileInfo::CreateLoop(BasicBlock *Preheader, BasicBlock *Exit, + Value *Bound, Value *Step, StringRef Name, + IRBuilderBase &B, DomTreeUpdater &DTU, Loop *L, + LoopInfo &LI) { + LLVMContext &Ctx = Preheader->getContext(); + BasicBlock *Header = BasicBlock::Create( + Preheader->getContext(), Name + ".header", Preheader->getParent(), Exit); + BasicBlock *Body = BasicBlock::Create(Header->getContext(), Name + ".body", + Header->getParent(), Exit); + BasicBlock *Latch = BasicBlock::Create(Header->getContext(), Name + ".latch", + Header->getParent(), Exit); + + Type *I32Ty = Type::getInt64Ty(Ctx); + BranchInst::Create(Body, Header); + BranchInst::Create(Latch, Body); + PHINode *IV = + PHINode::Create(I32Ty, 2, Name + ".iv", Header->getTerminator()); + IV->addIncoming(ConstantInt::get(I32Ty, 0), Preheader); + + B.SetInsertPoint(Latch); + Value *Inc = B.CreateAdd(IV, Step, Name + ".step"); + Value *Cond = B.CreateICmpNE(Inc, Bound, Name + ".cond"); + BranchInst::Create(Header, Exit, Cond, Latch); + IV->addIncoming(Inc, Latch); + + BranchInst *PreheaderBr = cast(Preheader->getTerminator()); + BasicBlock *Tmp = PreheaderBr->getSuccessor(0); + PreheaderBr->setSuccessor(0, Header); + DTU.applyUpdatesPermissive({ + {DominatorTree::Delete, Preheader, Tmp}, + {DominatorTree::Insert, Header, Body}, + {DominatorTree::Insert, Body, Latch}, + {DominatorTree::Insert, Latch, Header}, + {DominatorTree::Insert, Latch, Exit}, + {DominatorTree::Insert, Preheader, Header}, + }); + + L->addBasicBlockToLoop(Header, LI); + L->addBasicBlockToLoop(Body, LI); + L->addBasicBlockToLoop(Latch, LI); + return Body; +} + +// Creates the following loop nest skeleton: +// for C = 0; C < NumColumns; C += TileSize +// for R = 0; R < NumRows; R += TileSize +// for K = 0; K < Inner ; K += TileSize +BasicBlock *TileInfo::CreateTiledLoops(BasicBlock *Start, BasicBlock *End, + IRBuilderBase &B, DomTreeUpdater &DTU, + LoopInfo &LI) { + Loop *ColLoop = LI.AllocateLoop(); + Loop *RowLoop = LI.AllocateLoop(); + Loop *InnerLoop = LI.AllocateLoop(); + RowLoop->addChildLoop(InnerLoop); + ColLoop->addChildLoop(RowLoop); + if (Loop *ParentL = LI.getLoopFor(Start)) + ParentL->addChildLoop(ColLoop); + else + LI.addTopLevelLoop(ColLoop); + + BasicBlock *ColBody = + CreateLoop(Start, End, B.getInt64(NumColumns), B.getInt64(TileSize), + "cols", B, DTU, ColLoop, LI); + BasicBlock *ColLatch = ColBody->getSingleSuccessor(); + BasicBlock *RowBody = + CreateLoop(ColBody, ColLatch, B.getInt64(NumRows), B.getInt64(TileSize), + "rows", B, DTU, RowLoop, LI); + RowLoopLatch = RowBody->getSingleSuccessor(); + + BasicBlock *InnerBody = + CreateLoop(RowBody, RowLoopLatch, B.getInt64(NumInner), + B.getInt64(TileSize), "inner", B, DTU, InnerLoop, LI); + InnerLoopLatch = InnerBody->getSingleSuccessor(); + ColumnLoopHeader = ColBody->getSinglePredecessor(); + RowLoopHeader = RowBody->getSinglePredecessor(); + InnerLoopHeader = InnerBody->getSinglePredecessor(); + CurrentRow = &*RowLoopHeader->begin(); + CurrentCol = &*ColumnLoopHeader->begin(); + CurrentK = &*InnerLoopHeader->begin(); + + return InnerBody; +} diff --git a/llvm/lib/Transforms/Utils/MetaRenamer.cpp b/llvm/lib/Transforms/Utils/MetaRenamer.cpp index 7f961dbaf4b4..e350320e7569 100644 --- a/llvm/lib/Transforms/Utils/MetaRenamer.cpp +++ b/llvm/lib/Transforms/Utils/MetaRenamer.cpp @@ -12,6 +12,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/MetaRenamer.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" @@ -25,6 +26,7 @@ #include "llvm/IR/GlobalVariable.h" #include "llvm/IR/Instruction.h" #include "llvm/IR/Module.h" +#include "llvm/IR/PassManager.h" #include "llvm/IR/Type.h" #include "llvm/IR/TypeFinder.h" #include "llvm/InitializePasses.h" @@ -40,123 +42,125 @@ static const char *const metaNames[] = { }; namespace { +// This PRNG is from the ISO C spec. It is intentionally simple and +// unsuitable for cryptographic use. We're just looking for enough +// variety to surprise and delight users. +struct PRNG { + unsigned long next; + + void srand(unsigned int seed) { next = seed; } + + int rand() { + next = next * 1103515245 + 12345; + return (unsigned int)(next / 65536) % 32768; + } +}; - // This PRNG is from the ISO C spec. It is intentionally simple and - // unsuitable for cryptographic use. We're just looking for enough - // variety to surprise and delight users. - struct PRNG { - unsigned long next; +struct Renamer { + Renamer(unsigned int seed) { prng.srand(seed); } - void srand(unsigned int seed) { - next = seed; - } + const char *newName() { + return metaNames[prng.rand() % array_lengthof(metaNames)]; + } - int rand() { - next = next * 1103515245 + 12345; - return (unsigned int)(next / 65536) % 32768; - } - }; + PRNG prng; +}; - struct Renamer { - Renamer(unsigned int seed) { - prng.srand(seed); - } +void MetaRename(Function &F) { + for (auto AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) + if (!AI->getType()->isVoidTy()) + AI->setName("arg"); - const char *newName() { - return metaNames[prng.rand() % array_lengthof(metaNames)]; - } + for (auto &BB : F) { + BB.setName("bb"); - PRNG prng; - }; + for (auto &I : BB) + if (!I.getType()->isVoidTy()) + I.setName("tmp"); + } +} - struct MetaRenamer : public ModulePass { - // Pass identification, replacement for typeid - static char ID; - - MetaRenamer() : ModulePass(ID) { - initializeMetaRenamerPass(*PassRegistry::getPassRegistry()); - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired(); - AU.setPreservesAll(); - } - - bool runOnModule(Module &M) override { - // Seed our PRNG with simple additive sum of ModuleID. We're looking to - // simply avoid always having the same function names, and we need to - // remain deterministic. - unsigned int randSeed = 0; - for (auto C : M.getModuleIdentifier()) - randSeed += C; - - Renamer renamer(randSeed); - - // Rename all aliases - for (auto AI = M.alias_begin(), AE = M.alias_end(); AI != AE; ++AI) { - StringRef Name = AI->getName(); - if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1)) - continue; - - AI->setName("alias"); - } - - // Rename all global variables - for (auto GI = M.global_begin(), GE = M.global_end(); GI != GE; ++GI) { - StringRef Name = GI->getName(); - if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1)) - continue; - - GI->setName("global"); - } - - // Rename all struct types - TypeFinder StructTypes; - StructTypes.run(M, true); - for (StructType *STy : StructTypes) { - if (STy->isLiteral() || STy->getName().empty()) continue; - - SmallString<128> NameStorage; - STy->setName((Twine("struct.") + - renamer.newName()).toStringRef(NameStorage)); - } - - // Rename all functions - for (auto &F : M) { - StringRef Name = F.getName(); - LibFunc Tmp; - // Leave library functions alone because their presence or absence could - // affect the behavior of other passes. - if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) || - getAnalysis().getTLI(F).getLibFunc( - F, Tmp)) - continue; - - // Leave @main alone. The output of -metarenamer might be passed to - // lli for execution and the latter needs a main entry point. - if (Name != "main") - F.setName(renamer.newName()); - - runOnFunction(F); - } - return true; - } - - bool runOnFunction(Function &F) { - for (auto AI = F.arg_begin(), AE = F.arg_end(); AI != AE; ++AI) - if (!AI->getType()->isVoidTy()) - AI->setName("arg"); - - for (auto &BB : F) { - BB.setName("bb"); - - for (auto &I : BB) - if (!I.getType()->isVoidTy()) - I.setName("tmp"); - } - return true; - } - }; +void MetaRename(Module &M, + function_ref GetTLI) { + // Seed our PRNG with simple additive sum of ModuleID. We're looking to + // simply avoid always having the same function names, and we need to + // remain deterministic. + unsigned int randSeed = 0; + for (auto C : M.getModuleIdentifier()) + randSeed += C; + + Renamer renamer(randSeed); + + // Rename all aliases + for (auto AI = M.alias_begin(), AE = M.alias_end(); AI != AE; ++AI) { + StringRef Name = AI->getName(); + if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1)) + continue; + + AI->setName("alias"); + } + + // Rename all global variables + for (auto GI = M.global_begin(), GE = M.global_end(); GI != GE; ++GI) { + StringRef Name = GI->getName(); + if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1)) + continue; + + GI->setName("global"); + } + + // Rename all struct types + TypeFinder StructTypes; + StructTypes.run(M, true); + for (StructType *STy : StructTypes) { + if (STy->isLiteral() || STy->getName().empty()) + continue; + + SmallString<128> NameStorage; + STy->setName( + (Twine("struct.") + renamer.newName()).toStringRef(NameStorage)); + } + + // Rename all functions + for (auto &F : M) { + StringRef Name = F.getName(); + LibFunc Tmp; + // Leave library functions alone because their presence or absence could + // affect the behavior of other passes. + if (Name.startswith("llvm.") || (!Name.empty() && Name[0] == 1) || + GetTLI(F).getLibFunc(F, Tmp)) + continue; + + // Leave @main alone. The output of -metarenamer might be passed to + // lli for execution and the latter needs a main entry point. + if (Name != "main") + F.setName(renamer.newName()); + + MetaRename(F); + } +} + +struct MetaRenamer : public ModulePass { + // Pass identification, replacement for typeid + static char ID; + + MetaRenamer() : ModulePass(ID) { + initializeMetaRenamerPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.addRequired(); + AU.setPreservesAll(); + } + + bool runOnModule(Module &M) override { + auto GetTLI = [this](Function &F) -> TargetLibraryInfo & { + return this->getAnalysis().getTLI(F); + }; + MetaRename(M, GetTLI); + return true; + } +}; } // end anonymous namespace @@ -175,3 +179,14 @@ INITIALIZE_PASS_END(MetaRenamer, "metarenamer", ModulePass *llvm::createMetaRenamerPass() { return new MetaRenamer(); } + +PreservedAnalyses MetaRenamerPass::run(Module &M, ModuleAnalysisManager &AM) { + FunctionAnalysisManager &FAM = + AM.getResult(M).getManager(); + auto GetTLI = [&FAM](Function &F) -> TargetLibraryInfo & { + return FAM.getResult(F); + }; + MetaRename(M, GetTLI); + + return PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Utils/MisExpect.cpp b/llvm/lib/Transforms/Utils/MisExpect.cpp deleted file mode 100644 index a16ca1fb8efa..000000000000 --- a/llvm/lib/Transforms/Utils/MisExpect.cpp +++ /dev/null @@ -1,178 +0,0 @@ -//===--- MisExpect.cpp - Check the use of llvm.expect with PGO data -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit warnings for potentially incorrect usage of the -// llvm.expect intrinsic. This utility extracts the threshold values from -// metadata associated with the instrumented Branch or Switch instruction. The -// threshold values are then used to determine if a warning should be emmited. -// -// MisExpect metadata is generated when llvm.expect intrinsics are lowered see -// LowerExpectIntrinsic.cpp -// -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Utils/MisExpect.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Analysis/OptimizationRemarkEmitter.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/Support/BranchProbability.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FormatVariadic.h" -#include -#include -#include - -#define DEBUG_TYPE "misexpect" - -using namespace llvm; -using namespace misexpect; - -namespace llvm { - -// Command line option to enable/disable the warning when profile data suggests -// a mismatch with the use of the llvm.expect intrinsic -static cl::opt PGOWarnMisExpect( - "pgo-warn-misexpect", cl::init(false), cl::Hidden, - cl::desc("Use this option to turn on/off " - "warnings about incorrect usage of llvm.expect intrinsics.")); - -} // namespace llvm - -namespace { - -Instruction *getOprndOrInst(Instruction *I) { - assert(I != nullptr && "MisExpect target Instruction cannot be nullptr"); - Instruction *Ret = nullptr; - if (auto *B = dyn_cast(I)) { - Ret = dyn_cast(B->getCondition()); - } - // TODO: Find a way to resolve condition location for switches - // Using the condition of the switch seems to often resolve to an earlier - // point in the program, i.e. the calculation of the switch condition, rather - // than the switches location in the source code. Thus, we should use the - // instruction to get source code locations rather than the condition to - // improve diagnostic output, such as the caret. If the same problem exists - // for branch instructions, then we should remove this function and directly - // use the instruction - // - // else if (auto S = dyn_cast(I)) { - // Ret = I; - //} - return Ret ? Ret : I; -} - -void emitMisexpectDiagnostic(Instruction *I, LLVMContext &Ctx, - uint64_t ProfCount, uint64_t TotalCount) { - double PercentageCorrect = (double)ProfCount / TotalCount; - auto PerString = - formatv("{0:P} ({1} / {2})", PercentageCorrect, ProfCount, TotalCount); - auto RemStr = formatv( - "Potential performance regression from use of the llvm.expect intrinsic: " - "Annotation was correct on {0} of profiled executions.", - PerString); - Twine Msg(PerString); - Instruction *Cond = getOprndOrInst(I); - if (PGOWarnMisExpect) - Ctx.diagnose(DiagnosticInfoMisExpect(Cond, Msg)); - OptimizationRemarkEmitter ORE(I->getParent()->getParent()); - ORE.emit(OptimizationRemark(DEBUG_TYPE, "misexpect", Cond) << RemStr.str()); -} - -} // namespace - -namespace llvm { -namespace misexpect { - -void verifyMisExpect(Instruction *I, const SmallVector &Weights, - LLVMContext &Ctx) { - if (auto *MisExpectData = I->getMetadata(LLVMContext::MD_misexpect)) { - auto *MisExpectDataName = dyn_cast(MisExpectData->getOperand(0)); - if (MisExpectDataName && - MisExpectDataName->getString().equals("misexpect")) { - LLVM_DEBUG(llvm::dbgs() << "------------------\n"); - LLVM_DEBUG(llvm::dbgs() - << "Function: " << I->getFunction()->getName() << "\n"); - LLVM_DEBUG(llvm::dbgs() << "Instruction: " << *I << ":\n"); - LLVM_DEBUG(for (int Idx = 0, Size = Weights.size(); Idx < Size; ++Idx) { - llvm::dbgs() << "Weights[" << Idx << "] = " << Weights[Idx] << "\n"; - }); - - // extract values from misexpect metadata - const auto *IndexCint = - mdconst::dyn_extract(MisExpectData->getOperand(1)); - const auto *LikelyCInt = - mdconst::dyn_extract(MisExpectData->getOperand(2)); - const auto *UnlikelyCInt = - mdconst::dyn_extract(MisExpectData->getOperand(3)); - - if (!IndexCint || !LikelyCInt || !UnlikelyCInt) - return; - - const uint64_t Index = IndexCint->getZExtValue(); - const uint64_t LikelyBranchWeight = LikelyCInt->getZExtValue(); - const uint64_t UnlikelyBranchWeight = UnlikelyCInt->getZExtValue(); - const uint64_t ProfileCount = Weights[Index]; - const uint64_t CaseTotal = std::accumulate( - Weights.begin(), Weights.end(), (uint64_t)0, std::plus()); - const uint64_t NumUnlikelyTargets = Weights.size() - 1; - - const uint64_t TotalBranchWeight = - LikelyBranchWeight + (UnlikelyBranchWeight * NumUnlikelyTargets); - - const llvm::BranchProbability LikelyThreshold(LikelyBranchWeight, - TotalBranchWeight); - uint64_t ScaledThreshold = LikelyThreshold.scale(CaseTotal); - - LLVM_DEBUG(llvm::dbgs() - << "Unlikely Targets: " << NumUnlikelyTargets << ":\n"); - LLVM_DEBUG(llvm::dbgs() << "Profile Count: " << ProfileCount << ":\n"); - LLVM_DEBUG(llvm::dbgs() - << "Scaled Threshold: " << ScaledThreshold << ":\n"); - LLVM_DEBUG(llvm::dbgs() << "------------------\n"); - if (ProfileCount < ScaledThreshold) - emitMisexpectDiagnostic(I, Ctx, ProfileCount, CaseTotal); - } - } -} - -void checkFrontendInstrumentation(Instruction &I) { - if (auto *MD = I.getMetadata(LLVMContext::MD_prof)) { - unsigned NOps = MD->getNumOperands(); - - // Only emit misexpect diagnostics if at least 2 branch weights are present. - // Less than 2 branch weights means that the profiling metadata is: - // 1) incorrect/corrupted - // 2) not branch weight metadata - // 3) completely deterministic - // In these cases we should not emit any diagnostic related to misexpect. - if (NOps < 3) - return; - - // Operand 0 is a string tag "branch_weights" - if (MDString *Tag = cast(MD->getOperand(0))) { - if (Tag->getString().equals("branch_weights")) { - SmallVector RealWeights(NOps - 1); - for (unsigned i = 1; i < NOps; i++) { - ConstantInt *Value = - mdconst::dyn_extract(MD->getOperand(i)); - RealWeights[i - 1] = Value->getZExtValue(); - } - verifyMisExpect(&I, RealWeights, I.getContext()); - } - } - } -} - -} // namespace misexpect -} // namespace llvm -#undef DEBUG_TYPE diff --git a/llvm/lib/Transforms/Utils/PredicateInfo.cpp b/llvm/lib/Transforms/Utils/PredicateInfo.cpp index 99b64a7462f6..3312a6f9459b 100644 --- a/llvm/lib/Transforms/Utils/PredicateInfo.cpp +++ b/llvm/lib/Transforms/Utils/PredicateInfo.cpp @@ -53,6 +53,10 @@ static cl::opt VerifyPredicateInfo( DEBUG_COUNTER(RenameCounter, "predicateinfo-rename", "Controls which variables are renamed with predicateinfo"); +// Maximum number of conditions considered for renaming for each branch/assume. +// This limits renaming of deep and/or chains. +static const unsigned MaxCondsPerBranch = 8; + namespace { // Given a predicate info that is a type of branching terminator, get the // branching block. @@ -367,6 +371,13 @@ void PredicateInfoBuilder::convertUsesToDFSOrdered( } } +bool shouldRename(Value *V) { + // Only want real values, not constants. Additionally, operands with one use + // are only being used in the comparison, which means they will not be useful + // for us to consider for predicateinfo. + return (isa(V) || isa(V)) && !V->hasOneUse(); +} + // Collect relevant operations from Comparison that we may want to insert copies // for. void collectCmpOps(CmpInst *Comparison, SmallVectorImpl &CmpOperands) { @@ -374,15 +385,9 @@ void collectCmpOps(CmpInst *Comparison, SmallVectorImpl &CmpOperands) { auto *Op1 = Comparison->getOperand(1); if (Op0 == Op1) return; - CmpOperands.push_back(Comparison); - // Only want real values, not constants. Additionally, operands with one use - // are only being used in the comparison, which means they will not be useful - // for us to consider for predicateinfo. - // - if ((isa(Op0) || isa(Op0)) && !Op0->hasOneUse()) - CmpOperands.push_back(Op0); - if ((isa(Op1) || isa(Op1)) && !Op1->hasOneUse()) - CmpOperands.push_back(Op1); + + CmpOperands.push_back(Op0); + CmpOperands.push_back(Op1); } // Add Op, PB to the list of value infos for Op, and mark Op to be renamed. @@ -400,38 +405,32 @@ void PredicateInfoBuilder::addInfoFor(SmallVectorImpl &OpsToRename, void PredicateInfoBuilder::processAssume( IntrinsicInst *II, BasicBlock *AssumeBB, SmallVectorImpl &OpsToRename) { - // See if we have a comparison we support - SmallVector CmpOperands; - SmallVector ConditionsToProcess; - CmpInst::Predicate Pred; - Value *Operand = II->getOperand(0); - if (m_c_And(m_Cmp(Pred, m_Value(), m_Value()), - m_Cmp(Pred, m_Value(), m_Value())) - .match(II->getOperand(0))) { - ConditionsToProcess.push_back(cast(Operand)->getOperand(0)); - ConditionsToProcess.push_back(cast(Operand)->getOperand(1)); - ConditionsToProcess.push_back(Operand); - } else if (isa(Operand)) { - - ConditionsToProcess.push_back(Operand); - } - for (auto Cond : ConditionsToProcess) { - if (auto *Cmp = dyn_cast(Cond)) { - collectCmpOps(Cmp, CmpOperands); - // Now add our copy infos for our operands - for (auto *Op : CmpOperands) { - auto *PA = new PredicateAssume(Op, II, Cmp); - addInfoFor(OpsToRename, Op, PA); + SmallVector Worklist; + SmallPtrSet Visited; + Worklist.push_back(II->getOperand(0)); + while (!Worklist.empty()) { + Value *Cond = Worklist.pop_back_val(); + if (!Visited.insert(Cond).second) + continue; + if (Visited.size() > MaxCondsPerBranch) + break; + + Value *Op0, *Op1; + if (match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { + Worklist.push_back(Op1); + Worklist.push_back(Op0); + } + + SmallVector Values; + Values.push_back(Cond); + if (auto *Cmp = dyn_cast(Cond)) + collectCmpOps(Cmp, Values); + + for (Value *V : Values) { + if (shouldRename(V)) { + auto *PA = new PredicateAssume(V, II, Cond); + addInfoFor(OpsToRename, V, PA); } - CmpOperands.clear(); - } else if (auto *BinOp = dyn_cast(Cond)) { - // Otherwise, it should be an AND. - assert(BinOp->getOpcode() == Instruction::And && - "Should have been an AND"); - auto *PA = new PredicateAssume(BinOp, II, BinOp); - addInfoFor(OpsToRename, BinOp, PA); - } else { - llvm_unreachable("Unknown type of condition"); } } } @@ -443,68 +442,46 @@ void PredicateInfoBuilder::processBranch( SmallVectorImpl &OpsToRename) { BasicBlock *FirstBB = BI->getSuccessor(0); BasicBlock *SecondBB = BI->getSuccessor(1); - SmallVector SuccsToProcess; - SuccsToProcess.push_back(FirstBB); - SuccsToProcess.push_back(SecondBB); - SmallVector ConditionsToProcess; - - auto InsertHelper = [&](Value *Op, bool isAnd, bool isOr, Value *Cond) { - for (auto *Succ : SuccsToProcess) { - // Don't try to insert on a self-edge. This is mainly because we will - // eliminate during renaming anyway. - if (Succ == BranchBB) - continue; - bool TakenEdge = (Succ == FirstBB); - // For and, only insert on the true edge - // For or, only insert on the false edge - if ((isAnd && !TakenEdge) || (isOr && TakenEdge)) + + for (BasicBlock *Succ : {FirstBB, SecondBB}) { + bool TakenEdge = Succ == FirstBB; + // Don't try to insert on a self-edge. This is mainly because we will + // eliminate during renaming anyway. + if (Succ == BranchBB) + continue; + + SmallVector Worklist; + SmallPtrSet Visited; + Worklist.push_back(BI->getCondition()); + while (!Worklist.empty()) { + Value *Cond = Worklist.pop_back_val(); + if (!Visited.insert(Cond).second) continue; - PredicateBase *PB = - new PredicateBranch(Op, BranchBB, Succ, Cond, TakenEdge); - addInfoFor(OpsToRename, Op, PB); - if (!Succ->getSinglePredecessor()) - EdgeUsesOnly.insert({BranchBB, Succ}); - } - }; + if (Visited.size() > MaxCondsPerBranch) + break; + + Value *Op0, *Op1; + if (TakenEdge ? match(Cond, m_LogicalAnd(m_Value(Op0), m_Value(Op1))) + : match(Cond, m_LogicalOr(m_Value(Op0), m_Value(Op1)))) { + Worklist.push_back(Op1); + Worklist.push_back(Op0); + } - // Match combinations of conditions. - CmpInst::Predicate Pred; - bool isAnd = false; - bool isOr = false; - SmallVector CmpOperands; - if (match(BI->getCondition(), m_And(m_Cmp(Pred, m_Value(), m_Value()), - m_Cmp(Pred, m_Value(), m_Value()))) || - match(BI->getCondition(), m_Or(m_Cmp(Pred, m_Value(), m_Value()), - m_Cmp(Pred, m_Value(), m_Value())))) { - auto *BinOp = cast(BI->getCondition()); - if (BinOp->getOpcode() == Instruction::And) - isAnd = true; - else if (BinOp->getOpcode() == Instruction::Or) - isOr = true; - ConditionsToProcess.push_back(BinOp->getOperand(0)); - ConditionsToProcess.push_back(BinOp->getOperand(1)); - ConditionsToProcess.push_back(BI->getCondition()); - } else if (isa(BI->getCondition())) { - ConditionsToProcess.push_back(BI->getCondition()); - } - for (auto Cond : ConditionsToProcess) { - if (auto *Cmp = dyn_cast(Cond)) { - collectCmpOps(Cmp, CmpOperands); - // Now add our copy infos for our operands - for (auto *Op : CmpOperands) - InsertHelper(Op, isAnd, isOr, Cmp); - } else if (auto *BinOp = dyn_cast(Cond)) { - // This must be an AND or an OR. - assert((BinOp->getOpcode() == Instruction::And || - BinOp->getOpcode() == Instruction::Or) && - "Should have been an AND or an OR"); - // The actual value of the binop is not subject to the same restrictions - // as the comparison. It's either true or false on the true/false branch. - InsertHelper(BinOp, false, false, BinOp); - } else { - llvm_unreachable("Unknown type of condition"); + SmallVector Values; + Values.push_back(Cond); + if (auto *Cmp = dyn_cast(Cond)) + collectCmpOps(Cmp, Values); + + for (Value *V : Values) { + if (shouldRename(V)) { + PredicateBase *PB = + new PredicateBranch(V, BranchBB, Succ, Cond, TakenEdge); + addInfoFor(OpsToRename, V, PB); + if (!Succ->getSinglePredecessor()) + EdgeUsesOnly.insert({BranchBB, Succ}); + } + } } - CmpOperands.clear(); } } // Process a block terminating switch, and place relevant operations to be @@ -822,6 +799,56 @@ PredicateInfo::~PredicateInfo() { } } +Optional PredicateBase::getConstraint() const { + switch (Type) { + case PT_Assume: + case PT_Branch: { + bool TrueEdge = true; + if (auto *PBranch = dyn_cast(this)) + TrueEdge = PBranch->TrueEdge; + + if (Condition == RenamedOp) { + return {{CmpInst::ICMP_EQ, + TrueEdge ? ConstantInt::getTrue(Condition->getType()) + : ConstantInt::getFalse(Condition->getType())}}; + } + + CmpInst *Cmp = dyn_cast(Condition); + if (!Cmp) { + // TODO: Make this an assertion once RenamedOp is fully accurate. + return None; + } + + CmpInst::Predicate Pred; + Value *OtherOp; + if (Cmp->getOperand(0) == RenamedOp) { + Pred = Cmp->getPredicate(); + OtherOp = Cmp->getOperand(1); + } else if (Cmp->getOperand(1) == RenamedOp) { + Pred = Cmp->getSwappedPredicate(); + OtherOp = Cmp->getOperand(0); + } else { + // TODO: Make this an assertion once RenamedOp is fully accurate. + return None; + } + + // Invert predicate along false edge. + if (!TrueEdge) + Pred = CmpInst::getInversePredicate(Pred); + + return {{Pred, OtherOp}}; + } + case PT_Switch: + if (Condition != RenamedOp) { + // TODO: Make this an assertion once RenamedOp is fully accurate. + return None; + } + + return {{CmpInst::ICMP_EQ, cast(this)->CaseValue}}; + } + llvm_unreachable("Unknown predicate type"); +} + void PredicateInfo::verifyPredicateInfo() const {} char PredicateInfoPrinterLegacyPass::ID = 0; diff --git a/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp b/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp index c7e9c919ec47..86bbb6a889e6 100644 --- a/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ b/llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -62,10 +62,6 @@ STATISTIC(NumDeadAlloca, "Number of dead alloca's removed"); STATISTIC(NumPHIInsert, "Number of PHI nodes inserted"); bool llvm::isAllocaPromotable(const AllocaInst *AI) { - // FIXME: If the memory unit is of pointer or integer type, we can permit - // assignments to subsections of the memory unit. - unsigned AS = AI->getType()->getAddressSpace(); - // Only allow direct and non-volatile loads and stores... for (const User *U : AI->users()) { if (const LoadInst *LI = dyn_cast(U)) { @@ -81,19 +77,18 @@ bool llvm::isAllocaPromotable(const AllocaInst *AI) { if (SI->isVolatile()) return false; } else if (const IntrinsicInst *II = dyn_cast(U)) { - if (!II->isLifetimeStartOrEnd()) + if (!II->isLifetimeStartOrEnd() && !II->isDroppable()) return false; } else if (const BitCastInst *BCI = dyn_cast(U)) { - if (BCI->getType() != Type::getInt8PtrTy(U->getContext(), AS)) - return false; - if (!onlyUsedByLifetimeMarkers(BCI)) + if (!onlyUsedByLifetimeMarkersOrDroppableInsts(BCI)) return false; } else if (const GetElementPtrInst *GEPI = dyn_cast(U)) { - if (GEPI->getType() != Type::getInt8PtrTy(U->getContext(), AS)) - return false; if (!GEPI->hasAllZeroIndices()) return false; - if (!onlyUsedByLifetimeMarkers(GEPI)) + if (!onlyUsedByLifetimeMarkersOrDroppableInsts(GEPI)) + return false; + } else if (const AddrSpaceCastInst *ASCI = dyn_cast(U)) { + if (!onlyUsedByLifetimeMarkers(ASCI)) return false; } else { return false; @@ -106,6 +101,8 @@ bool llvm::isAllocaPromotable(const AllocaInst *AI) { namespace { struct AllocaInfo { + using DbgUserVec = SmallVector; + SmallVector DefiningBlocks; SmallVector UsingBlocks; @@ -113,7 +110,7 @@ struct AllocaInfo { BasicBlock *OnlyBlock; bool OnlyUsedInOneBlock; - TinyPtrVector DbgDeclares; + DbgUserVec DbgUsers; void clear() { DefiningBlocks.clear(); @@ -121,7 +118,7 @@ struct AllocaInfo { OnlyStore = nullptr; OnlyBlock = nullptr; OnlyUsedInOneBlock = true; - DbgDeclares.clear(); + DbgUsers.clear(); } /// Scan the uses of the specified alloca, filling in the AllocaInfo used @@ -132,8 +129,8 @@ struct AllocaInfo { // As we scan the uses of the alloca instruction, keep track of stores, // and decide whether all of the loads and stores to the alloca are within // the same basic block. - for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) { - Instruction *User = cast(*UI++); + for (User *U : AI->users()) { + Instruction *User = cast(U); if (StoreInst *SI = dyn_cast(User)) { // Remember the basic blocks which define new values for the alloca @@ -154,7 +151,7 @@ struct AllocaInfo { } } - DbgDeclares = FindDbgAddrUses(AI); + findDbgUsers(DbgUsers, AI); } }; @@ -252,7 +249,7 @@ struct PromoteMem2Reg { /// For each alloca, we keep track of the dbg.declare intrinsic that /// describes it, if any, so that we can convert it to a dbg.value /// intrinsic if the alloca gets promoted. - SmallVector, 8> AllocaDbgDeclares; + SmallVector AllocaDbgUsers; /// The set of basic blocks the renamer has already visited. SmallPtrSet Visited; @@ -312,23 +309,37 @@ static void addAssumeNonNull(AssumptionCache *AC, LoadInst *LI) { AC->registerAssumption(CI); } -static void removeLifetimeIntrinsicUsers(AllocaInst *AI) { +static void removeIntrinsicUsers(AllocaInst *AI) { // Knowing that this alloca is promotable, we know that it's safe to kill all // instructions except for load and store. - for (auto UI = AI->user_begin(), UE = AI->user_end(); UI != UE;) { - Instruction *I = cast(*UI); + for (auto UI = AI->use_begin(), UE = AI->use_end(); UI != UE;) { + Instruction *I = cast(UI->getUser()); + Use &U = *UI; ++UI; if (isa(I) || isa(I)) continue; + // Drop the use of AI in droppable instructions. + if (I->isDroppable()) { + I->dropDroppableUse(U); + continue; + } + if (!I->getType()->isVoidTy()) { // The only users of this bitcast/GEP instruction are lifetime intrinsics. // Follow the use/def chain to erase them now instead of leaving it for // dead code elimination later. - for (auto UUI = I->user_begin(), UUE = I->user_end(); UUI != UUE;) { - Instruction *Inst = cast(*UUI); + for (auto UUI = I->use_begin(), UUE = I->use_end(); UUI != UUE;) { + Instruction *Inst = cast(UUI->getUser()); + Use &UU = *UUI; ++UUI; + + // Drop the use of I in droppable instructions. + if (Inst->isDroppable()) { + Inst->dropDroppableUse(UU); + continue; + } Inst->eraseFromParent(); } } @@ -355,8 +366,8 @@ static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info, // Clear out UsingBlocks. We will reconstruct it here if needed. Info.UsingBlocks.clear(); - for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) { - Instruction *UserInst = cast(*UI++); + for (User *U : make_early_inc_range(AI->users())) { + Instruction *UserInst = cast(U); if (UserInst == OnlyStore) continue; LoadInst *LI = cast(UserInst); @@ -412,10 +423,14 @@ static bool rewriteSingleStoreAlloca(AllocaInst *AI, AllocaInfo &Info, // Record debuginfo for the store and remove the declaration's // debuginfo. - for (DbgVariableIntrinsic *DII : Info.DbgDeclares) { - DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); - ConvertDebugDeclareToDebugValue(DII, Info.OnlyStore, DIB); - DII->eraseFromParent(); + for (DbgVariableIntrinsic *DII : Info.DbgUsers) { + if (DII->isAddressOfVariable()) { + DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); + ConvertDebugDeclareToDebugValue(DII, Info.OnlyStore, DIB); + DII->eraseFromParent(); + } else if (DII->getExpression()->startsWithDeref()) { + DII->eraseFromParent(); + } } // Remove the (now dead) store and alloca. Info.OnlyStore->eraseFromParent(); @@ -465,8 +480,8 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, // Walk all of the loads from this alloca, replacing them with the nearest // store above them, if any. - for (auto UI = AI->user_begin(), E = AI->user_end(); UI != E;) { - LoadInst *LI = dyn_cast(*UI++); + for (User *U : make_early_inc_range(AI->users())) { + LoadInst *LI = dyn_cast(U); if (!LI) continue; @@ -510,9 +525,11 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, while (!AI->use_empty()) { StoreInst *SI = cast(AI->user_back()); // Record debuginfo for the store before removing it. - for (DbgVariableIntrinsic *DII : Info.DbgDeclares) { - DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); - ConvertDebugDeclareToDebugValue(DII, SI, DIB); + for (DbgVariableIntrinsic *DII : Info.DbgUsers) { + if (DII->isAddressOfVariable()) { + DIBuilder DIB(*AI->getModule(), /*AllowUnresolved*/ false); + ConvertDebugDeclareToDebugValue(DII, SI, DIB); + } } SI->eraseFromParent(); LBI.deleteValue(SI); @@ -521,8 +538,9 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, AI->eraseFromParent(); // The alloca's debuginfo can be removed as well. - for (DbgVariableIntrinsic *DII : Info.DbgDeclares) - DII->eraseFromParent(); + for (DbgVariableIntrinsic *DII : Info.DbgUsers) + if (DII->isAddressOfVariable() || DII->getExpression()->startsWithDeref()) + DII->eraseFromParent(); ++NumLocalPromoted; return true; @@ -531,7 +549,7 @@ static bool promoteSingleBlockAlloca(AllocaInst *AI, const AllocaInfo &Info, void PromoteMem2Reg::run() { Function &F = *DT.getRoot()->getParent(); - AllocaDbgDeclares.resize(Allocas.size()); + AllocaDbgUsers.resize(Allocas.size()); AllocaInfo Info; LargeBlockInfo LBI; @@ -544,7 +562,7 @@ void PromoteMem2Reg::run() { assert(AI->getParent()->getParent() == &F && "All allocas should be in the same function, which is same as DF!"); - removeLifetimeIntrinsicUsers(AI); + removeIntrinsicUsers(AI); if (AI->use_empty()) { // If there are no uses of the alloca, just delete it now. @@ -589,8 +607,8 @@ void PromoteMem2Reg::run() { } // Remember the dbg.declare intrinsic describing this alloca, if any. - if (!Info.DbgDeclares.empty()) - AllocaDbgDeclares[AllocaNum] = Info.DbgDeclares; + if (!Info.DbgUsers.empty()) + AllocaDbgUsers[AllocaNum] = Info.DbgUsers; // Keep the reverse mapping of the 'Allocas' array for the rename pass. AllocaLookup[Allocas[AllocaNum]] = AllocaNum; @@ -663,9 +681,11 @@ void PromoteMem2Reg::run() { } // Remove alloca's dbg.declare instrinsics from the function. - for (auto &Declares : AllocaDbgDeclares) - for (auto *DII : Declares) - DII->eraseFromParent(); + for (auto &DbgUsers : AllocaDbgUsers) { + for (auto *DII : DbgUsers) + if (DII->isAddressOfVariable() || DII->getExpression()->startsWithDeref()) + DII->eraseFromParent(); + } // Loop over all of the PHI nodes and see if there are any that we can get // rid of because they merge all of the same incoming values. This can @@ -720,7 +740,7 @@ void PromoteMem2Reg::run() { continue; // Get the preds for BB. - SmallVector Preds(pred_begin(BB), pred_end(BB)); + SmallVector Preds(predecessors(BB)); // Ok, now we know that all of the PHI nodes are missing entries for some // basic blocks. Start by sorting the incoming predecessors for efficient @@ -887,7 +907,7 @@ NextIteration: // operands so far. Remember this count. unsigned NewPHINumOperands = APN->getNumOperands(); - unsigned NumEdges = std::count(succ_begin(Pred), succ_end(Pred), BB); + unsigned NumEdges = llvm::count(successors(Pred), BB); assert(NumEdges && "Must be at least one edge from Pred to BB!"); // Add entries for all the phis. @@ -905,8 +925,9 @@ NextIteration: // The currently active variable for this block is now the PHI. IncomingVals[AllocaNo] = APN; - for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[AllocaNo]) - ConvertDebugDeclareToDebugValue(DII, APN, DIB); + for (DbgVariableIntrinsic *DII : AllocaDbgUsers[AllocaNo]) + if (DII->isAddressOfVariable()) + ConvertDebugDeclareToDebugValue(DII, APN, DIB); // Get the next phi node. ++PNI; @@ -965,8 +986,9 @@ NextIteration: // Record debuginfo for the store before removing it. IncomingLocs[AllocaNo] = SI->getDebugLoc(); - for (DbgVariableIntrinsic *DII : AllocaDbgDeclares[ai->second]) - ConvertDebugDeclareToDebugValue(DII, SI, DIB); + for (DbgVariableIntrinsic *DII : AllocaDbgUsers[ai->second]) + if (DII->isAddressOfVariable()) + ConvertDebugDeclareToDebugValue(DII, SI, DIB); BB->getInstList().erase(SI); } } diff --git a/llvm/lib/Transforms/Utils/SSAUpdater.cpp b/llvm/lib/Transforms/Utils/SSAUpdater.cpp index 57df2334c750..c210d1c46077 100644 --- a/llvm/lib/Transforms/Utils/SSAUpdater.cpp +++ b/llvm/lib/Transforms/Utils/SSAUpdater.cpp @@ -64,8 +64,7 @@ bool SSAUpdater::HasValueForBlock(BasicBlock *BB) const { } Value *SSAUpdater::FindValueForBlock(BasicBlock *BB) const { - AvailableValsTy::iterator AVI = getAvailableVals(AV).find(BB); - return (AVI != getAvailableVals(AV).end()) ? AVI->second : nullptr; + return getAvailableVals(AV).lookup(BB); } void SSAUpdater::AddAvailableValue(BasicBlock *BB, Value *V) { @@ -254,12 +253,10 @@ public: // We can get our predecessor info by walking the pred_iterator list, // but it is relatively slow. If we already have PHI nodes in this // block, walk one of them to get the predecessor list instead. - if (PHINode *SomePhi = dyn_cast(BB->begin())) { - Preds->append(SomePhi->block_begin(), SomePhi->block_end()); - } else { - for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) - Preds->push_back(*PI); - } + if (PHINode *SomePhi = dyn_cast(BB->begin())) + append_range(*Preds, SomePhi->blocks()); + else + append_range(*Preds, predecessors(BB)); } /// GetUndefVal - Get an undefined value of the same type as the value @@ -283,12 +280,6 @@ public: PHI->addIncoming(Val, Pred); } - /// InstrIsPHI - Check if an instruction is a PHI. - /// - static PHINode *InstrIsPHI(Instruction *I) { - return dyn_cast(I); - } - /// ValueIsPHI - Check if a value is a PHI. static PHINode *ValueIsPHI(Value *Val, SSAUpdater *Updater) { return dyn_cast(Val); diff --git a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp index 71b48482f26a..6dbfb0b61fea 100644 --- a/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Transforms/Utils/ScalarEvolutionExpander.cpp @@ -27,6 +27,7 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/LoopUtils.h" using namespace llvm; @@ -38,8 +39,7 @@ cl::opt llvm::SCEVCheapExpansionBudget( using namespace PatternMatch; /// ReuseOrCreateCast - Arrange for there to be a cast of V to Ty at IP, -/// reusing an existing cast if a suitable one exists, moving an existing -/// cast if a suitable one exists but isn't in the right place, or +/// reusing an existing cast if a suitable one (= dominating IP) exists, or /// creating a new one. Value *SCEVExpander::ReuseOrCreateCast(Value *V, Type *Ty, Instruction::CastOps Op, @@ -58,40 +58,38 @@ Value *SCEVExpander::ReuseOrCreateCast(Value *V, Type *Ty, Instruction *Ret = nullptr; // Check to see if there is already a cast! - for (User *U : V->users()) - if (U->getType() == Ty) - if (CastInst *CI = dyn_cast(U)) - if (CI->getOpcode() == Op) { - // If the cast isn't where we want it, create a new cast at IP. - // Likewise, do not reuse a cast at BIP because it must dominate - // instructions that might be inserted before BIP. - if (BasicBlock::iterator(CI) != IP || BIP == IP) { - // Create a new cast, and leave the old cast in place in case - // it is being used as an insert point. - Ret = CastInst::Create(Op, V, Ty, "", &*IP); - Ret->takeName(CI); - CI->replaceAllUsesWith(Ret); - break; - } - Ret = CI; - break; - } + for (User *U : V->users()) { + if (U->getType() != Ty) + continue; + CastInst *CI = dyn_cast(U); + if (!CI || CI->getOpcode() != Op) + continue; + + // Found a suitable cast that is at IP or comes before IP. Use it. Note that + // the cast must also properly dominate the Builder's insertion point. + if (IP->getParent() == CI->getParent() && &*BIP != CI && + (&*IP == CI || CI->comesBefore(&*IP))) { + Ret = CI; + break; + } + } // Create a new cast. - if (!Ret) + if (!Ret) { Ret = CastInst::Create(Op, V, Ty, V->getName(), &*IP); + rememberInstruction(Ret); + } // We assert at the end of the function since IP might point to an // instruction with different dominance properties than a cast // (an invoke for example) and not dominate BIP (but the cast does). assert(SE.DT.dominates(Ret, &*BIP)); - rememberInstruction(Ret); return Ret; } -static BasicBlock::iterator findInsertPointAfter(Instruction *I, - BasicBlock *MustDominate) { +BasicBlock::iterator +SCEVExpander::findInsertPointAfter(Instruction *I, Instruction *MustDominate) { BasicBlock::iterator IP = ++I->getIterator(); if (auto *II = dyn_cast(I)) IP = II->getNormalDest()->begin(); @@ -102,11 +100,17 @@ static BasicBlock::iterator findInsertPointAfter(Instruction *I, if (isa(IP) || isa(IP)) { ++IP; } else if (isa(IP)) { - IP = MustDominate->getFirstInsertionPt(); + IP = MustDominate->getParent()->getFirstInsertionPt(); } else { assert(!IP->isEHPad() && "unexpected eh pad!"); } + // Adjust insert point to be after instructions inserted by the expander, so + // we can re-use already inserted instructions. Avoid skipping past the + // original \p MustDominate, in case it is an inserted instruction. + while (isInsertedInstruction(&*IP) && &*IP != MustDominate) + ++IP; + return IP; } @@ -122,6 +126,22 @@ Value *SCEVExpander::InsertNoopCastOfTo(Value *V, Type *Ty) { assert(SE.getTypeSizeInBits(V->getType()) == SE.getTypeSizeInBits(Ty) && "InsertNoopCastOfTo cannot change sizes!"); + // inttoptr only works for integral pointers. For non-integral pointers, we + // can create a GEP on i8* null with the integral value as index. Note that + // it is safe to use GEP of null instead of inttoptr here, because only + // expressions already based on a GEP of null should be converted to pointers + // during expansion. + if (Op == Instruction::IntToPtr) { + auto *PtrTy = cast(Ty); + if (DL.isNonIntegralPointerType(PtrTy)) { + auto *Int8PtrTy = Builder.getInt8PtrTy(PtrTy->getAddressSpace()); + assert(DL.getTypeAllocSize(Int8PtrTy->getElementType()) == 1 && + "alloc size of i8 must by 1 byte for the GEP to be correct"); + auto *GEP = Builder.CreateGEP( + Builder.getInt8Ty(), Constant::getNullValue(Int8PtrTy), V, "uglygep"); + return Builder.CreateBitCast(GEP, Ty); + } + } // Short-circuit unnecessary bitcasts. if (Op == Instruction::BitCast) { if (V->getType() == Ty) @@ -166,7 +186,7 @@ Value *SCEVExpander::InsertNoopCastOfTo(Value *V, Type *Ty) { // Cast the instruction immediately after the instruction. Instruction *I = cast(V); - BasicBlock::iterator IP = findInsertPointAfter(I, Builder.GetInsertBlock()); + BasicBlock::iterator IP = findInsertPointAfter(I, &*Builder.GetInsertPoint()); return ReuseOrCreateCast(I, Ty, Op, IP); } @@ -238,7 +258,6 @@ Value *SCEVExpander::InsertBinop(Instruction::BinaryOps Opcode, BO->setHasNoUnsignedWrap(); if (Flags & SCEV::FlagNSW) BO->setHasNoSignedWrap(); - rememberInstruction(BO); return BO; } @@ -290,7 +309,7 @@ static bool FactorOutConstant(const SCEV *&S, const SCEV *&Remainder, if (const SCEVConstant *FC = dyn_cast(Factor)) if (const SCEVConstant *C = dyn_cast(M->getOperand(0))) if (!C->getAPInt().srem(FC->getAPInt())) { - SmallVector NewMulOps(M->op_begin(), M->op_end()); + SmallVector NewMulOps(M->operands()); NewMulOps[0] = SE.getConstant(C->getAPInt().sdiv(FC->getAPInt())); S = SE.getMulExpr(NewMulOps); return true; @@ -462,9 +481,10 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, // we didn't find any operands that could be factored, tentatively // assume that element zero was selected (since the zero offset // would obviously be folded away). - Value *Scaled = ScaledOps.empty() ? - Constant::getNullValue(Ty) : - expandCodeFor(SE.getAddExpr(ScaledOps), Ty); + Value *Scaled = + ScaledOps.empty() + ? Constant::getNullValue(Ty) + : expandCodeForImpl(SE.getAddExpr(ScaledOps), Ty, false); GepIndices.push_back(Scaled); // Collect struct field index operands. @@ -523,7 +543,7 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, SE.DT.dominates(cast(V), &*Builder.GetInsertPoint())); // Expand the operands for a plain byte offset. - Value *Idx = expandCodeFor(SE.getAddExpr(Ops), Ty); + Value *Idx = expandCodeForImpl(SE.getAddExpr(Ops), Ty, false); // Fold a GEP with constant operands. if (Constant *CLHS = dyn_cast(V)) @@ -564,10 +584,7 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, } // Emit a GEP. - Value *GEP = Builder.CreateGEP(Builder.getInt8Ty(), V, Idx, "uglygep"); - rememberInstruction(GEP); - - return GEP; + return Builder.CreateGEP(Builder.getInt8Ty(), V, Idx, "uglygep"); } { @@ -598,7 +615,6 @@ Value *SCEVExpander::expandAddToGEP(const SCEV *const *op_begin, Casted = InsertNoopCastOfTo(Casted, PTy); Value *GEP = Builder.CreateGEP(OriginalElTy, Casted, GepIndices, "scevgep"); Ops.push_back(SE.getUnknown(GEP)); - rememberInstruction(GEP); } return expand(SE.getAddExpr(Ops)); @@ -748,14 +764,14 @@ Value *SCEVExpander::visitAddExpr(const SCEVAddExpr *S) { Sum = expandAddToGEP(NewOps.begin(), NewOps.end(), PTy, Ty, expand(Op)); } else if (Op->isNonConstantNegative()) { // Instead of doing a negate and add, just do a subtract. - Value *W = expandCodeFor(SE.getNegativeSCEV(Op), Ty); + Value *W = expandCodeForImpl(SE.getNegativeSCEV(Op), Ty, false); Sum = InsertNoopCastOfTo(Sum, Ty); Sum = InsertBinop(Instruction::Sub, Sum, W, SCEV::FlagAnyWrap, /*IsSafeToHoist*/ true); ++I; } else { // A simple add. - Value *W = expandCodeFor(Op, Ty); + Value *W = expandCodeForImpl(Op, Ty, false); Sum = InsertNoopCastOfTo(Sum, Ty); // Canonicalize a constant to the RHS. if (isa(Sum)) std::swap(Sum, W); @@ -807,7 +823,7 @@ Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) { // Calculate powers with exponents 1, 2, 4, 8 etc. and include those of them // that are needed into the result. - Value *P = expandCodeFor(I->second, Ty); + Value *P = expandCodeForImpl(I->second, Ty, false); Value *Result = nullptr; if (Exponent & 1) Result = P; @@ -866,7 +882,7 @@ Value *SCEVExpander::visitMulExpr(const SCEVMulExpr *S) { Value *SCEVExpander::visitUDivExpr(const SCEVUDivExpr *S) { Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *LHS = expandCodeFor(S->getLHS(), Ty); + Value *LHS = expandCodeForImpl(S->getLHS(), Ty, false); if (const SCEVConstant *SC = dyn_cast(S->getRHS())) { const APInt &RHS = SC->getAPInt(); if (RHS.isPowerOf2()) @@ -875,7 +891,7 @@ Value *SCEVExpander::visitUDivExpr(const SCEVUDivExpr *S) { SCEV::FlagAnyWrap, /*IsSafeToHoist*/ true); } - Value *RHS = expandCodeFor(S->getRHS(), Ty); + Value *RHS = expandCodeForImpl(S->getRHS(), Ty, false); return InsertBinop(Instruction::UDiv, LHS, RHS, SCEV::FlagAnyWrap, /*IsSafeToHoist*/ SE.isKnownNonZero(S->getRHS())); } @@ -895,7 +911,7 @@ static void ExposePointerBase(const SCEV *&Base, const SCEV *&Rest, } if (const SCEVAddExpr *A = dyn_cast(Base)) { Base = A->getOperand(A->getNumOperands()-1); - SmallVector NewAddOps(A->op_begin(), A->op_end()); + SmallVector NewAddOps(A->operands()); NewAddOps.back() = Rest; Rest = SE.getAddExpr(NewAddOps); ExposePointerBase(Base, Rest, SE); @@ -1073,15 +1089,12 @@ Value *SCEVExpander::expandIVInc(PHINode *PN, Value *StepV, const Loop *L, GEPPtrTy = PointerType::get(Type::getInt1Ty(SE.getContext()), GEPPtrTy->getAddressSpace()); IncV = expandAddToGEP(SE.getSCEV(StepV), GEPPtrTy, IntTy, PN); - if (IncV->getType() != PN->getType()) { + if (IncV->getType() != PN->getType()) IncV = Builder.CreateBitCast(IncV, PN->getType()); - rememberInstruction(IncV); - } } else { IncV = useSubtract ? Builder.CreateSub(PN, StepV, Twine(IVName) + ".iv.next") : Builder.CreateAdd(PN, StepV, Twine(IVName) + ".iv.next"); - rememberInstruction(IncV); } return IncV; } @@ -1193,6 +1206,14 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized, if (!SE.isSCEVable(PN.getType())) continue; + // We should not look for a incomplete PHI. Getting SCEV for a incomplete + // PHI has no meaning at all. + if (!PN.isComplete()) { + DEBUG_WITH_TYPE( + DebugType, dbgs() << "One incomplete PHI is found: " << PN << "\n"); + continue; + } + const SCEVAddRecExpr *PhiSCEV = dyn_cast(SE.getSCEV(&PN)); if (!PhiSCEV) continue; @@ -1253,6 +1274,9 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized, InsertedValues.insert(AddRecPhiMatch); // Remember the increment. rememberInstruction(IncV); + // Those values were not actually inserted but re-used. + ReusedValues.insert(AddRecPhiMatch); + ReusedValues.insert(IncV); return AddRecPhiMatch; } } @@ -1273,8 +1297,9 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized, // Expand code for the start value into the loop preheader. assert(L->getLoopPreheader() && "Can't expand add recurrences without a loop preheader!"); - Value *StartV = expandCodeFor(Normalized->getStart(), ExpandTy, - L->getLoopPreheader()->getTerminator()); + Value *StartV = + expandCodeForImpl(Normalized->getStart(), ExpandTy, + L->getLoopPreheader()->getTerminator(), false); // StartV must have been be inserted into L's preheader to dominate the new // phi. @@ -1292,7 +1317,8 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized, if (useSubtract) Step = SE.getNegativeSCEV(Step); // Expand the step somewhere that dominates the loop header. - Value *StepV = expandCodeFor(Step, IntTy, &L->getHeader()->front()); + Value *StepV = expandCodeForImpl( + Step, IntTy, &*L->getHeader()->getFirstInsertionPt(), false); // The no-wrap behavior proved by IsIncrement(NUW|NSW) is only applicable if // we actually do emit an addition. It does not apply if we emit a @@ -1306,7 +1332,6 @@ SCEVExpander::getAddRecExprPHILiterally(const SCEVAddRecExpr *Normalized, pred_iterator HPB = pred_begin(Header), HPE = pred_end(Header); PHINode *PN = Builder.CreatePHI(ExpandTy, std::distance(HPB, HPE), Twine(IVName) + ".iv"); - rememberInstruction(PN); // Create the step instructions and populate the PHI. for (pred_iterator HPI = HPB; HPI != HPE; ++HPI) { @@ -1415,6 +1440,17 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { assert(LatchBlock && "PostInc mode requires a unique loop latch!"); Result = PN->getIncomingValueForBlock(LatchBlock); + // We might be introducing a new use of the post-inc IV that is not poison + // safe, in which case we should drop poison generating flags. Only keep + // those flags for which SCEV has proven that they always hold. + if (isa(Result)) { + auto *I = cast(Result); + if (!S->hasNoUnsignedWrap()) + I->setHasNoUnsignedWrap(false); + if (!S->hasNoSignedWrap()) + I->setHasNoSignedWrap(false); + } + // For an expansion to use the postinc form, the client must call // expandCodeFor with an InsertPoint that is either outside the PostIncLoop // or dominated by IVIncInsertPos. @@ -1438,7 +1474,8 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { { // Expand the step somewhere that dominates the loop header. SCEVInsertPointGuard Guard(Builder, this); - StepV = expandCodeFor(Step, IntTy, &L->getHeader()->front()); + StepV = expandCodeForImpl( + Step, IntTy, &*L->getHeader()->getFirstInsertionPt(), false); } Result = expandIVInc(PN, StepV, L, ExpandTy, IntTy, useSubtract); } @@ -1452,16 +1489,13 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { if (ResTy != SE.getEffectiveSCEVType(ResTy)) Result = InsertNoopCastOfTo(Result, SE.getEffectiveSCEVType(ResTy)); // Truncate the result. - if (TruncTy != Result->getType()) { + if (TruncTy != Result->getType()) Result = Builder.CreateTrunc(Result, TruncTy); - rememberInstruction(Result); - } + // Invert the result. - if (InvertStep) { - Result = Builder.CreateSub(expandCodeFor(Normalized->getStart(), TruncTy), - Result); - rememberInstruction(Result); - } + if (InvertStep) + Result = Builder.CreateSub( + expandCodeForImpl(Normalized->getStart(), TruncTy, false), Result); } // Re-apply any non-loop-dominating scale. @@ -1469,24 +1503,22 @@ Value *SCEVExpander::expandAddRecExprLiterally(const SCEVAddRecExpr *S) { assert(S->isAffine() && "Can't linearly scale non-affine recurrences."); Result = InsertNoopCastOfTo(Result, IntTy); Result = Builder.CreateMul(Result, - expandCodeFor(PostLoopScale, IntTy)); - rememberInstruction(Result); + expandCodeForImpl(PostLoopScale, IntTy, false)); } // Re-apply any non-loop-dominating offset. if (PostLoopOffset) { if (PointerType *PTy = dyn_cast(ExpandTy)) { if (Result->getType()->isIntegerTy()) { - Value *Base = expandCodeFor(PostLoopOffset, ExpandTy); + Value *Base = expandCodeForImpl(PostLoopOffset, ExpandTy, false); Result = expandAddToGEP(SE.getUnknown(Result), PTy, IntTy, Base); } else { Result = expandAddToGEP(PostLoopOffset, PTy, IntTy, Result); } } else { Result = InsertNoopCastOfTo(Result, IntTy); - Result = Builder.CreateAdd(Result, - expandCodeFor(PostLoopOffset, IntTy)); - rememberInstruction(Result); + Result = Builder.CreateAdd( + Result, expandCodeForImpl(PostLoopOffset, IntTy, false)); } } @@ -1527,15 +1559,15 @@ Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) { Value *V = expand(SE.getAddRecExpr(NewOps, S->getLoop(), S->getNoWrapFlags(SCEV::FlagNW))); BasicBlock::iterator NewInsertPt = - findInsertPointAfter(cast(V), Builder.GetInsertBlock()); - V = expandCodeFor(SE.getTruncateExpr(SE.getUnknown(V), Ty), nullptr, - &*NewInsertPt); + findInsertPointAfter(cast(V), &*Builder.GetInsertPoint()); + V = expandCodeForImpl(SE.getTruncateExpr(SE.getUnknown(V), Ty), nullptr, + &*NewInsertPt, false); return V; } // {X,+,F} --> X + {0,+,F} if (!S->getStart()->isZero()) { - SmallVector NewOps(S->op_begin(), S->op_end()); + SmallVector NewOps(S->operands()); NewOps[0] = SE.getConstant(Ty, 0); const SCEV *Rest = SE.getAddRecExpr(NewOps, L, S->getNoWrapFlags(SCEV::FlagNW)); @@ -1642,31 +1674,34 @@ Value *SCEVExpander::visitAddRecExpr(const SCEVAddRecExpr *S) { return expand(T); } +Value *SCEVExpander::visitPtrToIntExpr(const SCEVPtrToIntExpr *S) { + Value *V = + expandCodeForImpl(S->getOperand(), S->getOperand()->getType(), false); + return Builder.CreatePtrToInt(V, S->getType()); +} + Value *SCEVExpander::visitTruncateExpr(const SCEVTruncateExpr *S) { Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *V = expandCodeFor(S->getOperand(), - SE.getEffectiveSCEVType(S->getOperand()->getType())); - Value *I = Builder.CreateTrunc(V, Ty); - rememberInstruction(I); - return I; + Value *V = expandCodeForImpl( + S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()), + false); + return Builder.CreateTrunc(V, Ty); } Value *SCEVExpander::visitZeroExtendExpr(const SCEVZeroExtendExpr *S) { Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *V = expandCodeFor(S->getOperand(), - SE.getEffectiveSCEVType(S->getOperand()->getType())); - Value *I = Builder.CreateZExt(V, Ty); - rememberInstruction(I); - return I; + Value *V = expandCodeForImpl( + S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()), + false); + return Builder.CreateZExt(V, Ty); } Value *SCEVExpander::visitSignExtendExpr(const SCEVSignExtendExpr *S) { Type *Ty = SE.getEffectiveSCEVType(S->getType()); - Value *V = expandCodeFor(S->getOperand(), - SE.getEffectiveSCEVType(S->getOperand()->getType())); - Value *I = Builder.CreateSExt(V, Ty); - rememberInstruction(I); - return I; + Value *V = expandCodeForImpl( + S->getOperand(), SE.getEffectiveSCEVType(S->getOperand()->getType()), + false); + return Builder.CreateSExt(V, Ty); } Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { @@ -1680,11 +1715,9 @@ Value *SCEVExpander::visitSMaxExpr(const SCEVSMaxExpr *S) { Ty = SE.getEffectiveSCEVType(Ty); LHS = InsertNoopCastOfTo(LHS, Ty); } - Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *RHS = expandCodeForImpl(S->getOperand(i), Ty, false); Value *ICmp = Builder.CreateICmpSGT(LHS, RHS); - rememberInstruction(ICmp); Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "smax"); - rememberInstruction(Sel); LHS = Sel; } // In the case of mixed integer and pointer types, cast the @@ -1705,11 +1738,9 @@ Value *SCEVExpander::visitUMaxExpr(const SCEVUMaxExpr *S) { Ty = SE.getEffectiveSCEVType(Ty); LHS = InsertNoopCastOfTo(LHS, Ty); } - Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *RHS = expandCodeForImpl(S->getOperand(i), Ty, false); Value *ICmp = Builder.CreateICmpUGT(LHS, RHS); - rememberInstruction(ICmp); Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "umax"); - rememberInstruction(Sel); LHS = Sel; } // In the case of mixed integer and pointer types, cast the @@ -1730,11 +1761,9 @@ Value *SCEVExpander::visitSMinExpr(const SCEVSMinExpr *S) { Ty = SE.getEffectiveSCEVType(Ty); LHS = InsertNoopCastOfTo(LHS, Ty); } - Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *RHS = expandCodeForImpl(S->getOperand(i), Ty, false); Value *ICmp = Builder.CreateICmpSLT(LHS, RHS); - rememberInstruction(ICmp); Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "smin"); - rememberInstruction(Sel); LHS = Sel; } // In the case of mixed integer and pointer types, cast the @@ -1755,11 +1784,9 @@ Value *SCEVExpander::visitUMinExpr(const SCEVUMinExpr *S) { Ty = SE.getEffectiveSCEVType(Ty); LHS = InsertNoopCastOfTo(LHS, Ty); } - Value *RHS = expandCodeFor(S->getOperand(i), Ty); + Value *RHS = expandCodeForImpl(S->getOperand(i), Ty, false); Value *ICmp = Builder.CreateICmpULT(LHS, RHS); - rememberInstruction(ICmp); Value *Sel = Builder.CreateSelect(ICmp, LHS, RHS, "umin"); - rememberInstruction(Sel); LHS = Sel; } // In the case of mixed integer and pointer types, cast the @@ -1769,15 +1796,45 @@ Value *SCEVExpander::visitUMinExpr(const SCEVUMinExpr *S) { return LHS; } -Value *SCEVExpander::expandCodeFor(const SCEV *SH, Type *Ty, - Instruction *IP) { +Value *SCEVExpander::expandCodeForImpl(const SCEV *SH, Type *Ty, + Instruction *IP, bool Root) { setInsertPoint(IP); - return expandCodeFor(SH, Ty); + Value *V = expandCodeForImpl(SH, Ty, Root); + return V; } -Value *SCEVExpander::expandCodeFor(const SCEV *SH, Type *Ty) { +Value *SCEVExpander::expandCodeForImpl(const SCEV *SH, Type *Ty, bool Root) { // Expand the code for this SCEV. Value *V = expand(SH); + + if (PreserveLCSSA) { + if (auto *Inst = dyn_cast(V)) { + // Create a temporary instruction to at the current insertion point, so we + // can hand it off to the helper to create LCSSA PHIs if required for the + // new use. + // FIXME: Ideally formLCSSAForInstructions (used in fixupLCSSAFormFor) + // would accept a insertion point and return an LCSSA phi for that + // insertion point, so there is no need to insert & remove the temporary + // instruction. + Instruction *Tmp; + if (Inst->getType()->isIntegerTy()) + Tmp = + cast(Builder.CreateAdd(Inst, Inst, "tmp.lcssa.user")); + else { + assert(Inst->getType()->isPointerTy()); + Tmp = cast( + Builder.CreateGEP(Inst, Builder.getInt32(1), "tmp.lcssa.user")); + } + V = fixupLCSSAFormFor(Tmp, 0); + + // Clean up temporary instruction. + InsertedValues.erase(Tmp); + InsertedPostIncValues.erase(Tmp); + Tmp->eraseFromParent(); + } + } + + InsertedExpressions[std::make_pair(SH, &*Builder.GetInsertPoint())] = V; if (Ty) { assert(SE.getTypeSizeInBits(Ty) == SE.getTypeSizeInBits(SH->getType()) && "non-trivial casts should be done with the SCEVs directly!"); @@ -1861,20 +1918,17 @@ Value *SCEVExpander::expand(const SCEV *S) { // there) so that it is guaranteed to dominate any user inside the loop. if (L && SE.hasComputableLoopEvolution(S, L) && !PostIncLoops.count(L)) InsertPt = &*L->getHeader()->getFirstInsertionPt(); + while (InsertPt->getIterator() != Builder.GetInsertPoint() && (isInsertedInstruction(InsertPt) || - isa(InsertPt))) + isa(InsertPt))) { InsertPt = &*std::next(InsertPt->getIterator()); + } break; } } } - // IndVarSimplify sometimes sets the insertion point at the block start, even - // when there are PHIs at that point. We must correct for this. - if (isa(*InsertPt)) - InsertPt = &*InsertPt->getParent()->getFirstInsertionPt(); - // Check to see if we already expanded this here. auto I = InsertedExpressions.find(std::make_pair(S, InsertPt)); if (I != InsertedExpressions.end()) @@ -1922,32 +1976,25 @@ Value *SCEVExpander::expand(const SCEV *S) { } void SCEVExpander::rememberInstruction(Value *I) { - if (!PostIncLoops.empty()) - InsertedPostIncValues.insert(I); - else - InsertedValues.insert(I); -} - -/// getOrInsertCanonicalInductionVariable - This method returns the -/// canonical induction variable of the specified type for the specified -/// loop (inserting one if there is none). A canonical induction variable -/// starts at zero and steps by one on each iteration. -PHINode * -SCEVExpander::getOrInsertCanonicalInductionVariable(const Loop *L, - Type *Ty) { - assert(Ty->isIntegerTy() && "Can only insert integer induction variables!"); - - // Build a SCEV for {0,+,1}. - // Conservatively use FlagAnyWrap for now. - const SCEV *H = SE.getAddRecExpr(SE.getConstant(Ty, 0), - SE.getConstant(Ty, 1), L, SCEV::FlagAnyWrap); + auto DoInsert = [this](Value *V) { + if (!PostIncLoops.empty()) + InsertedPostIncValues.insert(V); + else + InsertedValues.insert(V); + }; + DoInsert(I); - // Emit code for it. - SCEVInsertPointGuard Guard(Builder, this); - PHINode *V = - cast(expandCodeFor(H, nullptr, &L->getHeader()->front())); + if (!PreserveLCSSA) + return; - return V; + if (auto *Inst = dyn_cast(I)) { + // A new instruction has been added, which might introduce new uses outside + // a defining loop. Fix LCSSA from for each operand of the new instruction, + // if required. + for (unsigned OpIdx = 0, OpEnd = Inst->getNumOperands(); OpIdx != OpEnd; + OpIdx++) + fixupLCSSAFormFor(Inst, OpIdx); + } } /// replaceCongruentIVs - Check for congruent phis in this loop header and @@ -1970,8 +2017,8 @@ SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT, // Put pointers at the back and make sure pointer < pointer = false. if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy()) return RHS->getType()->isIntegerTy() && !LHS->getType()->isIntegerTy(); - return RHS->getType()->getPrimitiveSizeInBits() < - LHS->getType()->getPrimitiveSizeInBits(); + return RHS->getType()->getPrimitiveSizeInBits().getFixedSize() < + LHS->getType()->getPrimitiveSizeInBits().getFixedSize(); }); unsigned NumElim = 0; @@ -2079,6 +2126,8 @@ SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT, } DEBUG_WITH_TYPE(DebugType, dbgs() << "INDVARS: Eliminated congruent iv: " << *Phi << '\n'); + DEBUG_WITH_TYPE(DebugType, dbgs() << "INDVARS: Original iv: " + << *OrigPhiRef << '\n'); ++NumElim; Value *NewIV = OrigPhiRef; if (OrigPhiRef->getType() != Phi->getType()) { @@ -2092,15 +2141,6 @@ SCEVExpander::replaceCongruentIVs(Loop *L, const DominatorTree *DT, return NumElim; } -Value *SCEVExpander::getExactExistingExpansion(const SCEV *S, - const Instruction *At, Loop *L) { - Optional VO = - getRelatedExistingExpansion(S, At, L); - if (VO && VO.getValue().second == nullptr) - return VO.getValue().first; - return nullptr; -} - Optional SCEVExpander::getRelatedExistingExpansion(const SCEV *S, const Instruction *At, Loop *L) { @@ -2139,15 +2179,156 @@ SCEVExpander::getRelatedExistingExpansion(const SCEV *S, const Instruction *At, return None; } +template static int costAndCollectOperands( + const SCEVOperand &WorkItem, const TargetTransformInfo &TTI, + TargetTransformInfo::TargetCostKind CostKind, + SmallVectorImpl &Worklist) { + + const T *S = cast(WorkItem.S); + int Cost = 0; + // Object to help map SCEV operands to expanded IR instructions. + struct OperationIndices { + OperationIndices(unsigned Opc, size_t min, size_t max) : + Opcode(Opc), MinIdx(min), MaxIdx(max) { } + unsigned Opcode; + size_t MinIdx; + size_t MaxIdx; + }; + + // Collect the operations of all the instructions that will be needed to + // expand the SCEVExpr. This is so that when we come to cost the operands, + // we know what the generated user(s) will be. + SmallVector Operations; + + auto CastCost = [&](unsigned Opcode) { + Operations.emplace_back(Opcode, 0, 0); + return TTI.getCastInstrCost(Opcode, S->getType(), + S->getOperand(0)->getType(), + TTI::CastContextHint::None, CostKind); + }; + + auto ArithCost = [&](unsigned Opcode, unsigned NumRequired, + unsigned MinIdx = 0, unsigned MaxIdx = 1) { + Operations.emplace_back(Opcode, MinIdx, MaxIdx); + return NumRequired * + TTI.getArithmeticInstrCost(Opcode, S->getType(), CostKind); + }; + + auto CmpSelCost = [&](unsigned Opcode, unsigned NumRequired, + unsigned MinIdx, unsigned MaxIdx) { + Operations.emplace_back(Opcode, MinIdx, MaxIdx); + Type *OpType = S->getOperand(0)->getType(); + return NumRequired * TTI.getCmpSelInstrCost( + Opcode, OpType, CmpInst::makeCmpResultType(OpType), + CmpInst::BAD_ICMP_PREDICATE, CostKind); + }; + + switch (S->getSCEVType()) { + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + case scUnknown: + case scConstant: + return 0; + case scPtrToInt: + Cost = CastCost(Instruction::PtrToInt); + break; + case scTruncate: + Cost = CastCost(Instruction::Trunc); + break; + case scZeroExtend: + Cost = CastCost(Instruction::ZExt); + break; + case scSignExtend: + Cost = CastCost(Instruction::SExt); + break; + case scUDivExpr: { + unsigned Opcode = Instruction::UDiv; + if (auto *SC = dyn_cast(S->getOperand(1))) + if (SC->getAPInt().isPowerOf2()) + Opcode = Instruction::LShr; + Cost = ArithCost(Opcode, 1); + break; + } + case scAddExpr: + Cost = ArithCost(Instruction::Add, S->getNumOperands() - 1); + break; + case scMulExpr: + // TODO: this is a very pessimistic cost modelling for Mul, + // because of Bin Pow algorithm actually used by the expander, + // see SCEVExpander::visitMulExpr(), ExpandOpBinPowN(). + Cost = ArithCost(Instruction::Mul, S->getNumOperands() - 1); + break; + case scSMaxExpr: + case scUMaxExpr: + case scSMinExpr: + case scUMinExpr: { + Cost += CmpSelCost(Instruction::ICmp, S->getNumOperands() - 1, 0, 1); + Cost += CmpSelCost(Instruction::Select, S->getNumOperands() - 1, 0, 2); + break; + } + case scAddRecExpr: { + // In this polynominal, we may have some zero operands, and we shouldn't + // really charge for those. So how many non-zero coeffients are there? + int NumTerms = llvm::count_if(S->operands(), [](const SCEV *Op) { + return !Op->isZero(); + }); + + assert(NumTerms >= 1 && "Polynominal should have at least one term."); + assert(!(*std::prev(S->operands().end()))->isZero() && + "Last operand should not be zero"); + + // Ignoring constant term (operand 0), how many of the coeffients are u> 1? + int NumNonZeroDegreeNonOneTerms = + llvm::count_if(S->operands(), [](const SCEV *Op) { + auto *SConst = dyn_cast(Op); + return !SConst || SConst->getAPInt().ugt(1); + }); + + // Much like with normal add expr, the polynominal will require + // one less addition than the number of it's terms. + int AddCost = ArithCost(Instruction::Add, NumTerms - 1, + /*MinIdx*/1, /*MaxIdx*/1); + // Here, *each* one of those will require a multiplication. + int MulCost = ArithCost(Instruction::Mul, NumNonZeroDegreeNonOneTerms); + Cost = AddCost + MulCost; + + // What is the degree of this polynominal? + int PolyDegree = S->getNumOperands() - 1; + assert(PolyDegree >= 1 && "Should be at least affine."); + + // The final term will be: + // Op_{PolyDegree} * x ^ {PolyDegree} + // Where x ^ {PolyDegree} will again require PolyDegree-1 mul operations. + // Note that x ^ {PolyDegree} = x * x ^ {PolyDegree-1} so charging for + // x ^ {PolyDegree} will give us x ^ {2} .. x ^ {PolyDegree-1} for free. + // FIXME: this is conservatively correct, but might be overly pessimistic. + Cost += MulCost * (PolyDegree - 1); + break; + } + } + + for (auto &CostOp : Operations) { + for (auto SCEVOp : enumerate(S->operands())) { + // Clamp the index to account for multiple IR operations being chained. + size_t MinIdx = std::max(SCEVOp.index(), CostOp.MinIdx); + size_t OpIdx = std::min(MinIdx, CostOp.MaxIdx); + Worklist.emplace_back(CostOp.Opcode, OpIdx, SCEVOp.value()); + } + } + return Cost; +} + bool SCEVExpander::isHighCostExpansionHelper( - const SCEV *S, Loop *L, const Instruction &At, int &BudgetRemaining, - const TargetTransformInfo &TTI, SmallPtrSetImpl &Processed, - SmallVectorImpl &Worklist) { + const SCEVOperand &WorkItem, Loop *L, const Instruction &At, + int &BudgetRemaining, const TargetTransformInfo &TTI, + SmallPtrSetImpl &Processed, + SmallVectorImpl &Worklist) { if (BudgetRemaining < 0) return true; // Already run out of budget, give up. + const SCEV *S = WorkItem.S; // Was the cost of expansion of this expression already accounted for? - if (!Processed.insert(S).second) + if (!isa(S) && !Processed.insert(S).second) return false; // We have already accounted for this expression. // If we can find an existing value for this scev available at the point "At" @@ -2155,52 +2336,37 @@ bool SCEVExpander::isHighCostExpansionHelper( if (getRelatedExistingExpansion(S, &At, L)) return false; // Consider the expression to be free. - switch (S->getSCEVType()) { - case scUnknown: - case scConstant: - return false; // Assume to be zero-cost. - } - TargetTransformInfo::TargetCostKind CostKind = - TargetTransformInfo::TCK_RecipThroughput; + L->getHeader()->getParent()->hasMinSize() + ? TargetTransformInfo::TCK_CodeSize + : TargetTransformInfo::TCK_RecipThroughput; - if (auto *CastExpr = dyn_cast(S)) { - unsigned Opcode; - switch (S->getSCEVType()) { - case scTruncate: - Opcode = Instruction::Trunc; - break; - case scZeroExtend: - Opcode = Instruction::ZExt; - break; - case scSignExtend: - Opcode = Instruction::SExt; - break; - default: - llvm_unreachable("There are no other cast types."); - } - const SCEV *Op = CastExpr->getOperand(); - BudgetRemaining -= TTI.getCastInstrCost(Opcode, /*Dst=*/S->getType(), - /*Src=*/Op->getType(), CostKind); - Worklist.emplace_back(Op); + switch (S->getSCEVType()) { + case scCouldNotCompute: + llvm_unreachable("Attempt to use a SCEVCouldNotCompute object!"); + case scUnknown: + // Assume to be zero-cost. + return false; + case scConstant: { + // Only evalulate the costs of constants when optimizing for size. + if (CostKind != TargetTransformInfo::TCK_CodeSize) + return 0; + const APInt &Imm = cast(S)->getAPInt(); + Type *Ty = S->getType(); + BudgetRemaining -= TTI.getIntImmCostInst( + WorkItem.ParentOpcode, WorkItem.OperandIdx, Imm, Ty, CostKind); + return BudgetRemaining < 0; + } + case scTruncate: + case scPtrToInt: + case scZeroExtend: + case scSignExtend: { + int Cost = + costAndCollectOperands(WorkItem, TTI, CostKind, Worklist); + BudgetRemaining -= Cost; return false; // Will answer upon next entry into this function. } - - if (auto *UDivExpr = dyn_cast(S)) { - // If the divisor is a power of two count this as a logical right-shift. - if (auto *SC = dyn_cast(UDivExpr->getRHS())) { - if (SC->getAPInt().isPowerOf2()) { - BudgetRemaining -= - TTI.getArithmeticInstrCost(Instruction::LShr, S->getType(), - CostKind); - // Note that we don't count the cost of RHS, because it is a constant, - // and we consider those to be free. But if that changes, we would need - // to log2() it first before calling isHighCostExpansionHelper(). - Worklist.emplace_back(UDivExpr->getLHS()); - return false; // Will answer upon next entry into this function. - } - } - + case scUDivExpr: { // UDivExpr is very likely a UDiv that ScalarEvolution's HowFarToZero or // HowManyLessThans produced to compute a precise expression, rather than a // UDiv from the user's code. If we can't find a UDiv in the code with some @@ -2213,117 +2379,36 @@ bool SCEVExpander::isHighCostExpansionHelper( SE.getAddExpr(S, SE.getConstant(S->getType(), 1)), &At, L)) return false; // Consider it to be free. + int Cost = + costAndCollectOperands(WorkItem, TTI, CostKind, Worklist); // Need to count the cost of this UDiv. - BudgetRemaining -= - TTI.getArithmeticInstrCost(Instruction::UDiv, S->getType(), - CostKind); - Worklist.insert(Worklist.end(), {UDivExpr->getLHS(), UDivExpr->getRHS()}); + BudgetRemaining -= Cost; return false; // Will answer upon next entry into this function. } - - if (const auto *NAry = dyn_cast(S)) { - Type *OpType = NAry->getType(); - - assert(NAry->getNumOperands() >= 2 && - "Polynomial should be at least linear"); - - int AddCost = - TTI.getArithmeticInstrCost(Instruction::Add, OpType, CostKind); - int MulCost = - TTI.getArithmeticInstrCost(Instruction::Mul, OpType, CostKind); - - // In this polynominal, we may have some zero operands, and we shouldn't - // really charge for those. So how many non-zero coeffients are there? - int NumTerms = llvm::count_if(NAry->operands(), - [](const SCEV *S) { return !S->isZero(); }); - assert(NumTerms >= 1 && "Polynominal should have at least one term."); - assert(!(*std::prev(NAry->operands().end()))->isZero() && - "Last operand should not be zero"); - - // Much like with normal add expr, the polynominal will require - // one less addition than the number of it's terms. - BudgetRemaining -= AddCost * (NumTerms - 1); - if (BudgetRemaining < 0) - return true; - - // Ignoring constant term (operand 0), how many of the coeffients are u> 1? - int NumNonZeroDegreeNonOneTerms = - llvm::count_if(make_range(std::next(NAry->op_begin()), NAry->op_end()), - [](const SCEV *S) { - auto *SConst = dyn_cast(S); - return !SConst || SConst->getAPInt().ugt(1); - }); - // Here, *each* one of those will require a multiplication. - BudgetRemaining -= MulCost * NumNonZeroDegreeNonOneTerms; - if (BudgetRemaining < 0) - return true; - - // What is the degree of this polynominal? - int PolyDegree = NAry->getNumOperands() - 1; - assert(PolyDegree >= 1 && "Should be at least affine."); - - // The final term will be: - // Op_{PolyDegree} * x ^ {PolyDegree} - // Where x ^ {PolyDegree} will again require PolyDegree-1 mul operations. - // Note that x ^ {PolyDegree} = x * x ^ {PolyDegree-1} so charging for - // x ^ {PolyDegree} will give us x ^ {2} .. x ^ {PolyDegree-1} for free. - // FIXME: this is conservatively correct, but might be overly pessimistic. - BudgetRemaining -= MulCost * (PolyDegree - 1); - if (BudgetRemaining < 0) - return true; - - // And finally, the operands themselves should fit within the budget. - Worklist.insert(Worklist.end(), NAry->operands().begin(), - NAry->operands().end()); - return false; // So far so good, though ops may be too costly? - } - - if (const SCEVNAryExpr *NAry = dyn_cast(S)) { - Type *OpType = NAry->getType(); - - int PairCost; - switch (S->getSCEVType()) { - case scAddExpr: - PairCost = - TTI.getArithmeticInstrCost(Instruction::Add, OpType, CostKind); - break; - case scMulExpr: - // TODO: this is a very pessimistic cost modelling for Mul, - // because of Bin Pow algorithm actually used by the expander, - // see SCEVExpander::visitMulExpr(), ExpandOpBinPowN(). - PairCost = - TTI.getArithmeticInstrCost(Instruction::Mul, OpType, CostKind); - break; - case scSMaxExpr: - case scUMaxExpr: - case scSMinExpr: - case scUMinExpr: - PairCost = TTI.getCmpSelInstrCost(Instruction::ICmp, OpType, - CmpInst::makeCmpResultType(OpType), - CostKind) + - TTI.getCmpSelInstrCost(Instruction::Select, OpType, - CmpInst::makeCmpResultType(OpType), - CostKind); - break; - default: - llvm_unreachable("There are no other variants here."); - } - - assert(NAry->getNumOperands() > 1 && + case scAddExpr: + case scMulExpr: + case scUMaxExpr: + case scSMaxExpr: + case scUMinExpr: + case scSMinExpr: { + assert(cast(S)->getNumOperands() > 1 && "Nary expr should have more than 1 operand."); // The simple nary expr will require one less op (or pair of ops) // than the number of it's terms. - BudgetRemaining -= PairCost * (NAry->getNumOperands() - 1); - if (BudgetRemaining < 0) - return true; - - // And finally, the operands themselves should fit within the budget. - Worklist.insert(Worklist.end(), NAry->operands().begin(), - NAry->operands().end()); - return false; // So far so good, though ops may be too costly? + int Cost = + costAndCollectOperands(WorkItem, TTI, CostKind, Worklist); + BudgetRemaining -= Cost; + return BudgetRemaining < 0; } - - llvm_unreachable("No other scev expressions possible."); + case scAddRecExpr: { + assert(cast(S)->getNumOperands() >= 2 && + "Polynomial should be at least linear"); + BudgetRemaining -= costAndCollectOperands( + WorkItem, TTI, CostKind, Worklist); + return BudgetRemaining < 0; + } + } + llvm_unreachable("Unknown SCEV kind!"); } Value *SCEVExpander::expandCodeForPredicate(const SCEVPredicate *Pred, @@ -2344,8 +2429,10 @@ Value *SCEVExpander::expandCodeForPredicate(const SCEVPredicate *Pred, Value *SCEVExpander::expandEqualPredicate(const SCEVEqualPredicate *Pred, Instruction *IP) { - Value *Expr0 = expandCodeFor(Pred->getLHS(), Pred->getLHS()->getType(), IP); - Value *Expr1 = expandCodeFor(Pred->getRHS(), Pred->getRHS()->getType(), IP); + Value *Expr0 = + expandCodeForImpl(Pred->getLHS(), Pred->getLHS()->getType(), IP, false); + Value *Expr1 = + expandCodeForImpl(Pred->getRHS(), Pred->getRHS()->getType(), IP, false); Builder.SetInsertPoint(IP); auto *I = Builder.CreateICmpNE(Expr0, Expr1, "ident.check"); @@ -2361,7 +2448,7 @@ Value *SCEVExpander::generateOverflowCheck(const SCEVAddRecExpr *AR, const SCEV *ExitCount = SE.getPredicatedBackedgeTakenCount(AR->getLoop(), Pred); - assert(ExitCount != SE.getCouldNotCompute() && "Invalid loop count"); + assert(!isa(ExitCount) && "Invalid loop count"); const SCEV *Step = AR->getStepRecurrence(SE); const SCEV *Start = AR->getStart(); @@ -2377,15 +2464,16 @@ Value *SCEVExpander::generateOverflowCheck(const SCEVAddRecExpr *AR, IntegerType *CountTy = IntegerType::get(Loc->getContext(), SrcBits); Builder.SetInsertPoint(Loc); - Value *TripCountVal = expandCodeFor(ExitCount, CountTy, Loc); + Value *TripCountVal = expandCodeForImpl(ExitCount, CountTy, Loc, false); IntegerType *Ty = IntegerType::get(Loc->getContext(), SE.getTypeSizeInBits(ARTy)); Type *ARExpandTy = DL.isNonIntegralPointerType(ARTy) ? ARTy : Ty; - Value *StepValue = expandCodeFor(Step, Ty, Loc); - Value *NegStepValue = expandCodeFor(SE.getNegativeSCEV(Step), Ty, Loc); - Value *StartValue = expandCodeFor(Start, ARExpandTy, Loc); + Value *StepValue = expandCodeForImpl(Step, Ty, Loc, false); + Value *NegStepValue = + expandCodeForImpl(SE.getNegativeSCEV(Step), Ty, Loc, false); + Value *StartValue = expandCodeForImpl(Start, ARExpandTy, Loc, false); ConstantInt *Zero = ConstantInt::get(Loc->getContext(), APInt::getNullValue(DstBits)); @@ -2445,8 +2533,7 @@ Value *SCEVExpander::generateOverflowCheck(const SCEVAddRecExpr *AR, EndCheck = Builder.CreateOr(EndCheck, BackedgeCheck); } - EndCheck = Builder.CreateOr(EndCheck, OfMul); - return EndCheck; + return Builder.CreateOr(EndCheck, OfMul); } Value *SCEVExpander::expandWrapPredicate(const SCEVWrapPredicate *Pred, @@ -2489,6 +2576,34 @@ Value *SCEVExpander::expandUnionPredicate(const SCEVUnionPredicate *Union, return Check; } +Value *SCEVExpander::fixupLCSSAFormFor(Instruction *User, unsigned OpIdx) { + assert(PreserveLCSSA); + SmallVector ToUpdate; + + auto *OpV = User->getOperand(OpIdx); + auto *OpI = dyn_cast(OpV); + if (!OpI) + return OpV; + + Loop *DefLoop = SE.LI.getLoopFor(OpI->getParent()); + Loop *UseLoop = SE.LI.getLoopFor(User->getParent()); + if (!DefLoop || UseLoop == DefLoop || DefLoop->contains(UseLoop)) + return OpV; + + ToUpdate.push_back(OpI); + SmallVector PHIsToRemove; + formLCSSAForInstructions(ToUpdate, SE.DT, SE.LI, &SE, Builder, &PHIsToRemove); + for (PHINode *PN : PHIsToRemove) { + if (!PN->use_empty()) + continue; + InsertedValues.erase(PN); + InsertedPostIncValues.erase(PN); + PN->eraseFromParent(); + } + + return User->getOperand(OpIdx); +} + namespace { // Search for a SCEV subexpression that is not safe to expand. Any expression // that may expand to a !isSafeToSpeculativelyExecute value is unsafe, namely @@ -2566,4 +2681,40 @@ bool isSafeToExpandAt(const SCEV *S, const Instruction *InsertionPoint, } return false; } + +SCEVExpanderCleaner::~SCEVExpanderCleaner() { + // Result is used, nothing to remove. + if (ResultUsed) + return; + + auto InsertedInstructions = Expander.getAllInsertedInstructions(); +#ifndef NDEBUG + SmallPtrSet InsertedSet(InsertedInstructions.begin(), + InsertedInstructions.end()); + (void)InsertedSet; +#endif + // Remove sets with value handles. + Expander.clear(); + + // Sort so that earlier instructions do not dominate later instructions. + stable_sort(InsertedInstructions, [this](Instruction *A, Instruction *B) { + return DT.dominates(B, A); + }); + // Remove all inserted instructions. + for (Instruction *I : InsertedInstructions) { + +#ifndef NDEBUG + assert(all_of(I->users(), + [&InsertedSet](Value *U) { + return InsertedSet.contains(cast(U)); + }) && + "removed instruction should only be used by instructions inserted " + "during expansion"); +#endif + assert(!I->getType()->isVoidTy() && + "inserted instruction should have non-void types"); + I->replaceAllUsesWith(UndefValue::get(I->getType())); + I->eraseFromParent(); + } +} } diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index b450d71c996c..7cfe17618cde 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -13,8 +13,11 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SetOperations.h" #include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -58,6 +61,7 @@ #include "llvm/IR/Use.h" #include "llvm/IR/User.h" #include "llvm/IR/Value.h" +#include "llvm/IR/ValueHandle.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -67,6 +71,7 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "llvm/Transforms/Utils/Local.h" +#include "llvm/Transforms/Utils/SSAUpdater.h" #include "llvm/Transforms/Utils/ValueMapper.h" #include #include @@ -85,6 +90,12 @@ using namespace PatternMatch; #define DEBUG_TYPE "simplifycfg" +cl::opt llvm::RequireAndPreserveDomTree( + "simplifycfg-require-and-preserve-domtree", cl::Hidden, cl::ZeroOrMore, + cl::init(false), + cl::desc("Temorary development switch used to gradually uplift SimplifyCFG " + "into preserving DomTree,")); + // Chosen as 2 so as to be cheap, but still to have enough power to fold // a select, so the "clamp" idiom (of a min followed by a max) will be caught. // To catch this, we need to fold a compare and a select, hence '2' being the @@ -104,6 +115,10 @@ static cl::opt DupRet( "simplifycfg-dup-ret", cl::Hidden, cl::init(false), cl::desc("Duplicate return instructions into unconditional branches")); +static cl::opt + HoistCommon("simplifycfg-hoist-common", cl::Hidden, cl::init(true), + cl::desc("Hoist common instructions up to the parent block")); + static cl::opt SinkCommon("simplifycfg-sink-common", cl::Hidden, cl::init(true), cl::desc("Sink common instructions down to the end block")); @@ -138,6 +153,13 @@ MaxSmallBlockSize("simplifycfg-max-small-block-size", cl::Hidden, cl::init(10), cl::desc("Max size of a block which is still considered " "small enough to thread through")); +// Two is chosen to allow one negation and a logical combine. +static cl::opt + BranchFoldThreshold("simplifycfg-branch-fold-threshold", cl::Hidden, + cl::init(2), + cl::desc("Maximum cost of combining conditions when " + "folding branches")); + STATISTIC(NumBitMaps, "Number of switch instructions turned into bitmaps"); STATISTIC(NumLinearMaps, "Number of switch instructions turned into linear mapping"); @@ -147,9 +169,22 @@ STATISTIC( NumLookupTablesHoles, "Number of switch instructions turned into lookup tables (holes checked)"); STATISTIC(NumTableCmpReuses, "Number of reused switch table lookup compares"); -STATISTIC(NumSinkCommons, +STATISTIC(NumFoldValueComparisonIntoPredecessors, + "Number of value comparisons folded into predecessor basic blocks"); +STATISTIC(NumFoldBranchToCommonDest, + "Number of branches folded into predecessor basic block"); +STATISTIC( + NumHoistCommonCode, + "Number of common instruction 'blocks' hoisted up to the begin block"); +STATISTIC(NumHoistCommonInstrs, + "Number of common instructions hoisted up to the begin block"); +STATISTIC(NumSinkCommonCode, + "Number of common instruction 'blocks' sunk down to the end block"); +STATISTIC(NumSinkCommonInstrs, "Number of common instructions sunk down to the end block"); STATISTIC(NumSpeculations, "Number of speculative executed instructions"); +STATISTIC(NumInvokes, + "Number of invokes with empty resume blocks simplified into calls"); namespace { @@ -182,8 +217,9 @@ struct ValueEqualityComparisonCase { class SimplifyCFGOpt { const TargetTransformInfo &TTI; + DomTreeUpdater *DTU; const DataLayout &DL; - SmallPtrSetImpl *LoopHeaders; + ArrayRef LoopHeaders; const SimplifyCFGOptions &Options; bool Resimplify; @@ -193,6 +229,9 @@ class SimplifyCFGOpt { bool SimplifyEqualityComparisonWithOnlyPredecessor(Instruction *TI, BasicBlock *Pred, IRBuilder<> &Builder); + bool PerformValueComparisonIntoPredecessorFolding(Instruction *TI, Value *&CV, + Instruction *PTI, + IRBuilder<> &Builder); bool FoldValueComparisonIntoPredecessors(Instruction *TI, IRBuilder<> &Builder); @@ -225,13 +264,18 @@ class SimplifyCFGOpt { bool TurnSwitchRangeIntoICmp(SwitchInst *SI, IRBuilder<> &Builder); public: - SimplifyCFGOpt(const TargetTransformInfo &TTI, const DataLayout &DL, - SmallPtrSetImpl *LoopHeaders, + SimplifyCFGOpt(const TargetTransformInfo &TTI, DomTreeUpdater *DTU, + const DataLayout &DL, ArrayRef LoopHeaders, const SimplifyCFGOptions &Opts) - : TTI(TTI), DL(DL), LoopHeaders(LoopHeaders), Options(Opts) {} + : TTI(TTI), DTU(DTU), DL(DL), LoopHeaders(LoopHeaders), Options(Opts) { + assert((!DTU || !DTU->hasPostDomTree()) && + "SimplifyCFG is not yet capable of maintaining validity of a " + "PostDomTree, so don't ask for it."); + } - bool run(BasicBlock *BB); bool simplifyOnce(BasicBlock *BB); + bool simplifyOnceImpl(BasicBlock *BB); + bool run(BasicBlock *BB); // Helper to set Resimplify and return change indication. bool requestResimplify() { @@ -273,46 +317,6 @@ SafeToMergeTerminators(Instruction *SI1, Instruction *SI2, return !Fail; } -/// Return true if it is safe and profitable to merge these two terminator -/// instructions together, where SI1 is an unconditional branch. PhiNodes will -/// store all PHI nodes in common successors. -static bool -isProfitableToFoldUnconditional(BranchInst *SI1, BranchInst *SI2, - Instruction *Cond, - SmallVectorImpl &PhiNodes) { - if (SI1 == SI2) - return false; // Can't merge with self! - assert(SI1->isUnconditional() && SI2->isConditional()); - - // We fold the unconditional branch if we can easily update all PHI nodes in - // common successors: - // 1> We have a constant incoming value for the conditional branch; - // 2> We have "Cond" as the incoming value for the unconditional branch; - // 3> SI2->getCondition() and Cond have same operands. - CmpInst *Ci2 = dyn_cast(SI2->getCondition()); - if (!Ci2) - return false; - if (!(Cond->getOperand(0) == Ci2->getOperand(0) && - Cond->getOperand(1) == Ci2->getOperand(1)) && - !(Cond->getOperand(0) == Ci2->getOperand(1) && - Cond->getOperand(1) == Ci2->getOperand(0))) - return false; - - BasicBlock *SI1BB = SI1->getParent(); - BasicBlock *SI2BB = SI2->getParent(); - SmallPtrSet SI1Succs(succ_begin(SI1BB), succ_end(SI1BB)); - for (BasicBlock *Succ : successors(SI2BB)) - if (SI1Succs.count(Succ)) - for (BasicBlock::iterator BBI = Succ->begin(); isa(BBI); ++BBI) { - PHINode *PN = cast(BBI); - if (PN->getIncomingValueForBlock(SI1BB) != Cond || - !isa(PN->getIncomingValueForBlock(SI2BB))) - return false; - PhiNodes.push_back(PN); - } - return true; -} - /// Update PHI nodes in Succ to indicate that there will now be entries in it /// from the 'NewPred' block. The values that will be flowing into the PHI nodes /// will be the same as those coming in from ExistPred, an existing predecessor @@ -651,7 +655,7 @@ private: /// vector. /// One "Extra" case is allowed to differ from the other. void gather(Value *V) { - bool isEQ = (cast(V)->getOpcode() == Instruction::Or); + bool isEQ = match(V, m_LogicalOr(m_Value(), m_Value())); // Keep a stack (SmallVector for efficiency) for depth-first traversal SmallVector DFT; @@ -666,11 +670,14 @@ private: if (Instruction *I = dyn_cast(V)) { // If it is a || (or && depending on isEQ), process the operands. - if (I->getOpcode() == (isEQ ? Instruction::Or : Instruction::And)) { - if (Visited.insert(I->getOperand(1)).second) - DFT.push_back(I->getOperand(1)); - if (Visited.insert(I->getOperand(0)).second) - DFT.push_back(I->getOperand(0)); + Value *Op0, *Op1; + if (isEQ ? match(I, m_LogicalOr(m_Value(Op0), m_Value(Op1))) + : match(I, m_LogicalAnd(m_Value(Op0), m_Value(Op1)))) { + if (Visited.insert(Op1).second) + DFT.push_back(Op1); + if (Visited.insert(Op0).second) + DFT.push_back(Op0); + continue; } @@ -765,7 +772,7 @@ BasicBlock *SimplifyCFGOpt::GetValueEqualityComparisonCases( static void EliminateBlockCases(BasicBlock *BB, std::vector &Cases) { - Cases.erase(std::remove(Cases.begin(), Cases.end(), BB), Cases.end()); + llvm::erase_value(Cases, BB); } /// Return true if there are any keys in C1 that exist in C2 as well. @@ -875,13 +882,18 @@ bool SimplifyCFGOpt::SimplifyEqualityComparisonWithOnlyPredecessor( (void)NI; // Remove PHI node entries for the dead edge. - ThisCases[0].Dest->removePredecessor(TI->getParent()); + ThisCases[0].Dest->removePredecessor(PredDef); LLVM_DEBUG(dbgs() << "Threading pred instr: " << *Pred->getTerminator() << "Through successor TI: " << *TI << "Leaving: " << *NI << "\n"); EraseTerminatorAndDCECond(TI); + + if (DTU) + DTU->applyUpdates( + {{DominatorTree::Delete, PredDef, ThisCases[0].Dest}}); + return true; } @@ -894,13 +906,25 @@ bool SimplifyCFGOpt::SimplifyEqualityComparisonWithOnlyPredecessor( LLVM_DEBUG(dbgs() << "Threading pred instr: " << *Pred->getTerminator() << "Through successor TI: " << *TI); + SmallMapVector NumPerSuccessorCases; for (SwitchInst::CaseIt i = SI->case_end(), e = SI->case_begin(); i != e;) { --i; + auto *Successor = i->getCaseSuccessor(); + ++NumPerSuccessorCases[Successor]; if (DeadCases.count(i->getCaseValue())) { - i->getCaseSuccessor()->removePredecessor(TI->getParent()); + Successor->removePredecessor(PredDef); SI.removeCase(i); + --NumPerSuccessorCases[Successor]; } } + + std::vector Updates; + for (const std::pair &I : NumPerSuccessorCases) + if (I.second == 0) + Updates.push_back({DominatorTree::Delete, PredDef, I.first}); + if (DTU) + DTU->applyUpdates(Updates); + LLVM_DEBUG(dbgs() << "Leaving: " << *TI << "\n"); return true; } @@ -930,12 +954,16 @@ bool SimplifyCFGOpt::SimplifyEqualityComparisonWithOnlyPredecessor( if (!TheRealDest) TheRealDest = ThisDef; + SmallSetVector RemovedSuccs; + // Remove PHI node entries for dead edges. BasicBlock *CheckEdge = TheRealDest; for (BasicBlock *Succ : successors(TIBB)) - if (Succ != CheckEdge) + if (Succ != CheckEdge) { + if (Succ != TheRealDest) + RemovedSuccs.insert(Succ); Succ->removePredecessor(TIBB); - else + } else CheckEdge = nullptr; // Insert the new branch. @@ -947,6 +975,13 @@ bool SimplifyCFGOpt::SimplifyEqualityComparisonWithOnlyPredecessor( << "\n"); EraseTerminatorAndDCECond(TI); + if (DTU) { + SmallVector Updates; + Updates.reserve(RemovedSuccs.size()); + for (auto *RemovedSucc : RemovedSuccs) + Updates.push_back({DominatorTree::Delete, TIBB, RemovedSucc}); + DTU->applyUpdates(Updates); + } return true; } @@ -1014,219 +1049,300 @@ static void FitWeights(MutableArrayRef Weights) { } } -/// The specified terminator is a value equality comparison instruction -/// (either a switch or a branch on "X == c"). -/// See if any of the predecessors of the terminator block are value comparisons -/// on the same value. If so, and if safe to do so, fold them together. -bool SimplifyCFGOpt::FoldValueComparisonIntoPredecessors(Instruction *TI, - IRBuilder<> &Builder) { - BasicBlock *BB = TI->getParent(); - Value *CV = isValueEqualityComparison(TI); // CondVal - assert(CV && "Not a comparison?"); - bool Changed = false; +static void CloneInstructionsIntoPredecessorBlockAndUpdateSSAUses( + BasicBlock *BB, BasicBlock *PredBlock, ValueToValueMapTy &VMap) { + Instruction *PTI = PredBlock->getTerminator(); - SmallVector Preds(pred_begin(BB), pred_end(BB)); - while (!Preds.empty()) { - BasicBlock *Pred = Preds.pop_back_val(); + // If we have bonus instructions, clone them into the predecessor block. + // Note that there may be multiple predecessor blocks, so we cannot move + // bonus instructions to a predecessor block. + for (Instruction &BonusInst : *BB) { + if (isa(BonusInst) || BonusInst.isTerminator()) + continue; - // See if the predecessor is a comparison with the same value. - Instruction *PTI = Pred->getTerminator(); - Value *PCV = isValueEqualityComparison(PTI); // PredCondVal + Instruction *NewBonusInst = BonusInst.clone(); - if (PCV == CV && TI != PTI) { - SmallSetVector FailBlocks; - if (!SafeToMergeTerminators(TI, PTI, &FailBlocks)) { - for (auto *Succ : FailBlocks) { - if (!SplitBlockPredecessors(Succ, TI->getParent(), ".fold.split")) - return false; - } - } + if (PTI->getDebugLoc() != NewBonusInst->getDebugLoc()) { + // Unless the instruction has the same !dbg location as the original + // branch, drop it. When we fold the bonus instructions we want to make + // sure we reset their debug locations in order to avoid stepping on + // dead code caused by folding dead branches. + NewBonusInst->setDebugLoc(DebugLoc()); + } - // Figure out which 'cases' to copy from SI to PSI. - std::vector BBCases; - BasicBlock *BBDefault = GetValueEqualityComparisonCases(TI, BBCases); - - std::vector PredCases; - BasicBlock *PredDefault = GetValueEqualityComparisonCases(PTI, PredCases); - - // Based on whether the default edge from PTI goes to BB or not, fill in - // PredCases and PredDefault with the new switch cases we would like to - // build. - SmallVector NewSuccessors; - - // Update the branch weight metadata along the way - SmallVector Weights; - bool PredHasWeights = HasBranchWeights(PTI); - bool SuccHasWeights = HasBranchWeights(TI); - - if (PredHasWeights) { - GetBranchWeights(PTI, Weights); - // branch-weight metadata is inconsistent here. - if (Weights.size() != 1 + PredCases.size()) - PredHasWeights = SuccHasWeights = false; - } else if (SuccHasWeights) - // If there are no predecessor weights but there are successor weights, - // populate Weights with 1, which will later be scaled to the sum of - // successor's weights - Weights.assign(1 + PredCases.size(), 1); - - SmallVector SuccWeights; - if (SuccHasWeights) { - GetBranchWeights(TI, SuccWeights); - // branch-weight metadata is inconsistent here. - if (SuccWeights.size() != 1 + BBCases.size()) - PredHasWeights = SuccHasWeights = false; - } else if (PredHasWeights) - SuccWeights.assign(1 + BBCases.size(), 1); - - if (PredDefault == BB) { - // If this is the default destination from PTI, only the edges in TI - // that don't occur in PTI, or that branch to BB will be activated. - std::set PTIHandled; - for (unsigned i = 0, e = PredCases.size(); i != e; ++i) - if (PredCases[i].Dest != BB) - PTIHandled.insert(PredCases[i].Value); - else { - // The default destination is BB, we don't need explicit targets. - std::swap(PredCases[i], PredCases.back()); - - if (PredHasWeights || SuccHasWeights) { - // Increase weight for the default case. - Weights[0] += Weights[i + 1]; - std::swap(Weights[i + 1], Weights.back()); - Weights.pop_back(); - } + RemapInstruction(NewBonusInst, VMap, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + VMap[&BonusInst] = NewBonusInst; + + // If we moved a load, we cannot any longer claim any knowledge about + // its potential value. The previous information might have been valid + // only given the branch precondition. + // For an analogous reason, we must also drop all the metadata whose + // semantics we don't understand. We *can* preserve !annotation, because + // it is tied to the instruction itself, not the value or position. + NewBonusInst->dropUnknownNonDebugMetadata(LLVMContext::MD_annotation); + + PredBlock->getInstList().insert(PTI->getIterator(), NewBonusInst); + NewBonusInst->takeName(&BonusInst); + BonusInst.setName(NewBonusInst->getName() + ".old"); + + // Update (liveout) uses of bonus instructions, + // now that the bonus instruction has been cloned into predecessor. + SSAUpdater SSAUpdate; + SSAUpdate.Initialize(BonusInst.getType(), + (NewBonusInst->getName() + ".merge").str()); + SSAUpdate.AddAvailableValue(BB, &BonusInst); + SSAUpdate.AddAvailableValue(PredBlock, NewBonusInst); + for (Use &U : make_early_inc_range(BonusInst.uses())) + SSAUpdate.RewriteUseAfterInsertions(U); + } +} - PredCases.pop_back(); - --i; - --e; - } +bool SimplifyCFGOpt::PerformValueComparisonIntoPredecessorFolding( + Instruction *TI, Value *&CV, Instruction *PTI, IRBuilder<> &Builder) { + BasicBlock *BB = TI->getParent(); + BasicBlock *Pred = PTI->getParent(); + + std::vector Updates; + + // Figure out which 'cases' to copy from SI to PSI. + std::vector BBCases; + BasicBlock *BBDefault = GetValueEqualityComparisonCases(TI, BBCases); - // Reconstruct the new switch statement we will be building. - if (PredDefault != BBDefault) { - PredDefault->removePredecessor(Pred); - PredDefault = BBDefault; - NewSuccessors.push_back(BBDefault); + std::vector PredCases; + BasicBlock *PredDefault = GetValueEqualityComparisonCases(PTI, PredCases); + + // Based on whether the default edge from PTI goes to BB or not, fill in + // PredCases and PredDefault with the new switch cases we would like to + // build. + SmallMapVector NewSuccessors; + + // Update the branch weight metadata along the way + SmallVector Weights; + bool PredHasWeights = HasBranchWeights(PTI); + bool SuccHasWeights = HasBranchWeights(TI); + + if (PredHasWeights) { + GetBranchWeights(PTI, Weights); + // branch-weight metadata is inconsistent here. + if (Weights.size() != 1 + PredCases.size()) + PredHasWeights = SuccHasWeights = false; + } else if (SuccHasWeights) + // If there are no predecessor weights but there are successor weights, + // populate Weights with 1, which will later be scaled to the sum of + // successor's weights + Weights.assign(1 + PredCases.size(), 1); + + SmallVector SuccWeights; + if (SuccHasWeights) { + GetBranchWeights(TI, SuccWeights); + // branch-weight metadata is inconsistent here. + if (SuccWeights.size() != 1 + BBCases.size()) + PredHasWeights = SuccHasWeights = false; + } else if (PredHasWeights) + SuccWeights.assign(1 + BBCases.size(), 1); + + if (PredDefault == BB) { + // If this is the default destination from PTI, only the edges in TI + // that don't occur in PTI, or that branch to BB will be activated. + std::set PTIHandled; + for (unsigned i = 0, e = PredCases.size(); i != e; ++i) + if (PredCases[i].Dest != BB) + PTIHandled.insert(PredCases[i].Value); + else { + // The default destination is BB, we don't need explicit targets. + std::swap(PredCases[i], PredCases.back()); + + if (PredHasWeights || SuccHasWeights) { + // Increase weight for the default case. + Weights[0] += Weights[i + 1]; + std::swap(Weights[i + 1], Weights.back()); + Weights.pop_back(); } - unsigned CasesFromPred = Weights.size(); - uint64_t ValidTotalSuccWeight = 0; - for (unsigned i = 0, e = BBCases.size(); i != e; ++i) - if (!PTIHandled.count(BBCases[i].Value) && - BBCases[i].Dest != BBDefault) { - PredCases.push_back(BBCases[i]); - NewSuccessors.push_back(BBCases[i].Dest); - if (SuccHasWeights || PredHasWeights) { - // The default weight is at index 0, so weight for the ith case - // should be at index i+1. Scale the cases from successor by - // PredDefaultWeight (Weights[0]). - Weights.push_back(Weights[0] * SuccWeights[i + 1]); - ValidTotalSuccWeight += SuccWeights[i + 1]; - } - } + PredCases.pop_back(); + --i; + --e; + } + // Reconstruct the new switch statement we will be building. + if (PredDefault != BBDefault) { + PredDefault->removePredecessor(Pred); + if (PredDefault != BB) + Updates.push_back({DominatorTree::Delete, Pred, PredDefault}); + PredDefault = BBDefault; + ++NewSuccessors[BBDefault]; + } + + unsigned CasesFromPred = Weights.size(); + uint64_t ValidTotalSuccWeight = 0; + for (unsigned i = 0, e = BBCases.size(); i != e; ++i) + if (!PTIHandled.count(BBCases[i].Value) && BBCases[i].Dest != BBDefault) { + PredCases.push_back(BBCases[i]); + ++NewSuccessors[BBCases[i].Dest]; if (SuccHasWeights || PredHasWeights) { - ValidTotalSuccWeight += SuccWeights[0]; - // Scale the cases from predecessor by ValidTotalSuccWeight. - for (unsigned i = 1; i < CasesFromPred; ++i) - Weights[i] *= ValidTotalSuccWeight; - // Scale the default weight by SuccDefaultWeight (SuccWeights[0]). - Weights[0] *= SuccWeights[0]; + // The default weight is at index 0, so weight for the ith case + // should be at index i+1. Scale the cases from successor by + // PredDefaultWeight (Weights[0]). + Weights.push_back(Weights[0] * SuccWeights[i + 1]); + ValidTotalSuccWeight += SuccWeights[i + 1]; } - } else { - // If this is not the default destination from PSI, only the edges - // in SI that occur in PSI with a destination of BB will be - // activated. - std::set PTIHandled; - std::map WeightsForHandled; - for (unsigned i = 0, e = PredCases.size(); i != e; ++i) - if (PredCases[i].Dest == BB) { - PTIHandled.insert(PredCases[i].Value); - - if (PredHasWeights || SuccHasWeights) { - WeightsForHandled[PredCases[i].Value] = Weights[i + 1]; - std::swap(Weights[i + 1], Weights.back()); - Weights.pop_back(); - } - - std::swap(PredCases[i], PredCases.back()); - PredCases.pop_back(); - --i; - --e; - } + } - // Okay, now we know which constants were sent to BB from the - // predecessor. Figure out where they will all go now. - for (unsigned i = 0, e = BBCases.size(); i != e; ++i) - if (PTIHandled.count(BBCases[i].Value)) { - // If this is one we are capable of getting... - if (PredHasWeights || SuccHasWeights) - Weights.push_back(WeightsForHandled[BBCases[i].Value]); - PredCases.push_back(BBCases[i]); - NewSuccessors.push_back(BBCases[i].Dest); - PTIHandled.erase( - BBCases[i].Value); // This constant is taken care of - } + if (SuccHasWeights || PredHasWeights) { + ValidTotalSuccWeight += SuccWeights[0]; + // Scale the cases from predecessor by ValidTotalSuccWeight. + for (unsigned i = 1; i < CasesFromPred; ++i) + Weights[i] *= ValidTotalSuccWeight; + // Scale the default weight by SuccDefaultWeight (SuccWeights[0]). + Weights[0] *= SuccWeights[0]; + } + } else { + // If this is not the default destination from PSI, only the edges + // in SI that occur in PSI with a destination of BB will be + // activated. + std::set PTIHandled; + std::map WeightsForHandled; + for (unsigned i = 0, e = PredCases.size(); i != e; ++i) + if (PredCases[i].Dest == BB) { + PTIHandled.insert(PredCases[i].Value); - // If there are any constants vectored to BB that TI doesn't handle, - // they must go to the default destination of TI. - for (ConstantInt *I : PTIHandled) { - if (PredHasWeights || SuccHasWeights) - Weights.push_back(WeightsForHandled[I]); - PredCases.push_back(ValueEqualityComparisonCase(I, BBDefault)); - NewSuccessors.push_back(BBDefault); + if (PredHasWeights || SuccHasWeights) { + WeightsForHandled[PredCases[i].Value] = Weights[i + 1]; + std::swap(Weights[i + 1], Weights.back()); + Weights.pop_back(); } + + std::swap(PredCases[i], PredCases.back()); + PredCases.pop_back(); + --i; + --e; } - // Okay, at this point, we know which new successor Pred will get. Make - // sure we update the number of entries in the PHI nodes for these - // successors. - for (BasicBlock *NewSuccessor : NewSuccessors) - AddPredecessorToBlock(NewSuccessor, Pred, BB); - - Builder.SetInsertPoint(PTI); - // Convert pointer to int before we switch. - if (CV->getType()->isPointerTy()) { - CV = Builder.CreatePtrToInt(CV, DL.getIntPtrType(CV->getType()), - "magicptr"); + // Okay, now we know which constants were sent to BB from the + // predecessor. Figure out where they will all go now. + for (unsigned i = 0, e = BBCases.size(); i != e; ++i) + if (PTIHandled.count(BBCases[i].Value)) { + // If this is one we are capable of getting... + if (PredHasWeights || SuccHasWeights) + Weights.push_back(WeightsForHandled[BBCases[i].Value]); + PredCases.push_back(BBCases[i]); + ++NewSuccessors[BBCases[i].Dest]; + PTIHandled.erase(BBCases[i].Value); // This constant is taken care of } - // Now that the successors are updated, create the new Switch instruction. - SwitchInst *NewSI = - Builder.CreateSwitch(CV, PredDefault, PredCases.size()); - NewSI->setDebugLoc(PTI->getDebugLoc()); - for (ValueEqualityComparisonCase &V : PredCases) - NewSI->addCase(V.Value, V.Dest); + // If there are any constants vectored to BB that TI doesn't handle, + // they must go to the default destination of TI. + for (ConstantInt *I : PTIHandled) { + if (PredHasWeights || SuccHasWeights) + Weights.push_back(WeightsForHandled[I]); + PredCases.push_back(ValueEqualityComparisonCase(I, BBDefault)); + ++NewSuccessors[BBDefault]; + } + } + + // Okay, at this point, we know which new successor Pred will get. Make + // sure we update the number of entries in the PHI nodes for these + // successors. + for (const std::pair &NewSuccessor : + NewSuccessors) { + for (auto I : seq(0, NewSuccessor.second)) { + (void)I; + AddPredecessorToBlock(NewSuccessor.first, Pred, BB); + } + if (!is_contained(successors(Pred), NewSuccessor.first)) + Updates.push_back({DominatorTree::Insert, Pred, NewSuccessor.first}); + } + + Builder.SetInsertPoint(PTI); + // Convert pointer to int before we switch. + if (CV->getType()->isPointerTy()) { + CV = + Builder.CreatePtrToInt(CV, DL.getIntPtrType(CV->getType()), "magicptr"); + } + + // Now that the successors are updated, create the new Switch instruction. + SwitchInst *NewSI = Builder.CreateSwitch(CV, PredDefault, PredCases.size()); + NewSI->setDebugLoc(PTI->getDebugLoc()); + for (ValueEqualityComparisonCase &V : PredCases) + NewSI->addCase(V.Value, V.Dest); + + if (PredHasWeights || SuccHasWeights) { + // Halve the weights if any of them cannot fit in an uint32_t + FitWeights(Weights); + + SmallVector MDWeights(Weights.begin(), Weights.end()); - if (PredHasWeights || SuccHasWeights) { - // Halve the weights if any of them cannot fit in an uint32_t - FitWeights(Weights); + setBranchWeights(NewSI, MDWeights); + } - SmallVector MDWeights(Weights.begin(), Weights.end()); + EraseTerminatorAndDCECond(PTI); - setBranchWeights(NewSI, MDWeights); + // Okay, last check. If BB is still a successor of PSI, then we must + // have an infinite loop case. If so, add an infinitely looping block + // to handle the case to preserve the behavior of the code. + BasicBlock *InfLoopBlock = nullptr; + for (unsigned i = 0, e = NewSI->getNumSuccessors(); i != e; ++i) + if (NewSI->getSuccessor(i) == BB) { + if (!InfLoopBlock) { + // Insert it at the end of the function, because it's either code, + // or it won't matter if it's hot. :) + InfLoopBlock = + BasicBlock::Create(BB->getContext(), "infloop", BB->getParent()); + BranchInst::Create(InfLoopBlock, InfLoopBlock); + Updates.push_back({DominatorTree::Insert, InfLoopBlock, InfLoopBlock}); } + NewSI->setSuccessor(i, InfLoopBlock); + } - EraseTerminatorAndDCECond(PTI); - - // Okay, last check. If BB is still a successor of PSI, then we must - // have an infinite loop case. If so, add an infinitely looping block - // to handle the case to preserve the behavior of the code. - BasicBlock *InfLoopBlock = nullptr; - for (unsigned i = 0, e = NewSI->getNumSuccessors(); i != e; ++i) - if (NewSI->getSuccessor(i) == BB) { - if (!InfLoopBlock) { - // Insert it at the end of the function, because it's either code, - // or it won't matter if it's hot. :) - InfLoopBlock = BasicBlock::Create(BB->getContext(), "infloop", - BB->getParent()); - BranchInst::Create(InfLoopBlock, InfLoopBlock); - } - NewSI->setSuccessor(i, InfLoopBlock); - } + if (InfLoopBlock) + Updates.push_back({DominatorTree::Insert, Pred, InfLoopBlock}); - Changed = true; + Updates.push_back({DominatorTree::Delete, Pred, BB}); + + if (DTU) + DTU->applyUpdates(Updates); + + ++NumFoldValueComparisonIntoPredecessors; + return true; +} + +/// The specified terminator is a value equality comparison instruction +/// (either a switch or a branch on "X == c"). +/// See if any of the predecessors of the terminator block are value comparisons +/// on the same value. If so, and if safe to do so, fold them together. +bool SimplifyCFGOpt::FoldValueComparisonIntoPredecessors(Instruction *TI, + IRBuilder<> &Builder) { + BasicBlock *BB = TI->getParent(); + Value *CV = isValueEqualityComparison(TI); // CondVal + assert(CV && "Not a comparison?"); + + bool Changed = false; + + SmallSetVector Preds(pred_begin(BB), pred_end(BB)); + while (!Preds.empty()) { + BasicBlock *Pred = Preds.pop_back_val(); + Instruction *PTI = Pred->getTerminator(); + + // Don't try to fold into itself. + if (Pred == BB) + continue; + + // See if the predecessor is a comparison with the same value. + Value *PCV = isValueEqualityComparison(PTI); // PredCondVal + if (PCV != CV) + continue; + + SmallSetVector FailBlocks; + if (!SafeToMergeTerminators(TI, PTI, &FailBlocks)) { + for (auto *Succ : FailBlocks) { + if (!SplitBlockPredecessors(Succ, TI->getParent(), ".fold.split", DTU)) + return false; + } } + + PerformValueComparisonIntoPredecessorFolding(TI, CV, PTI, Builder); + Changed = true; } return Changed; } @@ -1248,7 +1364,7 @@ static bool isSafeToHoistInvoke(BasicBlock *BB1, BasicBlock *BB2, return true; } -static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I); +static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValueMayBeModified = false); /// Given a conditional branch that goes to BB1 and BB2, hoist any common code /// in the two blocks up into the branch block. The caller of this function @@ -1285,6 +1401,12 @@ bool SimplifyCFGOpt::HoistThenElseCodeToIf(BranchInst *BI, BasicBlock *BIParent = BI->getParent(); bool Changed = false; + + auto _ = make_scope_exit([&]() { + if (Changed) + ++NumHoistCommonCode; + }); + do { // If we are hoisting the terminator instruction, don't move one (making a // broken BB), instead clone it, and remove BI. @@ -1353,6 +1475,7 @@ bool SimplifyCFGOpt::HoistThenElseCodeToIf(BranchInst *BI, I2->eraseFromParent(); Changed = true; } + ++NumHoistCommonInstrs; I1 = &*BB1_Itr++; I2 = &*BB2_Itr++; @@ -1407,6 +1530,8 @@ HoistTerminator: I2->replaceAllUsesWith(NT); NT->takeName(I1); } + Changed = true; + ++NumHoistCommonInstrs; // Ensure terminator gets a debug location, even an unknown one, in case // it involves inlinable calls. @@ -1448,12 +1573,20 @@ HoistTerminator: } } + SmallVector Updates; + // Update any PHI nodes in our new successors. - for (BasicBlock *Succ : successors(BB1)) + for (BasicBlock *Succ : successors(BB1)) { AddPredecessorToBlock(Succ, BIParent, BB1); + Updates.push_back({DominatorTree::Insert, BIParent, Succ}); + } + for (BasicBlock *Succ : successors(BI)) + Updates.push_back({DominatorTree::Delete, BIParent, Succ}); EraseTerminatorAndDCECond(BI); - return true; + if (DTU) + DTU->applyUpdates(Updates); + return Changed; } // Check lifetime markers. @@ -1744,7 +1877,8 @@ namespace { /// true, sink any common code from the predecessors to BB. /// We also allow one predecessor to end with conditional branch (but no more /// than one). -static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { +static bool SinkCommonCodeFromPredecessors(BasicBlock *BB, + DomTreeUpdater *DTU) { // We support two situations: // (1) all incoming arcs are unconditional // (2) one incoming arc is conditional @@ -1800,7 +1934,6 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { if (UnconditionalPreds.size() < 2) return false; - bool Changed = false; // We take a two-step approach to tail sinking. First we scan from the end of // each block upwards in lockstep. If the n'th instruction from the end of each // block can be sunk, those instructions are added to ValuesToSink and we @@ -1820,6 +1953,12 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { --LRI; } + // If no instructions can be sunk, early-return. + if (ScanIdx == 0) + return false; + + bool Changed = false; + auto ProfitableToSinkInstruction = [&](LockstepReverseIterator &LRI) { unsigned NumPHIdValues = 0; for (auto *I : *LRI) @@ -1834,7 +1973,7 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { return NumPHIInsts <= 1; }; - if (ScanIdx > 0 && Cond) { + if (Cond) { // Check if we would actually sink anything first! This mutates the CFG and // adds an extra block. The goal in doing this is to allow instructions that // couldn't be sunk before to be sunk - obviously, speculatable instructions @@ -1857,7 +1996,7 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { LLVM_DEBUG(dbgs() << "SINK: Splitting edge\n"); // We have a conditional edge and we're going to sink some instructions. // Insert a new block postdominating all blocks we're going to sink from. - if (!SplitBlockPredecessors(BB, UnconditionalPreds, ".sink.split")) + if (!SplitBlockPredecessors(BB, UnconditionalPreds, ".sink.split", DTU)) // Edges couldn't be split. return false; Changed = true; @@ -1875,7 +2014,8 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { // sink presuming a later value will also be sunk, but stop half way through // and never actually sink it which means we produce more PHIs than intended. // This is unlikely in practice though. - for (unsigned SinkIdx = 0; SinkIdx != ScanIdx; ++SinkIdx) { + unsigned SinkIdx = 0; + for (; SinkIdx != ScanIdx; ++SinkIdx) { LLVM_DEBUG(dbgs() << "SINK: Sink: " << *UnconditionalPreds[0]->getTerminator()->getPrevNode() << "\n"); @@ -1890,11 +2030,18 @@ static bool SinkCommonCodeFromPredecessors(BasicBlock *BB) { break; } - if (!sinkLastInstruction(UnconditionalPreds)) - return Changed; - NumSinkCommons++; + if (!sinkLastInstruction(UnconditionalPreds)) { + LLVM_DEBUG( + dbgs() + << "SINK: stopping here, failed to actually sink instruction!\n"); + break; + } + + NumSinkCommonInstrs++; Changed = true; } + if (SinkIdx != 0) + ++NumSinkCommonCode; return Changed; } @@ -1938,7 +2085,9 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB, // Look for a store to the same pointer in BrBB. unsigned MaxNumInstToLookAt = 9; - for (Instruction &CurI : reverse(BrBB->instructionsWithoutDebug())) { + // Skip pseudo probe intrinsic calls which are not really killing any memory + // accesses. + for (Instruction &CurI : reverse(BrBB->instructionsWithoutDebug(true))) { if (!MaxNumInstToLookAt) break; --MaxNumInstToLookAt; @@ -1959,6 +2108,65 @@ static Value *isSafeToSpeculateStore(Instruction *I, BasicBlock *BrBB, return nullptr; } +/// Estimate the cost of the insertion(s) and check that the PHI nodes can be +/// converted to selects. +static bool validateAndCostRequiredSelects(BasicBlock *BB, BasicBlock *ThenBB, + BasicBlock *EndBB, + unsigned &SpeculatedInstructions, + int &BudgetRemaining, + const TargetTransformInfo &TTI) { + TargetTransformInfo::TargetCostKind CostKind = + BB->getParent()->hasMinSize() + ? TargetTransformInfo::TCK_CodeSize + : TargetTransformInfo::TCK_SizeAndLatency; + + bool HaveRewritablePHIs = false; + for (PHINode &PN : EndBB->phis()) { + Value *OrigV = PN.getIncomingValueForBlock(BB); + Value *ThenV = PN.getIncomingValueForBlock(ThenBB); + + // FIXME: Try to remove some of the duplication with HoistThenElseCodeToIf. + // Skip PHIs which are trivial. + if (ThenV == OrigV) + continue; + + BudgetRemaining -= + TTI.getCmpSelInstrCost(Instruction::Select, PN.getType(), nullptr, + CmpInst::BAD_ICMP_PREDICATE, CostKind); + + // Don't convert to selects if we could remove undefined behavior instead. + if (passingValueIsAlwaysUndefined(OrigV, &PN) || + passingValueIsAlwaysUndefined(ThenV, &PN)) + return false; + + HaveRewritablePHIs = true; + ConstantExpr *OrigCE = dyn_cast(OrigV); + ConstantExpr *ThenCE = dyn_cast(ThenV); + if (!OrigCE && !ThenCE) + continue; // Known safe and cheap. + + if ((ThenCE && !isSafeToSpeculativelyExecute(ThenCE)) || + (OrigCE && !isSafeToSpeculativelyExecute(OrigCE))) + return false; + unsigned OrigCost = OrigCE ? ComputeSpeculationCost(OrigCE, TTI) : 0; + unsigned ThenCost = ThenCE ? ComputeSpeculationCost(ThenCE, TTI) : 0; + unsigned MaxCost = + 2 * PHINodeFoldingThreshold * TargetTransformInfo::TCC_Basic; + if (OrigCost + ThenCost > MaxCost) + return false; + + // Account for the cost of an unfolded ConstantExpr which could end up + // getting expanded into Instructions. + // FIXME: This doesn't account for how many operations are combined in the + // constant expression. + ++SpeculatedInstructions; + if (SpeculatedInstructions > 1) + return false; + } + + return HaveRewritablePHIs; +} + /// Speculate a conditional basic block flattening the CFG. /// /// Note that this is a very risky transform currently. Speculating @@ -2005,6 +2213,8 @@ bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, BasicBlock *BB = BI->getParent(); BasicBlock *EndBB = ThenBB->getTerminator()->getSuccessor(0); + int BudgetRemaining = + PHINodeFoldingThreshold * TargetTransformInfo::TCC_Basic; // If ThenBB is actually on the false edge of the conditional branch, remember // to swap the select operands later. @@ -2037,6 +2247,14 @@ bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, continue; } + // Skip pseudo probes. The consequence is we lose track of the branch + // probability for ThenBB, which is fine since the optimization here takes + // place regardless of the branch probability. + if (isa(I)) { + SpeculatedDbgIntrinsics.push_back(I); + continue; + } + // Only speculatively execute a single instruction (not counting the // terminator) for now. ++SpeculatedInstructions; @@ -2082,50 +2300,13 @@ bool SimplifyCFGOpt::SpeculativelyExecuteBB(BranchInst *BI, BasicBlock *ThenBB, return false; } - // Check that the PHI nodes can be converted to selects. - bool HaveRewritablePHIs = false; - for (PHINode &PN : EndBB->phis()) { - Value *OrigV = PN.getIncomingValueForBlock(BB); - Value *ThenV = PN.getIncomingValueForBlock(ThenBB); - - // FIXME: Try to remove some of the duplication with HoistThenElseCodeToIf. - // Skip PHIs which are trivial. - if (ThenV == OrigV) - continue; - - // Don't convert to selects if we could remove undefined behavior instead. - if (passingValueIsAlwaysUndefined(OrigV, &PN) || - passingValueIsAlwaysUndefined(ThenV, &PN)) - return false; - - HaveRewritablePHIs = true; - ConstantExpr *OrigCE = dyn_cast(OrigV); - ConstantExpr *ThenCE = dyn_cast(ThenV); - if (!OrigCE && !ThenCE) - continue; // Known safe and cheap. - - if ((ThenCE && !isSafeToSpeculativelyExecute(ThenCE)) || - (OrigCE && !isSafeToSpeculativelyExecute(OrigCE))) - return false; - unsigned OrigCost = OrigCE ? ComputeSpeculationCost(OrigCE, TTI) : 0; - unsigned ThenCost = ThenCE ? ComputeSpeculationCost(ThenCE, TTI) : 0; - unsigned MaxCost = - 2 * PHINodeFoldingThreshold * TargetTransformInfo::TCC_Basic; - if (OrigCost + ThenCost > MaxCost) - return false; - - // Account for the cost of an unfolded ConstantExpr which could end up - // getting expanded into Instructions. - // FIXME: This doesn't account for how many operations are combined in the - // constant expression. - ++SpeculatedInstructions; - if (SpeculatedInstructions > 1) - return false; - } - - // If there are no PHIs to process, bail early. This helps ensure idempotence - // as well. - if (!HaveRewritablePHIs && !(HoistCondStores && SpeculatedStoreValue)) + // Check that we can insert the selects and that it's not too expensive to do + // so. + bool Convert = SpeculatedStore != nullptr; + Convert |= validateAndCostRequiredSelects(BB, ThenBB, EndBB, + SpeculatedInstructions, + BudgetRemaining, TTI); + if (!Convert || BudgetRemaining < 0) return false; // If we get here, we can hoist the instruction and if-convert. @@ -2199,6 +2380,12 @@ static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) { for (Instruction &I : BB->instructionsWithoutDebug()) { if (Size > MaxSmallBlockSize) return false; // Don't clone large BB's. + + // Can't fold blocks that contain noduplicate or convergent calls. + if (CallInst *CI = dyn_cast(&I)) + if (CI->cannotDuplicate() || CI->isConvergent()) + return false; + // We will delete Phis while threading, so Phis should not be accounted in // block's size if (!isa(I)) @@ -2221,8 +2408,8 @@ static bool BlockIsSimpleEnoughToThreadThrough(BasicBlock *BB) { /// If we have a conditional branch on a PHI node value that is defined in the /// same block as the branch and if any PHI entries are constants, thread edges /// corresponding to that entry to be branches to their ultimate destination. -static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, - AssumptionCache *AC) { +static bool FoldCondBranchOnPHI(BranchInst *BI, DomTreeUpdater *DTU, + const DataLayout &DL, AssumptionCache *AC) { BasicBlock *BB = BI->getParent(); PHINode *PN = dyn_cast(BI->getCondition()); // NOTE: we currently cannot transform this case if the PHI node is used @@ -2240,13 +2427,6 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, if (!BlockIsSimpleEnoughToThreadThrough(BB)) return false; - // Can't fold blocks that contain noduplicate or convergent calls. - if (any_of(*BB, [](const Instruction &I) { - const CallInst *CI = dyn_cast(&I); - return CI && (CI->cannotDuplicate() || CI->isConvergent()); - })) - return false; - // Okay, this is a simple enough basic block. See if any phi values are // constants. for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { @@ -2265,6 +2445,8 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, if (isa(PredBB->getTerminator())) continue; + SmallVector Updates; + // The dest block might have PHI nodes, other predecessors and other // difficult cases. Instead of being smart about this, just insert a new // block that jumps to the destination block, effectively splitting @@ -2273,6 +2455,7 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, BasicBlock::Create(BB->getContext(), RealDest->getName() + ".critedge", RealDest->getParent(), RealDest); BranchInst *CritEdgeBranch = BranchInst::Create(RealDest, EdgeBB); + Updates.push_back({DominatorTree::Insert, EdgeBB, RealDest}); CritEdgeBranch->setDebugLoc(BI->getDebugLoc()); // Update PHI nodes. @@ -2331,8 +2514,14 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, PredBBTI->setSuccessor(i, EdgeBB); } + Updates.push_back({DominatorTree::Insert, PredBB, EdgeBB}); + Updates.push_back({DominatorTree::Delete, PredBB, BB}); + + if (DTU) + DTU->applyUpdates(Updates); + // Recurse, simplifying any other constants. - return FoldCondBranchOnPHI(BI, DL, AC) || true; + return FoldCondBranchOnPHI(BI, DTU, DL, AC) || true; } return false; @@ -2341,7 +2530,7 @@ static bool FoldCondBranchOnPHI(BranchInst *BI, const DataLayout &DL, /// Given a BB that starts with the specified two-entry PHI node, /// see if we can eliminate it. static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, - const DataLayout &DL) { + DomTreeUpdater *DTU, const DataLayout &DL) { // Ok, this is a two entry PHI node. Check to see if this is a simple "if // statement", which has a very simple dominance structure. Basically, we // are trying to find the condition that is being branched on, which @@ -2374,11 +2563,13 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, int BudgetRemaining = TwoEntryPHINodeFoldingThreshold * TargetTransformInfo::TCC_Basic; + bool Changed = false; for (BasicBlock::iterator II = BB->begin(); isa(II);) { PHINode *PN = cast(II++); if (Value *V = SimplifyInstruction(PN, {DL, PN})) { PN->replaceAllUsesWith(V); PN->eraseFromParent(); + Changed = true; continue; } @@ -2386,7 +2577,7 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, BudgetRemaining, TTI) || !DominatesMergePoint(PN->getIncomingValue(1), BB, AggressiveInsts, BudgetRemaining, TTI)) - return false; + return Changed; } // If we folded the first phi, PN dangles at this point. Refresh it. If @@ -2413,7 +2604,7 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, isa(IfCond)) && !CanHoistNotFromBothValues(PN->getIncomingValue(0), PN->getIncomingValue(1))) - return false; + return Changed; // If all PHI nodes are promotable, check to make sure that all instructions // in the predecessor blocks can be promoted as well. If not, we won't be able @@ -2427,11 +2618,12 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, } else { DomBlock = *pred_begin(IfBlock1); for (BasicBlock::iterator I = IfBlock1->begin(); !I->isTerminator(); ++I) - if (!AggressiveInsts.count(&*I) && !isa(I)) { + if (!AggressiveInsts.count(&*I) && !isa(I) && + !isa(I)) { // This is not an aggressive instruction that we can promote. // Because of this, we won't be able to get rid of the control flow, so // the xform is not worth it. - return false; + return Changed; } } @@ -2440,11 +2632,12 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, } else { DomBlock = *pred_begin(IfBlock2); for (BasicBlock::iterator I = IfBlock2->begin(); !I->isTerminator(); ++I) - if (!AggressiveInsts.count(&*I) && !isa(I)) { + if (!AggressiveInsts.count(&*I) && !isa(I) && + !isa(I)) { // This is not an aggressive instruction that we can promote. // Because of this, we won't be able to get rid of the control flow, so // the xform is not worth it. - return false; + return Changed; } } assert(DomBlock && "Failed to find root DomBlock"); @@ -2487,7 +2680,18 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, Instruction *OldTI = DomBlock->getTerminator(); Builder.SetInsertPoint(OldTI); Builder.CreateBr(BB); + + SmallVector Updates; + if (DTU) { + Updates.push_back({DominatorTree::Insert, DomBlock, BB}); + for (auto *Successor : successors(DomBlock)) + Updates.push_back({DominatorTree::Delete, DomBlock, Successor}); + } + OldTI->eraseFromParent(); + if (DTU) + DTU->applyUpdates(Updates); + return true; } @@ -2496,9 +2700,11 @@ static bool FoldTwoEntryPHINode(PHINode *PN, const TargetTransformInfo &TTI, /// introducing a select if the return values disagree. bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, IRBuilder<> &Builder) { + auto *BB = BI->getParent(); assert(BI->isConditional() && "Must be a conditional branch"); BasicBlock *TrueSucc = BI->getSuccessor(0); BasicBlock *FalseSucc = BI->getSuccessor(1); + // NOTE: destinations may match, this could be degenerate uncond branch. ReturnInst *TrueRet = cast(TrueSucc->getTerminator()); ReturnInst *FalseRet = cast(FalseSucc->getTerminator()); @@ -2515,10 +2721,17 @@ bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, // there is no return value for this function, just change the // branch into a return. if (FalseRet->getNumOperands() == 0) { - TrueSucc->removePredecessor(BI->getParent()); - FalseSucc->removePredecessor(BI->getParent()); + TrueSucc->removePredecessor(BB); + FalseSucc->removePredecessor(BB); Builder.CreateRetVoid(); EraseTerminatorAndDCECond(BI); + if (DTU) { + SmallVector Updates; + Updates.push_back({DominatorTree::Delete, BB, TrueSucc}); + if (TrueSucc != FalseSucc) + Updates.push_back({DominatorTree::Delete, BB, FalseSucc}); + DTU->applyUpdates(Updates); + } return true; } @@ -2530,10 +2743,10 @@ bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, // Unwrap any PHI nodes in the return blocks. if (PHINode *TVPN = dyn_cast_or_null(TrueValue)) if (TVPN->getParent() == TrueSucc) - TrueValue = TVPN->getIncomingValueForBlock(BI->getParent()); + TrueValue = TVPN->getIncomingValueForBlock(BB); if (PHINode *FVPN = dyn_cast_or_null(FalseValue)) if (FVPN->getParent() == FalseSucc) - FalseValue = FVPN->getIncomingValueForBlock(BI->getParent()); + FalseValue = FVPN->getIncomingValueForBlock(BB); // In order for this transformation to be safe, we must be able to // unconditionally execute both operands to the return. This is @@ -2549,8 +2762,8 @@ bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, // Okay, we collected all the mapped values and checked them for sanity, and // defined to really do this transformation. First, update the CFG. - TrueSucc->removePredecessor(BI->getParent()); - FalseSucc->removePredecessor(BI->getParent()); + TrueSucc->removePredecessor(BB); + FalseSucc->removePredecessor(BB); // Insert select instructions where needed. Value *BrCond = BI->getCondition(); @@ -2575,27 +2788,17 @@ bool SimplifyCFGOpt::SimplifyCondBranchToTwoReturns(BranchInst *BI, << *TrueSucc << "\nFALSEBLOCK: " << *FalseSucc); EraseTerminatorAndDCECond(BI); + if (DTU) { + SmallVector Updates; + Updates.push_back({DominatorTree::Delete, BB, TrueSucc}); + if (TrueSucc != FalseSucc) + Updates.push_back({DominatorTree::Delete, BB, FalseSucc}); + DTU->applyUpdates(Updates); + } return true; } -/// Return true if the given instruction is available -/// in its predecessor block. If yes, the instruction will be removed. -static bool tryCSEWithPredecessor(Instruction *Inst, BasicBlock *PB) { - if (!isa(Inst) && !isa(Inst)) - return false; - for (Instruction &I : *PB) { - Instruction *PBI = &I; - // Check whether Inst and PBI generate the same value. - if (Inst->isIdenticalTo(PBI)) { - Inst->replaceAllUsesWith(PBI); - Inst->eraseFromParent(); - return true; - } - } - return false; -} - /// Return true if either PBI or BI has branch weight available, and store /// the weights in {Pred|Succ}{True|False}Weight. If one of PBI and BI does /// not have branch weight, use 1:1 as its weight. @@ -2619,63 +2822,174 @@ static bool extractPredSuccWeights(BranchInst *PBI, BranchInst *BI, } } +// Determine if the two branches share a common destination, +// and deduce a glue that we need to use to join branch's conditions +// to arrive at the common destination. +static Optional> +CheckIfCondBranchesShareCommonDestination(BranchInst *BI, BranchInst *PBI) { + assert(BI && PBI && BI->isConditional() && PBI->isConditional() && + "Both blocks must end with a conditional branches."); + assert(is_contained(predecessors(BI->getParent()), PBI->getParent()) && + "PredBB must be a predecessor of BB."); + + if (PBI->getSuccessor(0) == BI->getSuccessor(0)) + return {{Instruction::Or, false}}; + else if (PBI->getSuccessor(1) == BI->getSuccessor(1)) + return {{Instruction::And, false}}; + else if (PBI->getSuccessor(0) == BI->getSuccessor(1)) + return {{Instruction::And, true}}; + else if (PBI->getSuccessor(1) == BI->getSuccessor(0)) + return {{Instruction::Or, true}}; + return None; +} + +static bool PerformBranchToCommonDestFolding(BranchInst *BI, BranchInst *PBI, + DomTreeUpdater *DTU, + MemorySSAUpdater *MSSAU) { + BasicBlock *BB = BI->getParent(); + BasicBlock *PredBlock = PBI->getParent(); + + // Determine if the two branches share a common destination. + Instruction::BinaryOps Opc; + bool InvertPredCond; + std::tie(Opc, InvertPredCond) = + *CheckIfCondBranchesShareCommonDestination(BI, PBI); + + LLVM_DEBUG(dbgs() << "FOLDING BRANCH TO COMMON DEST:\n" << *PBI << *BB); + + IRBuilder<> Builder(PBI); + // The builder is used to create instructions to eliminate the branch in BB. + // If BB's terminator has !annotation metadata, add it to the new + // instructions. + Builder.CollectMetadataToCopy(BB->getTerminator(), + {LLVMContext::MD_annotation}); + + // If we need to invert the condition in the pred block to match, do so now. + if (InvertPredCond) { + Value *NewCond = PBI->getCondition(); + if (NewCond->hasOneUse() && isa(NewCond)) { + CmpInst *CI = cast(NewCond); + CI->setPredicate(CI->getInversePredicate()); + } else { + NewCond = + Builder.CreateNot(NewCond, PBI->getCondition()->getName() + ".not"); + } + + PBI->setCondition(NewCond); + PBI->swapSuccessors(); + } + + BasicBlock *UniqueSucc = + PBI->getSuccessor(0) == BB ? BI->getSuccessor(0) : BI->getSuccessor(1); + + // Before cloning instructions, notify the successor basic block that it + // is about to have a new predecessor. This will update PHI nodes, + // which will allow us to update live-out uses of bonus instructions. + AddPredecessorToBlock(UniqueSucc, PredBlock, BB, MSSAU); + + // Try to update branch weights. + uint64_t PredTrueWeight, PredFalseWeight, SuccTrueWeight, SuccFalseWeight; + if (extractPredSuccWeights(PBI, BI, PredTrueWeight, PredFalseWeight, + SuccTrueWeight, SuccFalseWeight)) { + SmallVector NewWeights; + + if (PBI->getSuccessor(0) == BB) { + // PBI: br i1 %x, BB, FalseDest + // BI: br i1 %y, UniqueSucc, FalseDest + // TrueWeight is TrueWeight for PBI * TrueWeight for BI. + NewWeights.push_back(PredTrueWeight * SuccTrueWeight); + // FalseWeight is FalseWeight for PBI * TotalWeight for BI + + // TrueWeight for PBI * FalseWeight for BI. + // We assume that total weights of a BranchInst can fit into 32 bits. + // Therefore, we will not have overflow using 64-bit arithmetic. + NewWeights.push_back(PredFalseWeight * + (SuccFalseWeight + SuccTrueWeight) + + PredTrueWeight * SuccFalseWeight); + } else { + // PBI: br i1 %x, TrueDest, BB + // BI: br i1 %y, TrueDest, UniqueSucc + // TrueWeight is TrueWeight for PBI * TotalWeight for BI + + // FalseWeight for PBI * TrueWeight for BI. + NewWeights.push_back(PredTrueWeight * (SuccFalseWeight + SuccTrueWeight) + + PredFalseWeight * SuccTrueWeight); + // FalseWeight is FalseWeight for PBI * FalseWeight for BI. + NewWeights.push_back(PredFalseWeight * SuccFalseWeight); + } + + // Halve the weights if any of them cannot fit in an uint32_t + FitWeights(NewWeights); + + SmallVector MDWeights(NewWeights.begin(), NewWeights.end()); + setBranchWeights(PBI, MDWeights[0], MDWeights[1]); + + // TODO: If BB is reachable from all paths through PredBlock, then we + // could replace PBI's branch probabilities with BI's. + } else + PBI->setMetadata(LLVMContext::MD_prof, nullptr); + + // Now, update the CFG. + PBI->setSuccessor(PBI->getSuccessor(0) != BB, UniqueSucc); + + if (DTU) + DTU->applyUpdates({{DominatorTree::Insert, PredBlock, UniqueSucc}, + {DominatorTree::Delete, PredBlock, BB}}); + + // If BI was a loop latch, it may have had associated loop metadata. + // We need to copy it to the new latch, that is, PBI. + if (MDNode *LoopMD = BI->getMetadata(LLVMContext::MD_loop)) + PBI->setMetadata(LLVMContext::MD_loop, LoopMD); + + ValueToValueMapTy VMap; // maps original values to cloned values + CloneInstructionsIntoPredecessorBlockAndUpdateSSAUses(BB, PredBlock, VMap); + + // Now that the Cond was cloned into the predecessor basic block, + // or/and the two conditions together. + Instruction *NewCond = cast(Builder.CreateBinOp( + Opc, PBI->getCondition(), VMap[BI->getCondition()], "or.cond")); + PBI->setCondition(NewCond); + + // Copy any debug value intrinsics into the end of PredBlock. + for (Instruction &I : *BB) { + if (isa(I)) { + Instruction *NewI = I.clone(); + RemapInstruction(NewI, VMap, + RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); + NewI->insertBefore(PBI); + } + } + + ++NumFoldBranchToCommonDest; + return true; +} + /// If this basic block is simple enough, and if a predecessor branches to us /// and one of our successors, fold the block into the predecessor and use /// logical operations to pick the right destination. -bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU, +bool llvm::FoldBranchToCommonDest(BranchInst *BI, DomTreeUpdater *DTU, + MemorySSAUpdater *MSSAU, + const TargetTransformInfo *TTI, unsigned BonusInstThreshold) { + // If this block ends with an unconditional branch, + // let SpeculativelyExecuteBB() deal with it. + if (!BI->isConditional()) + return false; + BasicBlock *BB = BI->getParent(); const unsigned PredCount = pred_size(BB); bool Changed = false; - Instruction *Cond = nullptr; - if (BI->isConditional()) - Cond = dyn_cast(BI->getCondition()); - else { - // For unconditional branch, check for a simple CFG pattern, where - // BB has a single predecessor and BB's successor is also its predecessor's - // successor. If such pattern exists, check for CSE between BB and its - // predecessor. - if (BasicBlock *PB = BB->getSinglePredecessor()) - if (BranchInst *PBI = dyn_cast(PB->getTerminator())) - if (PBI->isConditional() && - (BI->getSuccessor(0) == PBI->getSuccessor(0) || - BI->getSuccessor(0) == PBI->getSuccessor(1))) { - for (auto I = BB->instructionsWithoutDebug().begin(), - E = BB->instructionsWithoutDebug().end(); - I != E;) { - Instruction *Curr = &*I++; - if (isa(Curr)) { - Cond = Curr; - break; - } - // Quit if we can't remove this instruction. - if (!tryCSEWithPredecessor(Curr, PB)) - return Changed; - Changed = true; - } - } + TargetTransformInfo::TargetCostKind CostKind = + BB->getParent()->hasMinSize() ? TargetTransformInfo::TCK_CodeSize + : TargetTransformInfo::TCK_SizeAndLatency; - if (!Cond) - return Changed; - } + Instruction *Cond = dyn_cast(BI->getCondition()); if (!Cond || (!isa(Cond) && !isa(Cond)) || Cond->getParent() != BB || !Cond->hasOneUse()) return Changed; - // Make sure the instruction after the condition is the cond branch. - BasicBlock::iterator CondIt = ++Cond->getIterator(); - - // Ignore dbg intrinsics. - while (isa(CondIt)) - ++CondIt; - - if (&*CondIt != BI) - return Changed; - // Only allow this transformation if computing the condition doesn't involve // too many instructions and these involved instructions can be executed // unconditionally. We denote all involved instructions except the condition @@ -2683,19 +2997,16 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU, // number of the bonus instructions we'll need to create when cloning into // each predecessor does not exceed a certain threshold. unsigned NumBonusInsts = 0; - for (auto I = BB->begin(); Cond != &*I; ++I) { - // Ignore dbg intrinsics. - if (isa(I)) + for (Instruction &I : *BB) { + // Don't check the branch condition comparison itself. + if (&I == Cond) continue; - if (!I->hasOneUse() || !isSafeToSpeculativelyExecute(&*I)) - return Changed; - // I has only one use and can be executed unconditionally. - Instruction *User = dyn_cast(I->user_back()); - if (User == nullptr || User->getParent() != BB) + // Ignore dbg intrinsics, and the terminator. + if (isa(I) || isa(I)) + continue; + // I must be safe to execute unconditionally. + if (!isSafeToSpeculativelyExecute(&I)) return Changed; - // I is used in the same BB. Since BI uses Cond and doesn't have more slots - // to use any other instruction, User must be an instruction between next(I) - // and Cond. // Account for the cost of duplicating this instruction into each // predecessor. @@ -2715,9 +3026,7 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU, return Changed; // Finally, don't infinitely unroll conditional loops. - BasicBlock *TrueDest = BI->getSuccessor(0); - BasicBlock *FalseDest = (BI->isConditional()) ? BI->getSuccessor(1) : nullptr; - if (TrueDest == BB || FalseDest == BB) + if (is_contained(successors(BB), BB)) return Changed; for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) { @@ -2727,222 +3036,31 @@ bool llvm::FoldBranchToCommonDest(BranchInst *BI, MemorySSAUpdater *MSSAU, // Check that we have two conditional branches. If there is a PHI node in // the common successor, verify that the same value flows in from both // blocks. - SmallVector PHIs; - if (!PBI || PBI->isUnconditional() || - (BI->isConditional() && !SafeToMergeTerminators(BI, PBI)) || - (!BI->isConditional() && - !isProfitableToFoldUnconditional(BI, PBI, Cond, PHIs))) + if (!PBI || PBI->isUnconditional() || !SafeToMergeTerminators(BI, PBI)) continue; // Determine if the two branches share a common destination. - Instruction::BinaryOps Opc = Instruction::BinaryOpsEnd; - bool InvertPredCond = false; - - if (BI->isConditional()) { - if (PBI->getSuccessor(0) == TrueDest) { - Opc = Instruction::Or; - } else if (PBI->getSuccessor(1) == FalseDest) { - Opc = Instruction::And; - } else if (PBI->getSuccessor(0) == FalseDest) { - Opc = Instruction::And; - InvertPredCond = true; - } else if (PBI->getSuccessor(1) == TrueDest) { - Opc = Instruction::Or; - InvertPredCond = true; - } else { - continue; - } - } else { - if (PBI->getSuccessor(0) != TrueDest && PBI->getSuccessor(1) != TrueDest) - continue; - } - - LLVM_DEBUG(dbgs() << "FOLDING BRANCH TO COMMON DEST:\n" << *PBI << *BB); - Changed = true; - - IRBuilder<> Builder(PBI); - - // If we need to invert the condition in the pred block to match, do so now. - if (InvertPredCond) { - Value *NewCond = PBI->getCondition(); - - if (NewCond->hasOneUse() && isa(NewCond)) { - CmpInst *CI = cast(NewCond); - CI->setPredicate(CI->getInversePredicate()); - } else { - NewCond = - Builder.CreateNot(NewCond, PBI->getCondition()->getName() + ".not"); - } + Instruction::BinaryOps Opc; + bool InvertPredCond; + if (auto Recepie = CheckIfCondBranchesShareCommonDestination(BI, PBI)) + std::tie(Opc, InvertPredCond) = *Recepie; + else + continue; - PBI->setCondition(NewCond); - PBI->swapSuccessors(); - } + // Check the cost of inserting the necessary logic before performing the + // transformation. + if (TTI) { + Type *Ty = BI->getCondition()->getType(); + unsigned Cost = TTI->getArithmeticInstrCost(Opc, Ty, CostKind); + if (InvertPredCond && (!PBI->getCondition()->hasOneUse() || + !isa(PBI->getCondition()))) + Cost += TTI->getArithmeticInstrCost(Instruction::Xor, Ty, CostKind); - // If we have bonus instructions, clone them into the predecessor block. - // Note that there may be multiple predecessor blocks, so we cannot move - // bonus instructions to a predecessor block. - ValueToValueMapTy VMap; // maps original values to cloned values - // We already make sure Cond is the last instruction before BI. Therefore, - // all instructions before Cond other than DbgInfoIntrinsic are bonus - // instructions. - for (auto BonusInst = BB->begin(); Cond != &*BonusInst; ++BonusInst) { - if (isa(BonusInst)) + if (Cost > BranchFoldThreshold) continue; - Instruction *NewBonusInst = BonusInst->clone(); - - // When we fold the bonus instructions we want to make sure we - // reset their debug locations in order to avoid stepping on dead - // code caused by folding dead branches. - NewBonusInst->setDebugLoc(DebugLoc()); - - RemapInstruction(NewBonusInst, VMap, - RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); - VMap[&*BonusInst] = NewBonusInst; - - // If we moved a load, we cannot any longer claim any knowledge about - // its potential value. The previous information might have been valid - // only given the branch precondition. - // For an analogous reason, we must also drop all the metadata whose - // semantics we don't understand. - NewBonusInst->dropUnknownNonDebugMetadata(); - - PredBlock->getInstList().insert(PBI->getIterator(), NewBonusInst); - NewBonusInst->takeName(&*BonusInst); - BonusInst->setName(BonusInst->getName() + ".old"); } - // Clone Cond into the predecessor basic block, and or/and the - // two conditions together. - Instruction *CondInPred = Cond->clone(); - - // Reset the condition debug location to avoid jumping on dead code - // as the result of folding dead branches. - CondInPred->setDebugLoc(DebugLoc()); - - RemapInstruction(CondInPred, VMap, - RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); - PredBlock->getInstList().insert(PBI->getIterator(), CondInPred); - CondInPred->takeName(Cond); - Cond->setName(CondInPred->getName() + ".old"); - - if (BI->isConditional()) { - Instruction *NewCond = cast( - Builder.CreateBinOp(Opc, PBI->getCondition(), CondInPred, "or.cond")); - PBI->setCondition(NewCond); - - uint64_t PredTrueWeight, PredFalseWeight, SuccTrueWeight, SuccFalseWeight; - bool HasWeights = - extractPredSuccWeights(PBI, BI, PredTrueWeight, PredFalseWeight, - SuccTrueWeight, SuccFalseWeight); - SmallVector NewWeights; - - if (PBI->getSuccessor(0) == BB) { - if (HasWeights) { - // PBI: br i1 %x, BB, FalseDest - // BI: br i1 %y, TrueDest, FalseDest - // TrueWeight is TrueWeight for PBI * TrueWeight for BI. - NewWeights.push_back(PredTrueWeight * SuccTrueWeight); - // FalseWeight is FalseWeight for PBI * TotalWeight for BI + - // TrueWeight for PBI * FalseWeight for BI. - // We assume that total weights of a BranchInst can fit into 32 bits. - // Therefore, we will not have overflow using 64-bit arithmetic. - NewWeights.push_back(PredFalseWeight * - (SuccFalseWeight + SuccTrueWeight) + - PredTrueWeight * SuccFalseWeight); - } - AddPredecessorToBlock(TrueDest, PredBlock, BB, MSSAU); - PBI->setSuccessor(0, TrueDest); - } - if (PBI->getSuccessor(1) == BB) { - if (HasWeights) { - // PBI: br i1 %x, TrueDest, BB - // BI: br i1 %y, TrueDest, FalseDest - // TrueWeight is TrueWeight for PBI * TotalWeight for BI + - // FalseWeight for PBI * TrueWeight for BI. - NewWeights.push_back(PredTrueWeight * - (SuccFalseWeight + SuccTrueWeight) + - PredFalseWeight * SuccTrueWeight); - // FalseWeight is FalseWeight for PBI * FalseWeight for BI. - NewWeights.push_back(PredFalseWeight * SuccFalseWeight); - } - AddPredecessorToBlock(FalseDest, PredBlock, BB, MSSAU); - PBI->setSuccessor(1, FalseDest); - } - if (NewWeights.size() == 2) { - // Halve the weights if any of them cannot fit in an uint32_t - FitWeights(NewWeights); - - SmallVector MDWeights(NewWeights.begin(), - NewWeights.end()); - setBranchWeights(PBI, MDWeights[0], MDWeights[1]); - } else - PBI->setMetadata(LLVMContext::MD_prof, nullptr); - } else { - // Update PHI nodes in the common successors. - for (unsigned i = 0, e = PHIs.size(); i != e; ++i) { - ConstantInt *PBI_C = cast( - PHIs[i]->getIncomingValueForBlock(PBI->getParent())); - assert(PBI_C->getType()->isIntegerTy(1)); - Instruction *MergedCond = nullptr; - if (PBI->getSuccessor(0) == TrueDest) { - // Create (PBI_Cond and PBI_C) or (!PBI_Cond and BI_Value) - // PBI_C is true: PBI_Cond or (!PBI_Cond and BI_Value) - // is false: !PBI_Cond and BI_Value - Instruction *NotCond = cast( - Builder.CreateNot(PBI->getCondition(), "not.cond")); - MergedCond = cast( - Builder.CreateBinOp(Instruction::And, NotCond, CondInPred, - "and.cond")); - if (PBI_C->isOne()) - MergedCond = cast(Builder.CreateBinOp( - Instruction::Or, PBI->getCondition(), MergedCond, "or.cond")); - } else { - // Create (PBI_Cond and BI_Value) or (!PBI_Cond and PBI_C) - // PBI_C is true: (PBI_Cond and BI_Value) or (!PBI_Cond) - // is false: PBI_Cond and BI_Value - MergedCond = cast(Builder.CreateBinOp( - Instruction::And, PBI->getCondition(), CondInPred, "and.cond")); - if (PBI_C->isOne()) { - Instruction *NotCond = cast( - Builder.CreateNot(PBI->getCondition(), "not.cond")); - MergedCond = cast(Builder.CreateBinOp( - Instruction::Or, NotCond, MergedCond, "or.cond")); - } - } - // Update PHI Node. - PHIs[i]->setIncomingValueForBlock(PBI->getParent(), MergedCond); - } - - // PBI is changed to branch to TrueDest below. Remove itself from - // potential phis from all other successors. - if (MSSAU) - MSSAU->changeCondBranchToUnconditionalTo(PBI, TrueDest); - - // Change PBI from Conditional to Unconditional. - BranchInst *New_PBI = BranchInst::Create(TrueDest, PBI); - EraseTerminatorAndDCECond(PBI, MSSAU); - PBI = New_PBI; - } - - // If BI was a loop latch, it may have had associated loop metadata. - // We need to copy it to the new latch, that is, PBI. - if (MDNode *LoopMD = BI->getMetadata(LLVMContext::MD_loop)) - PBI->setMetadata(LLVMContext::MD_loop, LoopMD); - - // TODO: If BB is reachable from all paths through PredBlock, then we - // could replace PBI's branch probabilities with BI's. - - // Copy any debug value intrinsics into the end of PredBlock. - for (Instruction &I : *BB) { - if (isa(I)) { - Instruction *NewI = I.clone(); - RemapInstruction(NewI, VMap, - RF_NoModuleLevelChanges | RF_IgnoreMissingLocals); - NewI->insertBefore(PBI); - } - } - - return Changed; + return PerformBranchToCommonDestFolding(BI, PBI, DTU, MSSAU); } return Changed; } @@ -3015,12 +3133,10 @@ static Value *ensureValueAvailableInSuccessor(Value *V, BasicBlock *BB, return PHI; } -static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, - BasicBlock *QTB, BasicBlock *QFB, - BasicBlock *PostBB, Value *Address, - bool InvertPCond, bool InvertQCond, - const DataLayout &DL, - const TargetTransformInfo &TTI) { +static bool mergeConditionalStoreToAddress( + BasicBlock *PTB, BasicBlock *PFB, BasicBlock *QTB, BasicBlock *QFB, + BasicBlock *PostBB, Value *Address, bool InvertPCond, bool InvertQCond, + DomTreeUpdater *DTU, const DataLayout &DL, const TargetTransformInfo &TTI) { // For every pointer, there must be exactly two stores, one coming from // PTB or PFB, and the other from QTB or QFB. We don't support more than one // store (to any address) in PTB,PFB or QTB,QFB. @@ -3095,7 +3211,7 @@ static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, return true; }; - const SmallVector FreeStores = {PStore, QStore}; + const std::array FreeStores = {PStore, QStore}; if (!MergeCondStoresAggressively && (!IsWorthwhile(PTB, FreeStores) || !IsWorthwhile(PFB, FreeStores) || !IsWorthwhile(QTB, FreeStores) || !IsWorthwhile(QFB, FreeStores))) @@ -3109,8 +3225,8 @@ static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, // If QTB does not exist, then QFB's only predecessor has a conditional // branch to QFB and PostBB. BasicBlock *TruePred = QTB ? QTB : QFB->getSinglePredecessor(); - BasicBlock *NewBB = SplitBlockPredecessors(PostBB, { QFB, TruePred}, - "condstore.split"); + BasicBlock *NewBB = + SplitBlockPredecessors(PostBB, {QFB, TruePred}, "condstore.split", DTU); if (!NewBB) return false; PostBB = NewBB; @@ -3139,8 +3255,9 @@ static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, QPred = QB.CreateNot(QPred); Value *CombinedPred = QB.CreateOr(PPred, QPred); - auto *T = - SplitBlockAndInsertIfThen(CombinedPred, &*QB.GetInsertPoint(), false); + auto *T = SplitBlockAndInsertIfThen(CombinedPred, &*QB.GetInsertPoint(), + /*Unreachable=*/false, + /*BranchWeights=*/nullptr, DTU); QB.SetInsertPoint(T); StoreInst *SI = cast(QB.CreateStore(QPHI, Address)); AAMDNodes AAMD; @@ -3160,7 +3277,7 @@ static bool mergeConditionalStoreToAddress(BasicBlock *PTB, BasicBlock *PFB, } static bool mergeConditionalStores(BranchInst *PBI, BranchInst *QBI, - const DataLayout &DL, + DomTreeUpdater *DTU, const DataLayout &DL, const TargetTransformInfo &TTI) { // The intention here is to find diamonds or triangles (see below) where each // conditional block contains a store to the same address. Both of these @@ -3262,16 +3379,17 @@ static bool mergeConditionalStores(BranchInst *PBI, BranchInst *QBI, bool Changed = false; for (auto *Address : CommonAddresses) - Changed |= mergeConditionalStoreToAddress( - PTB, PFB, QTB, QFB, PostBB, Address, InvertPCond, InvertQCond, DL, TTI); + Changed |= + mergeConditionalStoreToAddress(PTB, PFB, QTB, QFB, PostBB, Address, + InvertPCond, InvertQCond, DTU, DL, TTI); return Changed; } - /// If the previous block ended with a widenable branch, determine if reusing /// the target block is profitable and legal. This will have the effect of /// "widening" PBI, but doesn't require us to reason about hosting safety. -static bool tryWidenCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI) { +static bool tryWidenCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, + DomTreeUpdater *DTU) { // TODO: This can be generalized in two important ways: // 1) We can allow phi nodes in IfFalseBB and simply reuse all the input // values from the PBI edge. @@ -3294,15 +3412,25 @@ static bool tryWidenCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI) { if (BI->getSuccessor(1) != IfFalseBB && // no inf looping BI->getSuccessor(1)->getTerminatingDeoptimizeCall() && // profitability NoSideEffects(*BI->getParent())) { - BI->getSuccessor(1)->removePredecessor(BI->getParent()); + auto *OldSuccessor = BI->getSuccessor(1); + OldSuccessor->removePredecessor(BI->getParent()); BI->setSuccessor(1, IfFalseBB); + if (DTU) + DTU->applyUpdates( + {{DominatorTree::Insert, BI->getParent(), IfFalseBB}, + {DominatorTree::Delete, BI->getParent(), OldSuccessor}}); return true; } if (BI->getSuccessor(0) != IfFalseBB && // no inf looping BI->getSuccessor(0)->getTerminatingDeoptimizeCall() && // profitability NoSideEffects(*BI->getParent())) { - BI->getSuccessor(0)->removePredecessor(BI->getParent()); + auto *OldSuccessor = BI->getSuccessor(0); + OldSuccessor->removePredecessor(BI->getParent()); BI->setSuccessor(0, IfFalseBB); + if (DTU) + DTU->applyUpdates( + {{DominatorTree::Insert, BI->getParent(), IfFalseBB}, + {DominatorTree::Delete, BI->getParent(), OldSuccessor}}); return true; } return false; @@ -3313,6 +3441,7 @@ static bool tryWidenCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI) { /// that PBI and BI are both conditional branches, and BI is in one of the /// successor blocks of PBI - PBI branches to BI. static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, + DomTreeUpdater *DTU, const DataLayout &DL, const TargetTransformInfo &TTI) { assert(PBI->isConditional() && BI->isConditional()); @@ -3366,7 +3495,7 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, // If the previous block ended with a widenable branch, determine if reusing // the target block is profitable and legal. This will have the effect of // "widening" PBI, but doesn't require us to reason about hosting safety. - if (tryWidenCondBranchToCondBranch(PBI, BI)) + if (tryWidenCondBranchToCondBranch(PBI, BI, DTU)) return true; if (auto *CE = dyn_cast(BI->getCondition())) @@ -3376,7 +3505,7 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, // If both branches are conditional and both contain stores to the same // address, remove the stores from the conditionals and create a conditional // merged store at the end. - if (MergeCondStores && mergeConditionalStores(PBI, BI, DL, TTI)) + if (MergeCondStores && mergeConditionalStores(PBI, BI, DTU, DL, TTI)) return true; // If this is a conditional branch in an empty block, and if any @@ -3419,6 +3548,7 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, // case, it would be unsafe to hoist the operation into a select instruction. BasicBlock *CommonDest = PBI->getSuccessor(PBIOp); + BasicBlock *RemovedDest = PBI->getSuccessor(PBIOp ^ 1); unsigned NumPhis = 0; for (BasicBlock::iterator II = CommonDest->begin(); isa(II); ++II, ++NumPhis) { @@ -3444,6 +3574,8 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, LLVM_DEBUG(dbgs() << "FOLDING BRs:" << *PBI->getParent() << "AND: " << *BI->getParent()); + SmallVector Updates; + // If OtherDest *is* BB, then BB is a basic block with a single conditional // branch in it, where one edge (OtherDest) goes back to itself but the other // exits. We don't *know* that the program avoids the infinite loop @@ -3457,6 +3589,7 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, BasicBlock *InfLoopBlock = BasicBlock::Create(BB->getContext(), "infloop", BB->getParent()); BranchInst::Create(InfLoopBlock, InfLoopBlock); + Updates.push_back({DominatorTree::Insert, InfLoopBlock, InfLoopBlock}); OtherDest = InfLoopBlock; } @@ -3483,6 +3616,12 @@ static bool SimplifyCondBranchToCondBranch(BranchInst *PBI, BranchInst *BI, PBI->setSuccessor(0, CommonDest); PBI->setSuccessor(1, OtherDest); + Updates.push_back({DominatorTree::Insert, PBI->getParent(), OtherDest}); + Updates.push_back({DominatorTree::Delete, PBI->getParent(), RemovedDest}); + + if (DTU) + DTU->applyUpdates(Updates); + // Update branch weight for PBI. uint64_t PredTrueWeight, PredFalseWeight, SuccTrueWeight, SuccFalseWeight; uint64_t PredCommon, PredOther, SuccCommon, SuccOther; @@ -3562,6 +3701,7 @@ bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, BasicBlock *FalseBB, uint32_t TrueWeight, uint32_t FalseWeight) { + auto *BB = OldTerm->getParent(); // Remove any superfluous successor edges from the CFG. // First, figure out which successors to preserve. // If TrueBB and FalseBB are equal, only try to preserve one copy of that @@ -3569,6 +3709,8 @@ bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, BasicBlock *KeepEdge1 = TrueBB; BasicBlock *KeepEdge2 = TrueBB != FalseBB ? FalseBB : nullptr; + SmallSetVector RemovedSuccessors; + // Then remove the rest. for (BasicBlock *Succ : successors(OldTerm)) { // Make sure only to keep exactly one copy of each edge. @@ -3576,9 +3718,13 @@ bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, KeepEdge1 = nullptr; else if (Succ == KeepEdge2) KeepEdge2 = nullptr; - else - Succ->removePredecessor(OldTerm->getParent(), + else { + Succ->removePredecessor(BB, /*KeepOneInputPHIs=*/true); + + if (Succ != TrueBB && Succ != FalseBB) + RemovedSuccessors.insert(Succ); + } } IRBuilder<> Builder(OldTerm); @@ -3586,11 +3732,11 @@ bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, // Insert an appropriate new terminator. if (!KeepEdge1 && !KeepEdge2) { - if (TrueBB == FalseBB) + if (TrueBB == FalseBB) { // We were only looking for one successor, and it was present. // Create an unconditional branch to it. Builder.CreateBr(TrueBB); - else { + } else { // We found both of the successors we were looking for. // Create a conditional branch sharing the condition of the select. BranchInst *NewBI = Builder.CreateCondBr(Cond, TrueBB, FalseBB); @@ -3605,15 +3751,25 @@ bool SimplifyCFGOpt::SimplifyTerminatorOnSelect(Instruction *OldTerm, // One of the selected values was a successor, but the other wasn't. // Insert an unconditional branch to the one that was found; // the edge to the one that wasn't must be unreachable. - if (!KeepEdge1) + if (!KeepEdge1) { // Only TrueBB was found. Builder.CreateBr(TrueBB); - else + } else { // Only FalseBB was found. Builder.CreateBr(FalseBB); + } } EraseTerminatorAndDCECond(OldTerm); + + if (DTU) { + SmallVector Updates; + Updates.reserve(RemovedSuccessors.size()); + for (auto *RemovedSuccessor : RemovedSuccessors) + Updates.push_back({DominatorTree::Delete, BB, RemovedSuccessor}); + DTU->applyUpdates(Updates); + } + return true; } @@ -3768,6 +3924,8 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt( ICI->replaceAllUsesWith(DefaultCst); ICI->eraseFromParent(); + SmallVector Updates; + // Okay, the switch goes to this block on a default value. Add an edge from // the switch to the merge point on the compared value. BasicBlock *NewBB = @@ -3781,13 +3939,17 @@ bool SimplifyCFGOpt::tryToSimplifyUncondBranchWithICmpInIt( SIW.setSuccessorWeight(0, *NewW); } SIW.addCase(Cst, NewBB, NewW); + Updates.push_back({DominatorTree::Insert, Pred, NewBB}); } // NewBB branches to the phi block, add the uncond branch and the phi entry. Builder.SetInsertPoint(NewBB); Builder.SetCurrentDebugLocation(SI->getDebugLoc()); Builder.CreateBr(SuccBlock); + Updates.push_back({DominatorTree::Insert, NewBB, SuccBlock}); PHIUse->addIncoming(NewCst, NewBB); + if (DTU) + DTU->applyUpdates(Updates); return true; } @@ -3821,7 +3983,7 @@ bool SimplifyCFGOpt::SimplifyBranchOnICmpChain(BranchInst *BI, if (UsedICmps <= 1) return false; - bool TrueWhenEqual = (Cond->getOpcode() == Instruction::Or); + bool TrueWhenEqual = match(Cond, m_LogicalOr(m_Value(), m_Value())); // There might be duplicate constants in the list, which the switch // instruction can't handle, remove them now. @@ -3853,12 +4015,15 @@ bool SimplifyCFGOpt::SimplifyBranchOnICmpChain(BranchInst *BI, << " cases into SWITCH. BB is:\n" << *BB); + SmallVector Updates; + // If there are any extra values that couldn't be folded into the switch // then we evaluate them with an explicit branch first. Split the block // right before the condbr to handle it. if (ExtraCase) { - BasicBlock *NewBB = - BB->splitBasicBlock(BI->getIterator(), "switch.early.test"); + BasicBlock *NewBB = SplitBlock(BB, BI, DTU, /*LI=*/nullptr, + /*MSSAU=*/nullptr, "switch.early.test"); + // Remove the uncond branch added to the old block. Instruction *OldTI = BB->getTerminator(); Builder.SetInsertPoint(OldTI); @@ -3870,6 +4035,8 @@ bool SimplifyCFGOpt::SimplifyBranchOnICmpChain(BranchInst *BI, OldTI->eraseFromParent(); + Updates.push_back({DominatorTree::Insert, BB, EdgeBB}); + // If there are PHI nodes in EdgeBB, then we need to add a new entry to them // for the edge we just added. AddPredecessorToBlock(EdgeBB, BB, NewBB); @@ -3905,6 +4072,8 @@ bool SimplifyCFGOpt::SimplifyBranchOnICmpChain(BranchInst *BI, // Erase the old branch instruction. EraseTerminatorAndDCECond(BI); + if (DTU) + DTU->applyUpdates(Updates); LLVM_DEBUG(dbgs() << " ** 'icmp' chain result is:\n" << *BB << '\n'); return true; @@ -3921,17 +4090,36 @@ bool SimplifyCFGOpt::simplifyResume(ResumeInst *RI, IRBuilder<> &Builder) { return false; } +// Check if cleanup block is empty +static bool isCleanupBlockEmpty(iterator_range R) { + for (Instruction &I : R) { + auto *II = dyn_cast(&I); + if (!II) + return false; + + Intrinsic::ID IntrinsicID = II->getIntrinsicID(); + switch (IntrinsicID) { + case Intrinsic::dbg_declare: + case Intrinsic::dbg_value: + case Intrinsic::dbg_label: + case Intrinsic::lifetime_end: + break; + default: + return false; + } + } + return true; +} + // Simplify resume that is shared by several landing pads (phi of landing pad). bool SimplifyCFGOpt::simplifyCommonResume(ResumeInst *RI) { BasicBlock *BB = RI->getParent(); - // Check that there are no other instructions except for debug intrinsics - // between the phi of landing pads (RI->getValue()) and resume instruction. - BasicBlock::iterator I = cast(RI->getValue())->getIterator(), - E = RI->getIterator(); - while (++I != E) - if (!isa(I)) - return false; + // Check that there are no other instructions except for debug and lifetime + // intrinsics between the phi's and resume instruction. + if (!isCleanupBlockEmpty( + make_range(RI->getParent()->getFirstNonPHI(), BB->getTerminator()))) + return false; SmallSetVector TrivialUnwindBlocks; auto *PhiLPInst = cast(RI->getValue()); @@ -3952,17 +4140,8 @@ bool SimplifyCFGOpt::simplifyCommonResume(ResumeInst *RI) { if (IncomingValue != LandingPad) continue; - bool isTrivial = true; - - I = IncomingBB->getFirstNonPHI()->getIterator(); - E = IncomingBB->getTerminator()->getIterator(); - while (++I != E) - if (!isa(I)) { - isTrivial = false; - break; - } - - if (isTrivial) + if (isCleanupBlockEmpty( + make_range(LandingPad->getNextNode(), IncomingBB->getTerminator()))) TrivialUnwindBlocks.insert(IncomingBB); } @@ -3981,7 +4160,8 @@ bool SimplifyCFGOpt::simplifyCommonResume(ResumeInst *RI) { for (pred_iterator PI = pred_begin(TrivialBB), PE = pred_end(TrivialBB); PI != PE;) { BasicBlock *Pred = *PI++; - removeUnwindEdge(Pred); + removeUnwindEdge(Pred, DTU); + ++NumInvokes; } // In each SimplifyCFG run, only the current processed block can be erased. @@ -3991,37 +4171,21 @@ bool SimplifyCFGOpt::simplifyCommonResume(ResumeInst *RI) { // predecessors. TrivialBB->getTerminator()->eraseFromParent(); new UnreachableInst(RI->getContext(), TrivialBB); + if (DTU) + DTU->applyUpdates({{DominatorTree::Delete, TrivialBB, BB}}); } // Delete the resume block if all its predecessors have been removed. - if (pred_empty(BB)) - BB->eraseFromParent(); + if (pred_empty(BB)) { + if (DTU) + DTU->deleteBB(BB); + else + BB->eraseFromParent(); + } return !TrivialUnwindBlocks.empty(); } -// Check if cleanup block is empty -static bool isCleanupBlockEmpty(Instruction *Inst, Instruction *RI) { - BasicBlock::iterator I = Inst->getIterator(), E = RI->getIterator(); - while (++I != E) { - auto *II = dyn_cast(I); - if (!II) - return false; - - Intrinsic::ID IntrinsicID = II->getIntrinsicID(); - switch (IntrinsicID) { - case Intrinsic::dbg_declare: - case Intrinsic::dbg_value: - case Intrinsic::dbg_label: - case Intrinsic::lifetime_end: - break; - default: - return false; - } - } - return true; -} - // Simplify resume that is only used by a single (non-phi) landing pad. bool SimplifyCFGOpt::simplifySingleResume(ResumeInst *RI) { BasicBlock *BB = RI->getParent(); @@ -4030,23 +4194,26 @@ bool SimplifyCFGOpt::simplifySingleResume(ResumeInst *RI) { "Resume must unwind the exception that caused control to here"); // Check that there are no other instructions except for debug intrinsics. - if (!isCleanupBlockEmpty(LPInst, RI)) + if (!isCleanupBlockEmpty( + make_range(LPInst->getNextNode(), RI))) return false; // Turn all invokes that unwind here into calls and delete the basic block. for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE;) { BasicBlock *Pred = *PI++; - removeUnwindEdge(Pred); + removeUnwindEdge(Pred, DTU); + ++NumInvokes; } // The landingpad is now unreachable. Zap it. - if (LoopHeaders) - LoopHeaders->erase(BB); - BB->eraseFromParent(); + if (DTU) + DTU->deleteBB(BB); + else + BB->eraseFromParent(); return true; } -static bool removeEmptyCleanup(CleanupReturnInst *RI) { +static bool removeEmptyCleanup(CleanupReturnInst *RI, DomTreeUpdater *DTU) { // If this is a trivial cleanup pad that executes no instructions, it can be // eliminated. If the cleanup pad continues to the caller, any predecessor // that is an EH pad will be updated to continue to the caller and any @@ -4067,7 +4234,8 @@ static bool removeEmptyCleanup(CleanupReturnInst *RI) { return false; // Check that there are no other instructions except for benign intrinsics. - if (!isCleanupBlockEmpty(CPInst, RI)) + if (!isCleanupBlockEmpty( + make_range(CPInst->getNextNode(), RI))) return false; // If the cleanup return we are simplifying unwinds to the caller, this will @@ -4152,19 +4320,32 @@ static bool removeEmptyCleanup(CleanupReturnInst *RI) { } } + std::vector Updates; + for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE;) { // The iterator must be updated here because we are removing this pred. BasicBlock *PredBB = *PI++; if (UnwindDest == nullptr) { - removeUnwindEdge(PredBB); + if (DTU) + DTU->applyUpdates(Updates); + Updates.clear(); + removeUnwindEdge(PredBB, DTU); + ++NumInvokes; } else { Instruction *TI = PredBB->getTerminator(); TI->replaceUsesOfWith(BB, UnwindDest); + Updates.push_back({DominatorTree::Insert, PredBB, UnwindDest}); + Updates.push_back({DominatorTree::Delete, PredBB, BB}); } } - // The cleanup pad is now unreachable. Zap it. - BB->eraseFromParent(); + if (DTU) { + DTU->applyUpdates(Updates); + DTU->deleteBB(BB); + } else + // The cleanup pad is now unreachable. Zap it. + BB->eraseFromParent(); + return true; } @@ -4211,7 +4392,7 @@ bool SimplifyCFGOpt::simplifyCleanupReturn(CleanupReturnInst *RI) { if (mergeCleanupPad(RI)) return true; - if (removeEmptyCleanup(RI)) + if (removeEmptyCleanup(RI, DTU)) return true; return false; @@ -4242,15 +4423,16 @@ bool SimplifyCFGOpt::simplifyReturn(ReturnInst *RI, IRBuilder<> &Builder) { BasicBlock *Pred = UncondBranchPreds.pop_back_val(); LLVM_DEBUG(dbgs() << "FOLDING: " << *BB << "INTO UNCOND BRANCH PRED: " << *Pred); - (void)FoldReturnIntoUncondBranch(RI, BB, Pred); + (void)FoldReturnIntoUncondBranch(RI, BB, Pred, DTU); } // If we eliminated all predecessors of the block, delete the block now. if (pred_empty(BB)) { // We know there are no successors, so just nuke the block. - if (LoopHeaders) - LoopHeaders->erase(BB); - BB->eraseFromParent(); + if (DTU) + DTU->deleteBB(BB); + else + BB->eraseFromParent(); } return true; @@ -4330,18 +4512,26 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { if (&BB->front() != UI) return Changed; - SmallVector Preds(pred_begin(BB), pred_end(BB)); + std::vector Updates; + + SmallSetVector Preds(pred_begin(BB), pred_end(BB)); for (unsigned i = 0, e = Preds.size(); i != e; ++i) { - Instruction *TI = Preds[i]->getTerminator(); + auto *Predecessor = Preds[i]; + Instruction *TI = Predecessor->getTerminator(); IRBuilder<> Builder(TI); if (auto *BI = dyn_cast(TI)) { - if (BI->isUnconditional()) { - assert(BI->getSuccessor(0) == BB && "Incorrect CFG"); + // We could either have a proper unconditional branch, + // or a degenerate conditional branch with matching destinations. + if (all_of(BI->successors(), + [BB](auto *Successor) { return Successor == BB; })) { new UnreachableInst(TI->getContext(), TI); TI->eraseFromParent(); Changed = true; } else { + assert(BI->isConditional() && "Can't get here with an uncond branch."); Value* Cond = BI->getCondition(); + assert(BI->getSuccessor(0) != BI->getSuccessor(1) && + "The destinations are guaranteed to be different here."); if (BI->getSuccessor(0) == BB) { Builder.CreateAssumption(Builder.CreateNot(Cond)); Builder.CreateBr(BI->getSuccessor(1)); @@ -4353,6 +4543,7 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { EraseTerminatorAndDCECond(BI); Changed = true; } + Updates.push_back({DominatorTree::Delete, Predecessor, BB}); } else if (auto *SI = dyn_cast(TI)) { SwitchInstProfUpdateWrapper SU(*SI); for (auto i = SU->case_begin(), e = SU->case_end(); i != e;) { @@ -4365,14 +4556,23 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { e = SU->case_end(); Changed = true; } + // Note that the default destination can't be removed! + if (SI->getDefaultDest() != BB) + Updates.push_back({DominatorTree::Delete, Predecessor, BB}); } else if (auto *II = dyn_cast(TI)) { if (II->getUnwindDest() == BB) { - removeUnwindEdge(TI->getParent()); + if (DTU) + DTU->applyUpdates(Updates); + Updates.clear(); + removeUnwindEdge(TI->getParent(), DTU); Changed = true; } } else if (auto *CSI = dyn_cast(TI)) { if (CSI->getUnwindDest() == BB) { - removeUnwindEdge(TI->getParent()); + if (DTU) + DTU->applyUpdates(Updates); + Updates.clear(); + removeUnwindEdge(TI->getParent(), DTU); Changed = true; continue; } @@ -4387,35 +4587,53 @@ bool SimplifyCFGOpt::simplifyUnreachable(UnreachableInst *UI) { Changed = true; } } + Updates.push_back({DominatorTree::Delete, Predecessor, BB}); if (CSI->getNumHandlers() == 0) { - BasicBlock *CatchSwitchBB = CSI->getParent(); if (CSI->hasUnwindDest()) { - // Redirect preds to the unwind dest - CatchSwitchBB->replaceAllUsesWith(CSI->getUnwindDest()); + // Redirect all predecessors of the block containing CatchSwitchInst + // to instead branch to the CatchSwitchInst's unwind destination. + for (auto *PredecessorOfPredecessor : predecessors(Predecessor)) { + Updates.push_back({DominatorTree::Insert, PredecessorOfPredecessor, + CSI->getUnwindDest()}); + Updates.push_back( + {DominatorTree::Delete, PredecessorOfPredecessor, Predecessor}); + } + Predecessor->replaceAllUsesWith(CSI->getUnwindDest()); } else { // Rewrite all preds to unwind to caller (or from invoke to call). - SmallVector EHPreds(predecessors(CatchSwitchBB)); + if (DTU) + DTU->applyUpdates(Updates); + Updates.clear(); + SmallVector EHPreds(predecessors(Predecessor)); for (BasicBlock *EHPred : EHPreds) - removeUnwindEdge(EHPred); + removeUnwindEdge(EHPred, DTU); } // The catchswitch is no longer reachable. new UnreachableInst(CSI->getContext(), CSI); CSI->eraseFromParent(); Changed = true; } - } else if (isa(TI)) { + } else if (auto *CRI = dyn_cast(TI)) { + (void)CRI; + assert(CRI->hasUnwindDest() && CRI->getUnwindDest() == BB && + "Expected to always have an unwind to BB."); + Updates.push_back({DominatorTree::Delete, Predecessor, BB}); new UnreachableInst(TI->getContext(), TI); TI->eraseFromParent(); Changed = true; } } + if (DTU) + DTU->applyUpdates(Updates); + // If this block is now dead, remove it. if (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()) { // We know there are no successors, so just nuke the block. - if (LoopHeaders) - LoopHeaders->erase(BB); - BB->eraseFromParent(); + if (DTU) + DTU->deleteBB(BB); + else + BB->eraseFromParent(); return true; } @@ -4433,15 +4651,26 @@ static bool CasesAreContiguous(SmallVectorImpl &Cases) { return true; } -static void createUnreachableSwitchDefault(SwitchInst *Switch) { +static void createUnreachableSwitchDefault(SwitchInst *Switch, + DomTreeUpdater *DTU) { LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n"); - BasicBlock *NewDefaultBlock = - SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), ""); + auto *BB = Switch->getParent(); + BasicBlock *NewDefaultBlock = SplitBlockPredecessors( + Switch->getDefaultDest(), Switch->getParent(), "", DTU); + auto *OrigDefaultBlock = Switch->getDefaultDest(); Switch->setDefaultDest(&*NewDefaultBlock); - SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front()); + if (DTU) + DTU->applyUpdates({{DominatorTree::Insert, BB, &*NewDefaultBlock}, + {DominatorTree::Delete, BB, OrigDefaultBlock}}); + SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front(), DTU); + SmallVector Updates; + for (auto *Successor : successors(NewDefaultBlock)) + Updates.push_back({DominatorTree::Delete, NewDefaultBlock, Successor}); auto *NewTerminator = NewDefaultBlock->getTerminator(); new UnreachableInst(Switch->getContext(), NewTerminator); EraseTerminatorAndDCECond(NewTerminator); + if (DTU) + DTU->applyUpdates(Updates); } /// Turn a switch with two reachable destinations into an integer range @@ -4453,6 +4682,8 @@ bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI, bool HasDefault = !isa(SI->getDefaultDest()->getFirstNonPHIOrDbg()); + auto *BB = SI->getParent(); + // Partition the cases into two sets with different destinations. BasicBlock *DestA = HasDefault ? SI->getDefaultDest() : nullptr; BasicBlock *DestB = nullptr; @@ -4556,17 +4787,23 @@ bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI, // Clean up the default block - it may have phis or other instructions before // the unreachable terminator. if (!HasDefault) - createUnreachableSwitchDefault(SI); + createUnreachableSwitchDefault(SI, DTU); + + auto *UnreachableDefault = SI->getDefaultDest(); // Drop the switch. SI->eraseFromParent(); + if (!HasDefault && DTU) + DTU->applyUpdates({{DominatorTree::Delete, BB, UnreachableDefault}}); + return true; } /// Compute masked bits for the condition of a switch /// and use it to remove dead cases. -static bool eliminateDeadSwitchCases(SwitchInst *SI, AssumptionCache *AC, +static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU, + AssumptionCache *AC, const DataLayout &DL) { Value *Cond = SI->getCondition(); unsigned Bits = Cond->getType()->getIntegerBitWidth(); @@ -4580,11 +4817,15 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, AssumptionCache *AC, // Gather dead cases. SmallVector DeadCases; + SmallMapVector NumPerSuccessorCases; for (auto &Case : SI->cases()) { + auto *Successor = Case.getCaseSuccessor(); + ++NumPerSuccessorCases[Successor]; const APInt &CaseVal = Case.getCaseValue()->getValue(); if (Known.Zero.intersects(CaseVal) || !Known.One.isSubsetOf(CaseVal) || (CaseVal.getMinSignedBits() > MaxSignificantBitsInCond)) { DeadCases.push_back(Case.getCaseValue()); + --NumPerSuccessorCases[Successor]; LLVM_DEBUG(dbgs() << "SimplifyCFG: switch case " << CaseVal << " is dead.\n"); } @@ -4602,7 +4843,7 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, AssumptionCache *AC, if (HasDefault && DeadCases.empty() && NumUnknownBits < 64 /* avoid overflow */ && SI->getNumCases() == (1ULL << NumUnknownBits)) { - createUnreachableSwitchDefault(SI); + createUnreachableSwitchDefault(SI, DTU); return true; } @@ -4619,6 +4860,13 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, AssumptionCache *AC, SIW.removeCase(CaseI); } + std::vector Updates; + for (const std::pair &I : NumPerSuccessorCases) + if (I.second == 0) + Updates.push_back({DominatorTree::Delete, SI->getParent(), I.first}); + if (DTU) + DTU->applyUpdates(Updates); + return true; } @@ -4974,30 +5222,41 @@ static Value *ConvertTwoCaseSwitch(const SwitchCaseResultVectorTy &ResultVector, // a select, fixing up PHI nodes and basic blocks. static void RemoveSwitchAfterSelectConversion(SwitchInst *SI, PHINode *PHI, Value *SelectValue, - IRBuilder<> &Builder) { + IRBuilder<> &Builder, + DomTreeUpdater *DTU) { + std::vector Updates; + BasicBlock *SelectBB = SI->getParent(); + BasicBlock *DestBB = PHI->getParent(); + + if (!is_contained(predecessors(DestBB), SelectBB)) + Updates.push_back({DominatorTree::Insert, SelectBB, DestBB}); + Builder.CreateBr(DestBB); + + // Remove the switch. + while (PHI->getBasicBlockIndex(SelectBB) >= 0) PHI->removeIncomingValue(SelectBB); PHI->addIncoming(SelectValue, SelectBB); - Builder.CreateBr(PHI->getParent()); - - // Remove the switch. for (unsigned i = 0, e = SI->getNumSuccessors(); i < e; ++i) { BasicBlock *Succ = SI->getSuccessor(i); - if (Succ == PHI->getParent()) + if (Succ == DestBB) continue; Succ->removePredecessor(SelectBB); + Updates.push_back({DominatorTree::Delete, SelectBB, Succ}); } SI->eraseFromParent(); + if (DTU) + DTU->applyUpdates(Updates); } /// If the switch is only used to initialize one or more /// phi nodes in a common successor block with only two different /// constant values, replace the switch with select. static bool switchToSelect(SwitchInst *SI, IRBuilder<> &Builder, - const DataLayout &DL, + DomTreeUpdater *DTU, const DataLayout &DL, const TargetTransformInfo &TTI) { Value *const Cond = SI->getCondition(); PHINode *PHI = nullptr; @@ -5017,7 +5276,7 @@ static bool switchToSelect(SwitchInst *SI, IRBuilder<> &Builder, Value *SelectValue = ConvertTwoCaseSwitch(UniqueResults, DefaultResult, Cond, Builder); if (SelectValue) { - RemoveSwitchAfterSelectConversion(SI, PHI, SelectValue, Builder); + RemoveSwitchAfterSelectConversion(SI, PHI, SelectValue, Builder, DTU); return true; } // The switch couldn't be converted into a select. @@ -5402,11 +5661,12 @@ static void reuseTableCompare( /// successor block with different constant values, replace the switch with /// lookup tables. static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, - const DataLayout &DL, + DomTreeUpdater *DTU, const DataLayout &DL, const TargetTransformInfo &TTI) { assert(SI->getNumCases() > 1 && "Degenerate switch?"); - Function *Fn = SI->getParent()->getParent(); + BasicBlock *BB = SI->getParent(); + Function *Fn = BB->getParent(); // Only build lookup table when we have a target that supports it or the // attribute is not set. if (!TTI.shouldBuildLookupTables() || @@ -5500,6 +5760,8 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, if (!ShouldBuildLookupTable(SI, TableSize, TTI, DL, ResultTypes)) return false; + std::vector Updates; + // Create the BB that does the lookups. Module &Mod = *CommonDest->getParent()->getParent(); BasicBlock *LookupBB = BasicBlock::Create( @@ -5532,6 +5794,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, if (!DefaultIsReachable || GeneratingCoveredLookupTable) { Builder.CreateBr(LookupBB); + Updates.push_back({DominatorTree::Insert, BB, LookupBB}); // Note: We call removeProdecessor later since we need to be able to get the // PHI value for the default case in case we're using a bit mask. } else { @@ -5539,6 +5802,7 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, TableIndex, ConstantInt::get(MinCaseVal->getType(), TableSize)); RangeCheckBranch = Builder.CreateCondBr(Cmp, LookupBB, SI->getDefaultDest()); + Updates.push_back({DominatorTree::Insert, BB, LookupBB}); } // Populate the BB that does the lookups. @@ -5576,16 +5840,18 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, Value *LoBit = Builder.CreateTrunc( Shifted, Type::getInt1Ty(Mod.getContext()), "switch.lobit"); Builder.CreateCondBr(LoBit, LookupBB, SI->getDefaultDest()); - + Updates.push_back({DominatorTree::Insert, MaskBB, LookupBB}); + Updates.push_back({DominatorTree::Insert, MaskBB, SI->getDefaultDest()}); Builder.SetInsertPoint(LookupBB); - AddPredecessorToBlock(SI->getDefaultDest(), MaskBB, SI->getParent()); + AddPredecessorToBlock(SI->getDefaultDest(), MaskBB, BB); } if (!DefaultIsReachable || GeneratingCoveredLookupTable) { // We cached PHINodes in PHIs. To avoid accessing deleted PHINodes later, // do not delete PHINodes here. - SI->getDefaultDest()->removePredecessor(SI->getParent(), + SI->getDefaultDest()->removePredecessor(BB, /*KeepOneInputPHIs=*/true); + Updates.push_back({DominatorTree::Delete, BB, SI->getDefaultDest()}); } bool ReturnedEarly = false; @@ -5622,19 +5888,29 @@ static bool SwitchToLookupTable(SwitchInst *SI, IRBuilder<> &Builder, PHI->addIncoming(Result, LookupBB); } - if (!ReturnedEarly) + if (!ReturnedEarly) { Builder.CreateBr(CommonDest); + Updates.push_back({DominatorTree::Insert, LookupBB, CommonDest}); + } // Remove the switch. + SmallSetVector RemovedSuccessors; for (unsigned i = 0, e = SI->getNumSuccessors(); i < e; ++i) { BasicBlock *Succ = SI->getSuccessor(i); if (Succ == SI->getDefaultDest()) continue; - Succ->removePredecessor(SI->getParent()); + Succ->removePredecessor(BB); + RemovedSuccessors.insert(Succ); } SI->eraseFromParent(); + if (DTU) { + for (BasicBlock *RemovedSuccessor : RemovedSuccessors) + Updates.push_back({DominatorTree::Delete, BB, RemovedSuccessor}); + DTU->applyUpdates(Updates); + } + ++NumLookupTables; if (NeedMask) ++NumLookupTablesHoles; @@ -5770,10 +6046,10 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) { return requestResimplify(); // Remove unreachable cases. - if (eliminateDeadSwitchCases(SI, Options.AC, DL)) + if (eliminateDeadSwitchCases(SI, DTU, Options.AC, DL)) return requestResimplify(); - if (switchToSelect(SI, Builder, DL, TTI)) + if (switchToSelect(SI, Builder, DTU, DL, TTI)) return requestResimplify(); if (Options.ForwardSwitchCondToPhi && ForwardSwitchConditionToPHI(SI)) @@ -5785,7 +6061,7 @@ bool SimplifyCFGOpt::simplifySwitch(SwitchInst *SI, IRBuilder<> &Builder) { // CVP. Therefore, only apply this transformation during late stages of the // optimisation pipeline. if (Options.ConvertSwitchToLookupTable && - SwitchToLookupTable(SI, Builder, DL, TTI)) + SwitchToLookupTable(SI, Builder, DTU, DL, TTI)) return requestResimplify(); if (ReduceSwitchRange(SI, Builder, DL, TTI)) @@ -5800,9 +6076,12 @@ bool SimplifyCFGOpt::simplifyIndirectBr(IndirectBrInst *IBI) { // Eliminate redundant destinations. SmallPtrSet Succs; + SmallSetVector RemovedSuccs; for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) { BasicBlock *Dest = IBI->getDestination(i); if (!Dest->hasAddressTaken() || !Succs.insert(Dest).second) { + if (!Dest->hasAddressTaken()) + RemovedSuccs.insert(Dest); Dest->removePredecessor(BB); IBI->removeDestination(i); --i; @@ -5811,6 +6090,14 @@ bool SimplifyCFGOpt::simplifyIndirectBr(IndirectBrInst *IBI) { } } + if (DTU) { + std::vector Updates; + Updates.reserve(RemovedSuccs.size()); + for (auto *RemovedSucc : RemovedSuccs) + Updates.push_back({DominatorTree::Delete, BB, RemovedSucc}); + DTU->applyUpdates(Updates); + } + if (IBI->getNumDestinations() == 0) { // If the indirectbr has no successors, change it to unreachable. new UnreachableInst(IBI->getContext(), IBI); @@ -5854,7 +6141,7 @@ bool SimplifyCFGOpt::simplifyIndirectBr(IndirectBrInst *IBI) { /// block when the inputs in the phi are the same for the two blocks being /// merged. In some cases, this could result in removal of the PHI entirely. static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, - BasicBlock *BB) { + BasicBlock *BB, DomTreeUpdater *DTU) { auto Succ = BB->getUniqueSuccessor(); assert(Succ); // If there's a phi in the successor block, we'd likely have to introduce @@ -5875,6 +6162,8 @@ static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, if (!BI2 || !BI2->isIdenticalTo(BI)) continue; + std::vector Updates; + // We've found an identical block. Update our predecessors to take that // path instead and make ourselves dead. SmallPtrSet Preds; @@ -5884,6 +6173,8 @@ static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, assert(II->getNormalDest() != BB && II->getUnwindDest() == BB && "unexpected successor"); II->setUnwindDest(OtherPred); + Updates.push_back({DominatorTree::Insert, Pred, OtherPred}); + Updates.push_back({DominatorTree::Delete, Pred, BB}); } // The debug info in OtherPred doesn't cover the merged control flow that @@ -5899,11 +6190,14 @@ static bool TryToMergeLandingPad(LandingPadInst *LPad, BranchInst *BI, Succs.insert(succ_begin(BB), succ_end(BB)); for (BasicBlock *Succ : Succs) { Succ->removePredecessor(BB); + Updates.push_back({DominatorTree::Delete, BB, Succ}); } IRBuilder<> Builder(BI); Builder.CreateUnreachable(); BI->eraseFromParent(); + if (DTU) + DTU->applyUpdates(Updates); return true; } return false; @@ -5928,11 +6222,11 @@ bool SimplifyCFGOpt::simplifyUncondBranch(BranchInst *BI, // backedge, so we can eliminate BB. bool NeedCanonicalLoop = Options.NeedCanonicalLoop && - (LoopHeaders && BB->hasNPredecessorsOrMore(2) && - (LoopHeaders->count(BB) || LoopHeaders->count(Succ))); + (!LoopHeaders.empty() && BB->hasNPredecessorsOrMore(2) && + (is_contained(LoopHeaders, BB) || is_contained(LoopHeaders, Succ))); BasicBlock::iterator I = BB->getFirstNonPHIOrDbg()->getIterator(); if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() && - !NeedCanonicalLoop && TryToSimplifyUncondBranchFromEmptyBlock(BB)) + !NeedCanonicalLoop && TryToSimplifyUncondBranchFromEmptyBlock(BB, DTU)) return true; // If the only instruction in the block is a seteq/setne comparison against a @@ -5951,7 +6245,7 @@ bool SimplifyCFGOpt::simplifyUncondBranch(BranchInst *BI, if (LandingPadInst *LPad = dyn_cast(I)) { for (++I; isa(I); ++I) ; - if (I->isTerminator() && TryToMergeLandingPad(LPad, BI, BB)) + if (I->isTerminator() && TryToMergeLandingPad(LPad, BI, BB, DTU)) return true; } @@ -5959,7 +6253,8 @@ bool SimplifyCFGOpt::simplifyUncondBranch(BranchInst *BI, // branches to us and our successor, fold the comparison into the // predecessor and use logical operations to update the incoming value // for PHI nodes in common successor. - if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold)) + if (FoldBranchToCommonDest(BI, DTU, /*MSSAU=*/nullptr, &TTI, + Options.BonusInstThreshold)) return requestResimplify(); return false; } @@ -6022,7 +6317,8 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { // If this basic block is ONLY a compare and a branch, and if a predecessor // branches to us and one of our successors, fold the comparison into the // predecessor and use logical operations to pick the right destination. - if (FoldBranchToCommonDest(BI, nullptr, Options.BonusInstThreshold)) + if (FoldBranchToCommonDest(BI, DTU, /*MSSAU=*/nullptr, &TTI, + Options.BonusInstThreshold)) return requestResimplify(); // We have a conditional branch to two blocks that are only reachable @@ -6031,8 +6327,9 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { // can hoist it up to the branching block. if (BI->getSuccessor(0)->getSinglePredecessor()) { if (BI->getSuccessor(1)->getSinglePredecessor()) { - if (HoistThenElseCodeToIf(BI, TTI)) - return requestResimplify(); + if (HoistCommon && Options.HoistCommonInsts) + if (HoistThenElseCodeToIf(BI, TTI)) + return requestResimplify(); } else { // If Successor #1 has multiple preds, we may be able to conditionally // execute Successor #0 if it branches to Successor #1. @@ -6056,14 +6353,14 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { // through this block if any PHI node entries are constants. if (PHINode *PN = dyn_cast(BI->getCondition())) if (PN->getParent() == BI->getParent()) - if (FoldCondBranchOnPHI(BI, DL, Options.AC)) + if (FoldCondBranchOnPHI(BI, DTU, DL, Options.AC)) return requestResimplify(); // Scan predecessor blocks for conditional branches. for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI) if (BranchInst *PBI = dyn_cast((*PI)->getTerminator())) if (PBI != BI && PBI->isConditional()) - if (SimplifyCondBranchToCondBranch(PBI, BI, DL, TTI)) + if (SimplifyCondBranchToCondBranch(PBI, BI, DTU, DL, TTI)) return requestResimplify(); // Look for diamond patterns. @@ -6071,14 +6368,14 @@ bool SimplifyCFGOpt::simplifyCondBranch(BranchInst *BI, IRBuilder<> &Builder) { if (BasicBlock *PrevBB = allPredecessorsComeFromSameSource(BB)) if (BranchInst *PBI = dyn_cast(PrevBB->getTerminator())) if (PBI != BI && PBI->isConditional()) - if (mergeConditionalStores(PBI, BI, DL, TTI)) + if (mergeConditionalStores(PBI, BI, DTU, DL, TTI)) return requestResimplify(); return false; } /// Check if passing a value to an instruction will cause undefined behavior. -static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I) { +static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValueMayBeModified) { Constant *C = dyn_cast(V); if (!C) return false; @@ -6101,12 +6398,15 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I) { // Look through GEPs. A load from a GEP derived from NULL is still undefined if (GetElementPtrInst *GEP = dyn_cast(Use)) - if (GEP->getPointerOperand() == I) - return passingValueIsAlwaysUndefined(V, GEP); + if (GEP->getPointerOperand() == I) { + if (!GEP->isInBounds() || !GEP->hasAllZeroIndices()) + PtrValueMayBeModified = true; + return passingValueIsAlwaysUndefined(V, GEP, PtrValueMayBeModified); + } // Look through bitcasts. if (BitCastInst *BC = dyn_cast(Use)) - return passingValueIsAlwaysUndefined(V, BC); + return passingValueIsAlwaysUndefined(V, BC, PtrValueMayBeModified); // Load from null is undefined. if (LoadInst *LI = dyn_cast(Use)) @@ -6121,24 +6421,51 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I) { SI->getPointerAddressSpace())) && SI->getPointerOperand() == I; - // A call to null is undefined. - if (auto *CB = dyn_cast(Use)) - return !NullPointerIsDefined(CB->getFunction()) && - CB->getCalledOperand() == I; + if (auto *CB = dyn_cast(Use)) { + if (C->isNullValue() && NullPointerIsDefined(CB->getFunction())) + return false; + // A call to null is undefined. + if (CB->getCalledOperand() == I) + return true; + + if (C->isNullValue()) { + for (const llvm::Use &Arg : CB->args()) + if (Arg == I) { + unsigned ArgIdx = CB->getArgOperandNo(&Arg); + if (CB->paramHasAttr(ArgIdx, Attribute::NonNull) && + CB->paramHasAttr(ArgIdx, Attribute::NoUndef)) { + // Passing null to a nonnnull+noundef argument is undefined. + return !PtrValueMayBeModified; + } + } + } else if (isa(C)) { + // Passing undef to a noundef argument is undefined. + for (const llvm::Use &Arg : CB->args()) + if (Arg == I) { + unsigned ArgIdx = CB->getArgOperandNo(&Arg); + if (CB->paramHasAttr(ArgIdx, Attribute::NoUndef)) { + // Passing undef to a noundef argument is undefined. + return true; + } + } + } + } } return false; } /// If BB has an incoming value that will always trigger undefined behavior /// (eg. null pointer dereference), remove the branch leading here. -static bool removeUndefIntroducingPredecessor(BasicBlock *BB) { +static bool removeUndefIntroducingPredecessor(BasicBlock *BB, + DomTreeUpdater *DTU) { for (PHINode &PHI : BB->phis()) for (unsigned i = 0, e = PHI.getNumIncomingValues(); i != e; ++i) if (passingValueIsAlwaysUndefined(PHI.getIncomingValue(i), &PHI)) { - Instruction *T = PHI.getIncomingBlock(i)->getTerminator(); + BasicBlock *Predecessor = PHI.getIncomingBlock(i); + Instruction *T = Predecessor->getTerminator(); IRBuilder<> Builder(T); if (BranchInst *BI = dyn_cast(T)) { - BB->removePredecessor(PHI.getIncomingBlock(i)); + BB->removePredecessor(Predecessor); // Turn uncoditional branches into unreachables and remove the dead // destination from conditional branches. if (BI->isUnconditional()) @@ -6147,6 +6474,8 @@ static bool removeUndefIntroducingPredecessor(BasicBlock *BB) { Builder.CreateBr(BI->getSuccessor(0) == BB ? BI->getSuccessor(1) : BI->getSuccessor(0)); BI->eraseFromParent(); + if (DTU) + DTU->applyUpdates({{DominatorTree::Delete, Predecessor, BB}}); return true; } // TODO: SwitchInst. @@ -6155,7 +6484,7 @@ static bool removeUndefIntroducingPredecessor(BasicBlock *BB) { return false; } -bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { +bool SimplifyCFGOpt::simplifyOnceImpl(BasicBlock *BB) { bool Changed = false; assert(BB && BB->getParent() && "Block not embedded in function!"); @@ -6166,28 +6495,29 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { if ((pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()) || BB->getSinglePredecessor() == BB) { LLVM_DEBUG(dbgs() << "Removing BB: \n" << *BB); - DeleteDeadBlock(BB); + DeleteDeadBlock(BB, DTU); return true; } // Check to see if we can constant propagate this terminator instruction // away... - Changed |= ConstantFoldTerminator(BB, true); + Changed |= ConstantFoldTerminator(BB, /*DeleteDeadConditions=*/true, + /*TLI=*/nullptr, DTU); // Check for and eliminate duplicate PHI nodes in this block. Changed |= EliminateDuplicatePHINodes(BB); // Check for and remove branches that will always cause undefined behavior. - Changed |= removeUndefIntroducingPredecessor(BB); + Changed |= removeUndefIntroducingPredecessor(BB, DTU); // Merge basic blocks into their predecessor if there is only one distinct // pred, and if there is only one distinct successor of the predecessor, and // if there are no PHI nodes. - if (MergeBlockIntoPredecessor(BB)) + if (MergeBlockIntoPredecessor(BB, DTU)) return true; if (SinkCommon && Options.SinkCommonInsts) - Changed |= SinkCommonCodeFromPredecessors(BB); + Changed |= SinkCommonCodeFromPredecessors(BB, DTU); IRBuilder<> Builder(BB); @@ -6196,7 +6526,7 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { // eliminate it, do so now. if (auto *PN = dyn_cast(BB->begin())) if (PN->getNumIncomingValues() == 2) - Changed |= FoldTwoEntryPHINode(PN, TTI, DL); + Changed |= FoldTwoEntryPHINode(PN, TTI, DTU, DL); } Instruction *Terminator = BB->getTerminator(); @@ -6228,7 +6558,23 @@ bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { return Changed; } +bool SimplifyCFGOpt::simplifyOnce(BasicBlock *BB) { + bool Changed = simplifyOnceImpl(BB); + + assert((!RequireAndPreserveDomTree || + (DTU && + DTU->getDomTree().verify(DominatorTree::VerificationLevel::Full))) && + "Failed to maintain validity of domtree!"); + + return Changed; +} + bool SimplifyCFGOpt::run(BasicBlock *BB) { + assert((!RequireAndPreserveDomTree || + (DTU && + DTU->getDomTree().verify(DominatorTree::VerificationLevel::Full))) && + "Original domtree is invalid?"); + bool Changed = false; // Repeated simplify BB as long as resimplification is requested. @@ -6244,9 +6590,9 @@ bool SimplifyCFGOpt::run(BasicBlock *BB) { } bool llvm::simplifyCFG(BasicBlock *BB, const TargetTransformInfo &TTI, - const SimplifyCFGOptions &Options, - SmallPtrSetImpl *LoopHeaders) { - return SimplifyCFGOpt(TTI, BB->getModule()->getDataLayout(), LoopHeaders, - Options) + DomTreeUpdater *DTU, const SimplifyCFGOptions &Options, + ArrayRef LoopHeaders) { + return SimplifyCFGOpt(TTI, RequireAndPreserveDomTree ? DTU : nullptr, + BB->getModule()->getDataLayout(), LoopHeaders, Options) .run(BB); } diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp index d3d0c3341908..290c04a7ad10 100644 --- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -191,15 +191,15 @@ bool SimplifyIndvar::makeIVComparisonInvariant(ICmpInst *ICmp, const SCEV *S = SE->getSCEVAtScope(ICmp->getOperand(IVOperIdx), ICmpLoop); const SCEV *X = SE->getSCEVAtScope(ICmp->getOperand(1 - IVOperIdx), ICmpLoop); - ICmpInst::Predicate InvariantPredicate; - const SCEV *InvariantLHS, *InvariantRHS; - auto *PN = dyn_cast(IVOperand); if (!PN) return false; - if (!SE->isLoopInvariantPredicate(Pred, S, X, L, InvariantPredicate, - InvariantLHS, InvariantRHS)) + auto LIP = SE->getLoopInvariantPredicate(Pred, S, X, L); + if (!LIP) return false; + ICmpInst::Predicate InvariantPredicate = LIP->Pred; + const SCEV *InvariantLHS = LIP->LHS; + const SCEV *InvariantRHS = LIP->RHS; // Rewrite the comparison to a loop invariant comparison if it can be done // cheaply, where cheaply means "we don't need to emit any new @@ -477,6 +477,7 @@ bool SimplifyIndvar::eliminateOverflowIntrinsic(WithOverflowInst *WO) { if (WO->use_empty()) WO->eraseFromParent(); + Changed = true; return true; } @@ -967,3 +968,1122 @@ bool simplifyLoopIVs(Loop *L, ScalarEvolution *SE, DominatorTree *DT, } } // namespace llvm + +//===----------------------------------------------------------------------===// +// Widen Induction Variables - Extend the width of an IV to cover its +// widest uses. +//===----------------------------------------------------------------------===// + +class WidenIV { + // Parameters + PHINode *OrigPhi; + Type *WideType; + + // Context + LoopInfo *LI; + Loop *L; + ScalarEvolution *SE; + DominatorTree *DT; + + // Does the module have any calls to the llvm.experimental.guard intrinsic + // at all? If not we can avoid scanning instructions looking for guards. + bool HasGuards; + + bool UsePostIncrementRanges; + + // Statistics + unsigned NumElimExt = 0; + unsigned NumWidened = 0; + + // Result + PHINode *WidePhi = nullptr; + Instruction *WideInc = nullptr; + const SCEV *WideIncExpr = nullptr; + SmallVectorImpl &DeadInsts; + + SmallPtrSet Widened; + + enum ExtendKind { ZeroExtended, SignExtended, Unknown }; + + // A map tracking the kind of extension used to widen each narrow IV + // and narrow IV user. + // Key: pointer to a narrow IV or IV user. + // Value: the kind of extension used to widen this Instruction. + DenseMap, ExtendKind> ExtendKindMap; + + using DefUserPair = std::pair, AssertingVH>; + + // A map with control-dependent ranges for post increment IV uses. The key is + // a pair of IV def and a use of this def denoting the context. The value is + // a ConstantRange representing possible values of the def at the given + // context. + DenseMap PostIncRangeInfos; + + Optional getPostIncRangeInfo(Value *Def, + Instruction *UseI) { + DefUserPair Key(Def, UseI); + auto It = PostIncRangeInfos.find(Key); + return It == PostIncRangeInfos.end() + ? Optional(None) + : Optional(It->second); + } + + void calculatePostIncRanges(PHINode *OrigPhi); + void calculatePostIncRange(Instruction *NarrowDef, Instruction *NarrowUser); + + void updatePostIncRangeInfo(Value *Def, Instruction *UseI, ConstantRange R) { + DefUserPair Key(Def, UseI); + auto It = PostIncRangeInfos.find(Key); + if (It == PostIncRangeInfos.end()) + PostIncRangeInfos.insert({Key, R}); + else + It->second = R.intersectWith(It->second); + } + +public: + /// Record a link in the Narrow IV def-use chain along with the WideIV that + /// computes the same value as the Narrow IV def. This avoids caching Use* + /// pointers. + struct NarrowIVDefUse { + Instruction *NarrowDef = nullptr; + Instruction *NarrowUse = nullptr; + Instruction *WideDef = nullptr; + + // True if the narrow def is never negative. Tracking this information lets + // us use a sign extension instead of a zero extension or vice versa, when + // profitable and legal. + bool NeverNegative = false; + + NarrowIVDefUse(Instruction *ND, Instruction *NU, Instruction *WD, + bool NeverNegative) + : NarrowDef(ND), NarrowUse(NU), WideDef(WD), + NeverNegative(NeverNegative) {} + }; + + WidenIV(const WideIVInfo &WI, LoopInfo *LInfo, ScalarEvolution *SEv, + DominatorTree *DTree, SmallVectorImpl &DI, + bool HasGuards, bool UsePostIncrementRanges = true); + + PHINode *createWideIV(SCEVExpander &Rewriter); + + unsigned getNumElimExt() { return NumElimExt; }; + unsigned getNumWidened() { return NumWidened; }; + +protected: + Value *createExtendInst(Value *NarrowOper, Type *WideType, bool IsSigned, + Instruction *Use); + + Instruction *cloneIVUser(NarrowIVDefUse DU, const SCEVAddRecExpr *WideAR); + Instruction *cloneArithmeticIVUser(NarrowIVDefUse DU, + const SCEVAddRecExpr *WideAR); + Instruction *cloneBitwiseIVUser(NarrowIVDefUse DU); + + ExtendKind getExtendKind(Instruction *I); + + using WidenedRecTy = std::pair; + + WidenedRecTy getWideRecurrence(NarrowIVDefUse DU); + + WidenedRecTy getExtendedOperandRecurrence(NarrowIVDefUse DU); + + const SCEV *getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS, + unsigned OpCode) const; + + Instruction *widenIVUse(NarrowIVDefUse DU, SCEVExpander &Rewriter); + + bool widenLoopCompare(NarrowIVDefUse DU); + bool widenWithVariantUse(NarrowIVDefUse DU); + + void pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef); + +private: + SmallVector NarrowIVUsers; +}; + + +/// Determine the insertion point for this user. By default, insert immediately +/// before the user. SCEVExpander or LICM will hoist loop invariants out of the +/// loop. For PHI nodes, there may be multiple uses, so compute the nearest +/// common dominator for the incoming blocks. A nullptr can be returned if no +/// viable location is found: it may happen if User is a PHI and Def only comes +/// to this PHI from unreachable blocks. +static Instruction *getInsertPointForUses(Instruction *User, Value *Def, + DominatorTree *DT, LoopInfo *LI) { + PHINode *PHI = dyn_cast(User); + if (!PHI) + return User; + + Instruction *InsertPt = nullptr; + for (unsigned i = 0, e = PHI->getNumIncomingValues(); i != e; ++i) { + if (PHI->getIncomingValue(i) != Def) + continue; + + BasicBlock *InsertBB = PHI->getIncomingBlock(i); + + if (!DT->isReachableFromEntry(InsertBB)) + continue; + + if (!InsertPt) { + InsertPt = InsertBB->getTerminator(); + continue; + } + InsertBB = DT->findNearestCommonDominator(InsertPt->getParent(), InsertBB); + InsertPt = InsertBB->getTerminator(); + } + + // If we have skipped all inputs, it means that Def only comes to Phi from + // unreachable blocks. + if (!InsertPt) + return nullptr; + + auto *DefI = dyn_cast(Def); + if (!DefI) + return InsertPt; + + assert(DT->dominates(DefI, InsertPt) && "def does not dominate all uses"); + + auto *L = LI->getLoopFor(DefI->getParent()); + assert(!L || L->contains(LI->getLoopFor(InsertPt->getParent()))); + + for (auto *DTN = (*DT)[InsertPt->getParent()]; DTN; DTN = DTN->getIDom()) + if (LI->getLoopFor(DTN->getBlock()) == L) + return DTN->getBlock()->getTerminator(); + + llvm_unreachable("DefI dominates InsertPt!"); +} + +WidenIV::WidenIV(const WideIVInfo &WI, LoopInfo *LInfo, ScalarEvolution *SEv, + DominatorTree *DTree, SmallVectorImpl &DI, + bool HasGuards, bool UsePostIncrementRanges) + : OrigPhi(WI.NarrowIV), WideType(WI.WidestNativeType), LI(LInfo), + L(LI->getLoopFor(OrigPhi->getParent())), SE(SEv), DT(DTree), + HasGuards(HasGuards), UsePostIncrementRanges(UsePostIncrementRanges), + DeadInsts(DI) { + assert(L->getHeader() == OrigPhi->getParent() && "Phi must be an IV"); + ExtendKindMap[OrigPhi] = WI.IsSigned ? SignExtended : ZeroExtended; +} + +Value *WidenIV::createExtendInst(Value *NarrowOper, Type *WideType, + bool IsSigned, Instruction *Use) { + // Set the debug location and conservative insertion point. + IRBuilder<> Builder(Use); + // Hoist the insertion point into loop preheaders as far as possible. + for (const Loop *L = LI->getLoopFor(Use->getParent()); + L && L->getLoopPreheader() && L->isLoopInvariant(NarrowOper); + L = L->getParentLoop()) + Builder.SetInsertPoint(L->getLoopPreheader()->getTerminator()); + + return IsSigned ? Builder.CreateSExt(NarrowOper, WideType) : + Builder.CreateZExt(NarrowOper, WideType); +} + +/// Instantiate a wide operation to replace a narrow operation. This only needs +/// to handle operations that can evaluation to SCEVAddRec. It can safely return +/// 0 for any operation we decide not to clone. +Instruction *WidenIV::cloneIVUser(WidenIV::NarrowIVDefUse DU, + const SCEVAddRecExpr *WideAR) { + unsigned Opcode = DU.NarrowUse->getOpcode(); + switch (Opcode) { + default: + return nullptr; + case Instruction::Add: + case Instruction::Mul: + case Instruction::UDiv: + case Instruction::Sub: + return cloneArithmeticIVUser(DU, WideAR); + + case Instruction::And: + case Instruction::Or: + case Instruction::Xor: + case Instruction::Shl: + case Instruction::LShr: + case Instruction::AShr: + return cloneBitwiseIVUser(DU); + } +} + +Instruction *WidenIV::cloneBitwiseIVUser(WidenIV::NarrowIVDefUse DU) { + Instruction *NarrowUse = DU.NarrowUse; + Instruction *NarrowDef = DU.NarrowDef; + Instruction *WideDef = DU.WideDef; + + LLVM_DEBUG(dbgs() << "Cloning bitwise IVUser: " << *NarrowUse << "\n"); + + // Replace NarrowDef operands with WideDef. Otherwise, we don't know anything + // about the narrow operand yet so must insert a [sz]ext. It is probably loop + // invariant and will be folded or hoisted. If it actually comes from a + // widened IV, it should be removed during a future call to widenIVUse. + bool IsSigned = getExtendKind(NarrowDef) == SignExtended; + Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(0), WideType, + IsSigned, NarrowUse); + Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(1), WideType, + IsSigned, NarrowUse); + + auto *NarrowBO = cast(NarrowUse); + auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, + NarrowBO->getName()); + IRBuilder<> Builder(NarrowUse); + Builder.Insert(WideBO); + WideBO->copyIRFlags(NarrowBO); + return WideBO; +} + +Instruction *WidenIV::cloneArithmeticIVUser(WidenIV::NarrowIVDefUse DU, + const SCEVAddRecExpr *WideAR) { + Instruction *NarrowUse = DU.NarrowUse; + Instruction *NarrowDef = DU.NarrowDef; + Instruction *WideDef = DU.WideDef; + + LLVM_DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *NarrowUse << "\n"); + + unsigned IVOpIdx = (NarrowUse->getOperand(0) == NarrowDef) ? 0 : 1; + + // We're trying to find X such that + // + // Widen(NarrowDef `op` NonIVNarrowDef) == WideAR == WideDef `op.wide` X + // + // We guess two solutions to X, sext(NonIVNarrowDef) and zext(NonIVNarrowDef), + // and check using SCEV if any of them are correct. + + // Returns true if extending NonIVNarrowDef according to `SignExt` is a + // correct solution to X. + auto GuessNonIVOperand = [&](bool SignExt) { + const SCEV *WideLHS; + const SCEV *WideRHS; + + auto GetExtend = [this, SignExt](const SCEV *S, Type *Ty) { + if (SignExt) + return SE->getSignExtendExpr(S, Ty); + return SE->getZeroExtendExpr(S, Ty); + }; + + if (IVOpIdx == 0) { + WideLHS = SE->getSCEV(WideDef); + const SCEV *NarrowRHS = SE->getSCEV(NarrowUse->getOperand(1)); + WideRHS = GetExtend(NarrowRHS, WideType); + } else { + const SCEV *NarrowLHS = SE->getSCEV(NarrowUse->getOperand(0)); + WideLHS = GetExtend(NarrowLHS, WideType); + WideRHS = SE->getSCEV(WideDef); + } + + // WideUse is "WideDef `op.wide` X" as described in the comment. + const SCEV *WideUse = + getSCEVByOpCode(WideLHS, WideRHS, NarrowUse->getOpcode()); + + return WideUse == WideAR; + }; + + bool SignExtend = getExtendKind(NarrowDef) == SignExtended; + if (!GuessNonIVOperand(SignExtend)) { + SignExtend = !SignExtend; + if (!GuessNonIVOperand(SignExtend)) + return nullptr; + } + + Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(0), WideType, + SignExtend, NarrowUse); + Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(1), WideType, + SignExtend, NarrowUse); + + auto *NarrowBO = cast(NarrowUse); + auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, + NarrowBO->getName()); + + IRBuilder<> Builder(NarrowUse); + Builder.Insert(WideBO); + WideBO->copyIRFlags(NarrowBO); + return WideBO; +} + +WidenIV::ExtendKind WidenIV::getExtendKind(Instruction *I) { + auto It = ExtendKindMap.find(I); + assert(It != ExtendKindMap.end() && "Instruction not yet extended!"); + return It->second; +} + +const SCEV *WidenIV::getSCEVByOpCode(const SCEV *LHS, const SCEV *RHS, + unsigned OpCode) const { + switch (OpCode) { + case Instruction::Add: + return SE->getAddExpr(LHS, RHS); + case Instruction::Sub: + return SE->getMinusSCEV(LHS, RHS); + case Instruction::Mul: + return SE->getMulExpr(LHS, RHS); + case Instruction::UDiv: + return SE->getUDivExpr(LHS, RHS); + default: + llvm_unreachable("Unsupported opcode."); + }; +} + +/// No-wrap operations can transfer sign extension of their result to their +/// operands. Generate the SCEV value for the widened operation without +/// actually modifying the IR yet. If the expression after extending the +/// operands is an AddRec for this loop, return the AddRec and the kind of +/// extension used. +WidenIV::WidenedRecTy +WidenIV::getExtendedOperandRecurrence(WidenIV::NarrowIVDefUse DU) { + // Handle the common case of add + const unsigned OpCode = DU.NarrowUse->getOpcode(); + // Only Add/Sub/Mul instructions supported yet. + if (OpCode != Instruction::Add && OpCode != Instruction::Sub && + OpCode != Instruction::Mul) + return {nullptr, Unknown}; + + // One operand (NarrowDef) has already been extended to WideDef. Now determine + // if extending the other will lead to a recurrence. + const unsigned ExtendOperIdx = + DU.NarrowUse->getOperand(0) == DU.NarrowDef ? 1 : 0; + assert(DU.NarrowUse->getOperand(1-ExtendOperIdx) == DU.NarrowDef && "bad DU"); + + const SCEV *ExtendOperExpr = nullptr; + const OverflowingBinaryOperator *OBO = + cast(DU.NarrowUse); + ExtendKind ExtKind = getExtendKind(DU.NarrowDef); + if (ExtKind == SignExtended && OBO->hasNoSignedWrap()) + ExtendOperExpr = SE->getSignExtendExpr( + SE->getSCEV(DU.NarrowUse->getOperand(ExtendOperIdx)), WideType); + else if(ExtKind == ZeroExtended && OBO->hasNoUnsignedWrap()) + ExtendOperExpr = SE->getZeroExtendExpr( + SE->getSCEV(DU.NarrowUse->getOperand(ExtendOperIdx)), WideType); + else + return {nullptr, Unknown}; + + // When creating this SCEV expr, don't apply the current operations NSW or NUW + // flags. This instruction may be guarded by control flow that the no-wrap + // behavior depends on. Non-control-equivalent instructions can be mapped to + // the same SCEV expression, and it would be incorrect to transfer NSW/NUW + // semantics to those operations. + const SCEV *lhs = SE->getSCEV(DU.WideDef); + const SCEV *rhs = ExtendOperExpr; + + // Let's swap operands to the initial order for the case of non-commutative + // operations, like SUB. See PR21014. + if (ExtendOperIdx == 0) + std::swap(lhs, rhs); + const SCEVAddRecExpr *AddRec = + dyn_cast(getSCEVByOpCode(lhs, rhs, OpCode)); + + if (!AddRec || AddRec->getLoop() != L) + return {nullptr, Unknown}; + + return {AddRec, ExtKind}; +} + +/// Is this instruction potentially interesting for further simplification after +/// widening it's type? In other words, can the extend be safely hoisted out of +/// the loop with SCEV reducing the value to a recurrence on the same loop. If +/// so, return the extended recurrence and the kind of extension used. Otherwise +/// return {nullptr, Unknown}. +WidenIV::WidenedRecTy WidenIV::getWideRecurrence(WidenIV::NarrowIVDefUse DU) { + if (!SE->isSCEVable(DU.NarrowUse->getType())) + return {nullptr, Unknown}; + + const SCEV *NarrowExpr = SE->getSCEV(DU.NarrowUse); + if (SE->getTypeSizeInBits(NarrowExpr->getType()) >= + SE->getTypeSizeInBits(WideType)) { + // NarrowUse implicitly widens its operand. e.g. a gep with a narrow + // index. So don't follow this use. + return {nullptr, Unknown}; + } + + const SCEV *WideExpr; + ExtendKind ExtKind; + if (DU.NeverNegative) { + WideExpr = SE->getSignExtendExpr(NarrowExpr, WideType); + if (isa(WideExpr)) + ExtKind = SignExtended; + else { + WideExpr = SE->getZeroExtendExpr(NarrowExpr, WideType); + ExtKind = ZeroExtended; + } + } else if (getExtendKind(DU.NarrowDef) == SignExtended) { + WideExpr = SE->getSignExtendExpr(NarrowExpr, WideType); + ExtKind = SignExtended; + } else { + WideExpr = SE->getZeroExtendExpr(NarrowExpr, WideType); + ExtKind = ZeroExtended; + } + const SCEVAddRecExpr *AddRec = dyn_cast(WideExpr); + if (!AddRec || AddRec->getLoop() != L) + return {nullptr, Unknown}; + return {AddRec, ExtKind}; +} + +/// This IV user cannot be widened. Replace this use of the original narrow IV +/// with a truncation of the new wide IV to isolate and eliminate the narrow IV. +static void truncateIVUse(WidenIV::NarrowIVDefUse DU, DominatorTree *DT, + LoopInfo *LI) { + auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI); + if (!InsertPt) + return; + LLVM_DEBUG(dbgs() << "INDVARS: Truncate IV " << *DU.WideDef << " for user " + << *DU.NarrowUse << "\n"); + IRBuilder<> Builder(InsertPt); + Value *Trunc = Builder.CreateTrunc(DU.WideDef, DU.NarrowDef->getType()); + DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, Trunc); +} + +/// If the narrow use is a compare instruction, then widen the compare +// (and possibly the other operand). The extend operation is hoisted into the +// loop preheader as far as possible. +bool WidenIV::widenLoopCompare(WidenIV::NarrowIVDefUse DU) { + ICmpInst *Cmp = dyn_cast(DU.NarrowUse); + if (!Cmp) + return false; + + // We can legally widen the comparison in the following two cases: + // + // - The signedness of the IV extension and comparison match + // + // - The narrow IV is always positive (and thus its sign extension is equal + // to its zero extension). For instance, let's say we're zero extending + // %narrow for the following use + // + // icmp slt i32 %narrow, %val ... (A) + // + // and %narrow is always positive. Then + // + // (A) == icmp slt i32 sext(%narrow), sext(%val) + // == icmp slt i32 zext(%narrow), sext(%val) + bool IsSigned = getExtendKind(DU.NarrowDef) == SignExtended; + if (!(DU.NeverNegative || IsSigned == Cmp->isSigned())) + return false; + + Value *Op = Cmp->getOperand(Cmp->getOperand(0) == DU.NarrowDef ? 1 : 0); + unsigned CastWidth = SE->getTypeSizeInBits(Op->getType()); + unsigned IVWidth = SE->getTypeSizeInBits(WideType); + assert(CastWidth <= IVWidth && "Unexpected width while widening compare."); + + // Widen the compare instruction. + auto *InsertPt = getInsertPointForUses(DU.NarrowUse, DU.NarrowDef, DT, LI); + if (!InsertPt) + return false; + IRBuilder<> Builder(InsertPt); + DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef); + + // Widen the other operand of the compare, if necessary. + if (CastWidth < IVWidth) { + Value *ExtOp = createExtendInst(Op, WideType, Cmp->isSigned(), Cmp); + DU.NarrowUse->replaceUsesOfWith(Op, ExtOp); + } + return true; +} + +// The widenIVUse avoids generating trunc by evaluating the use as AddRec, this +// will not work when: +// 1) SCEV traces back to an instruction inside the loop that SCEV can not +// expand, eg. add %indvar, (load %addr) +// 2) SCEV finds a loop variant, eg. add %indvar, %loopvariant +// While SCEV fails to avoid trunc, we can still try to use instruction +// combining approach to prove trunc is not required. This can be further +// extended with other instruction combining checks, but for now we handle the +// following case (sub can be "add" and "mul", "nsw + sext" can be "nus + zext") +// +// Src: +// %c = sub nsw %b, %indvar +// %d = sext %c to i64 +// Dst: +// %indvar.ext1 = sext %indvar to i64 +// %m = sext %b to i64 +// %d = sub nsw i64 %m, %indvar.ext1 +// Therefore, as long as the result of add/sub/mul is extended to wide type, no +// trunc is required regardless of how %b is generated. This pattern is common +// when calculating address in 64 bit architecture +bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { + Instruction *NarrowUse = DU.NarrowUse; + Instruction *NarrowDef = DU.NarrowDef; + Instruction *WideDef = DU.WideDef; + + // Handle the common case of add + const unsigned OpCode = NarrowUse->getOpcode(); + // Only Add/Sub/Mul instructions are supported. + if (OpCode != Instruction::Add && OpCode != Instruction::Sub && + OpCode != Instruction::Mul) + return false; + + // The operand that is not defined by NarrowDef of DU. Let's call it the + // other operand. + assert((NarrowUse->getOperand(0) == NarrowDef || + NarrowUse->getOperand(1) == NarrowDef) && + "bad DU"); + + const OverflowingBinaryOperator *OBO = + cast(NarrowUse); + ExtendKind ExtKind = getExtendKind(NarrowDef); + bool CanSignExtend = ExtKind == SignExtended && OBO->hasNoSignedWrap(); + bool CanZeroExtend = ExtKind == ZeroExtended && OBO->hasNoUnsignedWrap(); + auto AnotherOpExtKind = ExtKind; + + // Check that all uses are either: + // - narrow def (in case of we are widening the IV increment); + // - single-input LCSSA Phis; + // - comparison of the chosen type; + // - extend of the chosen type (raison d'etre). + SmallVector ExtUsers; + SmallVector LCSSAPhiUsers; + SmallVector ICmpUsers; + for (Use &U : NarrowUse->uses()) { + Instruction *User = cast(U.getUser()); + if (User == NarrowDef) + continue; + if (!L->contains(User)) { + auto *LCSSAPhi = cast(User); + // Make sure there is only 1 input, so that we don't have to split + // critical edges. + if (LCSSAPhi->getNumOperands() != 1) + return false; + LCSSAPhiUsers.push_back(LCSSAPhi); + continue; + } + if (auto *ICmp = dyn_cast(User)) { + auto Pred = ICmp->getPredicate(); + // We have 3 types of predicates: signed, unsigned and equality + // predicates. For equality, it's legal to widen icmp for either sign and + // zero extend. For sign extend, we can also do so for signed predicates, + // likeweise for zero extend we can widen icmp for unsigned predicates. + if (ExtKind == ZeroExtended && ICmpInst::isSigned(Pred)) + return false; + if (ExtKind == SignExtended && ICmpInst::isUnsigned(Pred)) + return false; + ICmpUsers.push_back(ICmp); + continue; + } + if (ExtKind == SignExtended) + User = dyn_cast(User); + else + User = dyn_cast(User); + if (!User || User->getType() != WideType) + return false; + ExtUsers.push_back(User); + } + if (ExtUsers.empty()) { + DeadInsts.emplace_back(NarrowUse); + return true; + } + + // We'll prove some facts that should be true in the context of ext users. If + // there is no users, we are done now. If there are some, pick their common + // dominator as context. + Instruction *Context = nullptr; + for (auto *Ext : ExtUsers) { + if (!Context || DT->dominates(Ext, Context)) + Context = Ext; + else if (!DT->dominates(Context, Ext)) + // For users that don't have dominance relation, use common dominator. + Context = + DT->findNearestCommonDominator(Context->getParent(), Ext->getParent()) + ->getTerminator(); + } + assert(Context && "Context not found?"); + + if (!CanSignExtend && !CanZeroExtend) { + // Because InstCombine turns 'sub nuw' to 'add' losing the no-wrap flag, we + // will most likely not see it. Let's try to prove it. + if (OpCode != Instruction::Add) + return false; + if (ExtKind != ZeroExtended) + return false; + const SCEV *LHS = SE->getSCEV(OBO->getOperand(0)); + const SCEV *RHS = SE->getSCEV(OBO->getOperand(1)); + // TODO: Support case for NarrowDef = NarrowUse->getOperand(1). + if (NarrowUse->getOperand(0) != NarrowDef) + return false; + if (!SE->isKnownNegative(RHS)) + return false; + bool ProvedSubNUW = SE->isKnownPredicateAt( + ICmpInst::ICMP_UGE, LHS, SE->getNegativeSCEV(RHS), Context); + if (!ProvedSubNUW) + return false; + // In fact, our 'add' is 'sub nuw'. We will need to widen the 2nd operand as + // neg(zext(neg(op))), which is basically sext(op). + AnotherOpExtKind = SignExtended; + } + + // Verifying that Defining operand is an AddRec + const SCEV *Op1 = SE->getSCEV(WideDef); + const SCEVAddRecExpr *AddRecOp1 = dyn_cast(Op1); + if (!AddRecOp1 || AddRecOp1->getLoop() != L) + return false; + + LLVM_DEBUG(dbgs() << "Cloning arithmetic IVUser: " << *NarrowUse << "\n"); + + // Generating a widening use instruction. + Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(0), WideType, + AnotherOpExtKind, NarrowUse); + Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) + ? WideDef + : createExtendInst(NarrowUse->getOperand(1), WideType, + AnotherOpExtKind, NarrowUse); + + auto *NarrowBO = cast(NarrowUse); + auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, + NarrowBO->getName()); + IRBuilder<> Builder(NarrowUse); + Builder.Insert(WideBO); + WideBO->copyIRFlags(NarrowBO); + ExtendKindMap[NarrowUse] = ExtKind; + + for (Instruction *User : ExtUsers) { + assert(User->getType() == WideType && "Checked before!"); + LLVM_DEBUG(dbgs() << "INDVARS: eliminating " << *User << " replaced by " + << *WideBO << "\n"); + ++NumElimExt; + User->replaceAllUsesWith(WideBO); + DeadInsts.emplace_back(User); + } + + for (PHINode *User : LCSSAPhiUsers) { + assert(User->getNumOperands() == 1 && "Checked before!"); + Builder.SetInsertPoint(User); + auto *WidePN = + Builder.CreatePHI(WideBO->getType(), 1, User->getName() + ".wide"); + BasicBlock *LoopExitingBlock = User->getParent()->getSinglePredecessor(); + assert(LoopExitingBlock && L->contains(LoopExitingBlock) && + "Not a LCSSA Phi?"); + WidePN->addIncoming(WideBO, LoopExitingBlock); + Builder.SetInsertPoint(&*User->getParent()->getFirstInsertionPt()); + auto *TruncPN = Builder.CreateTrunc(WidePN, User->getType()); + User->replaceAllUsesWith(TruncPN); + DeadInsts.emplace_back(User); + } + + for (ICmpInst *User : ICmpUsers) { + Builder.SetInsertPoint(User); + auto ExtendedOp = [&](Value * V)->Value * { + if (V == NarrowUse) + return WideBO; + if (ExtKind == ZeroExtended) + return Builder.CreateZExt(V, WideBO->getType()); + else + return Builder.CreateSExt(V, WideBO->getType()); + }; + auto Pred = User->getPredicate(); + auto *LHS = ExtendedOp(User->getOperand(0)); + auto *RHS = ExtendedOp(User->getOperand(1)); + auto *WideCmp = + Builder.CreateICmp(Pred, LHS, RHS, User->getName() + ".wide"); + User->replaceAllUsesWith(WideCmp); + DeadInsts.emplace_back(User); + } + + return true; +} + +/// Determine whether an individual user of the narrow IV can be widened. If so, +/// return the wide clone of the user. +Instruction *WidenIV::widenIVUse(WidenIV::NarrowIVDefUse DU, SCEVExpander &Rewriter) { + assert(ExtendKindMap.count(DU.NarrowDef) && + "Should already know the kind of extension used to widen NarrowDef"); + + // Stop traversing the def-use chain at inner-loop phis or post-loop phis. + if (PHINode *UsePhi = dyn_cast(DU.NarrowUse)) { + if (LI->getLoopFor(UsePhi->getParent()) != L) { + // For LCSSA phis, sink the truncate outside the loop. + // After SimplifyCFG most loop exit targets have a single predecessor. + // Otherwise fall back to a truncate within the loop. + if (UsePhi->getNumOperands() != 1) + truncateIVUse(DU, DT, LI); + else { + // Widening the PHI requires us to insert a trunc. The logical place + // for this trunc is in the same BB as the PHI. This is not possible if + // the BB is terminated by a catchswitch. + if (isa(UsePhi->getParent()->getTerminator())) + return nullptr; + + PHINode *WidePhi = + PHINode::Create(DU.WideDef->getType(), 1, UsePhi->getName() + ".wide", + UsePhi); + WidePhi->addIncoming(DU.WideDef, UsePhi->getIncomingBlock(0)); + IRBuilder<> Builder(&*WidePhi->getParent()->getFirstInsertionPt()); + Value *Trunc = Builder.CreateTrunc(WidePhi, DU.NarrowDef->getType()); + UsePhi->replaceAllUsesWith(Trunc); + DeadInsts.emplace_back(UsePhi); + LLVM_DEBUG(dbgs() << "INDVARS: Widen lcssa phi " << *UsePhi << " to " + << *WidePhi << "\n"); + } + return nullptr; + } + } + + // This narrow use can be widened by a sext if it's non-negative or its narrow + // def was widended by a sext. Same for zext. + auto canWidenBySExt = [&]() { + return DU.NeverNegative || getExtendKind(DU.NarrowDef) == SignExtended; + }; + auto canWidenByZExt = [&]() { + return DU.NeverNegative || getExtendKind(DU.NarrowDef) == ZeroExtended; + }; + + // Our raison d'etre! Eliminate sign and zero extension. + if ((isa(DU.NarrowUse) && canWidenBySExt()) || + (isa(DU.NarrowUse) && canWidenByZExt())) { + Value *NewDef = DU.WideDef; + if (DU.NarrowUse->getType() != WideType) { + unsigned CastWidth = SE->getTypeSizeInBits(DU.NarrowUse->getType()); + unsigned IVWidth = SE->getTypeSizeInBits(WideType); + if (CastWidth < IVWidth) { + // The cast isn't as wide as the IV, so insert a Trunc. + IRBuilder<> Builder(DU.NarrowUse); + NewDef = Builder.CreateTrunc(DU.WideDef, DU.NarrowUse->getType()); + } + else { + // A wider extend was hidden behind a narrower one. This may induce + // another round of IV widening in which the intermediate IV becomes + // dead. It should be very rare. + LLVM_DEBUG(dbgs() << "INDVARS: New IV " << *WidePhi + << " not wide enough to subsume " << *DU.NarrowUse + << "\n"); + DU.NarrowUse->replaceUsesOfWith(DU.NarrowDef, DU.WideDef); + NewDef = DU.NarrowUse; + } + } + if (NewDef != DU.NarrowUse) { + LLVM_DEBUG(dbgs() << "INDVARS: eliminating " << *DU.NarrowUse + << " replaced by " << *DU.WideDef << "\n"); + ++NumElimExt; + DU.NarrowUse->replaceAllUsesWith(NewDef); + DeadInsts.emplace_back(DU.NarrowUse); + } + // Now that the extend is gone, we want to expose it's uses for potential + // further simplification. We don't need to directly inform SimplifyIVUsers + // of the new users, because their parent IV will be processed later as a + // new loop phi. If we preserved IVUsers analysis, we would also want to + // push the uses of WideDef here. + + // No further widening is needed. The deceased [sz]ext had done it for us. + return nullptr; + } + + // Does this user itself evaluate to a recurrence after widening? + WidenedRecTy WideAddRec = getExtendedOperandRecurrence(DU); + if (!WideAddRec.first) + WideAddRec = getWideRecurrence(DU); + + assert((WideAddRec.first == nullptr) == (WideAddRec.second == Unknown)); + if (!WideAddRec.first) { + // If use is a loop condition, try to promote the condition instead of + // truncating the IV first. + if (widenLoopCompare(DU)) + return nullptr; + + // We are here about to generate a truncate instruction that may hurt + // performance because the scalar evolution expression computed earlier + // in WideAddRec.first does not indicate a polynomial induction expression. + // In that case, look at the operands of the use instruction to determine + // if we can still widen the use instead of truncating its operand. + if (widenWithVariantUse(DU)) + return nullptr; + + // This user does not evaluate to a recurrence after widening, so don't + // follow it. Instead insert a Trunc to kill off the original use, + // eventually isolating the original narrow IV so it can be removed. + truncateIVUse(DU, DT, LI); + return nullptr; + } + // Assume block terminators cannot evaluate to a recurrence. We can't to + // insert a Trunc after a terminator if there happens to be a critical edge. + assert(DU.NarrowUse != DU.NarrowUse->getParent()->getTerminator() && + "SCEV is not expected to evaluate a block terminator"); + + // Reuse the IV increment that SCEVExpander created as long as it dominates + // NarrowUse. + Instruction *WideUse = nullptr; + if (WideAddRec.first == WideIncExpr && + Rewriter.hoistIVInc(WideInc, DU.NarrowUse)) + WideUse = WideInc; + else { + WideUse = cloneIVUser(DU, WideAddRec.first); + if (!WideUse) + return nullptr; + } + // Evaluation of WideAddRec ensured that the narrow expression could be + // extended outside the loop without overflow. This suggests that the wide use + // evaluates to the same expression as the extended narrow use, but doesn't + // absolutely guarantee it. Hence the following failsafe check. In rare cases + // where it fails, we simply throw away the newly created wide use. + if (WideAddRec.first != SE->getSCEV(WideUse)) { + LLVM_DEBUG(dbgs() << "Wide use expression mismatch: " << *WideUse << ": " + << *SE->getSCEV(WideUse) << " != " << *WideAddRec.first + << "\n"); + DeadInsts.emplace_back(WideUse); + return nullptr; + } + + // if we reached this point then we are going to replace + // DU.NarrowUse with WideUse. Reattach DbgValue then. + replaceAllDbgUsesWith(*DU.NarrowUse, *WideUse, *WideUse, *DT); + + ExtendKindMap[DU.NarrowUse] = WideAddRec.second; + // Returning WideUse pushes it on the worklist. + return WideUse; +} + +/// Add eligible users of NarrowDef to NarrowIVUsers. +void WidenIV::pushNarrowIVUsers(Instruction *NarrowDef, Instruction *WideDef) { + const SCEV *NarrowSCEV = SE->getSCEV(NarrowDef); + bool NonNegativeDef = + SE->isKnownPredicate(ICmpInst::ICMP_SGE, NarrowSCEV, + SE->getZero(NarrowSCEV->getType())); + for (User *U : NarrowDef->users()) { + Instruction *NarrowUser = cast(U); + + // Handle data flow merges and bizarre phi cycles. + if (!Widened.insert(NarrowUser).second) + continue; + + bool NonNegativeUse = false; + if (!NonNegativeDef) { + // We might have a control-dependent range information for this context. + if (auto RangeInfo = getPostIncRangeInfo(NarrowDef, NarrowUser)) + NonNegativeUse = RangeInfo->getSignedMin().isNonNegative(); + } + + NarrowIVUsers.emplace_back(NarrowDef, NarrowUser, WideDef, + NonNegativeDef || NonNegativeUse); + } +} + +/// Process a single induction variable. First use the SCEVExpander to create a +/// wide induction variable that evaluates to the same recurrence as the +/// original narrow IV. Then use a worklist to forward traverse the narrow IV's +/// def-use chain. After widenIVUse has processed all interesting IV users, the +/// narrow IV will be isolated for removal by DeleteDeadPHIs. +/// +/// It would be simpler to delete uses as they are processed, but we must avoid +/// invalidating SCEV expressions. +PHINode *WidenIV::createWideIV(SCEVExpander &Rewriter) { + // Is this phi an induction variable? + const SCEVAddRecExpr *AddRec = dyn_cast(SE->getSCEV(OrigPhi)); + if (!AddRec) + return nullptr; + + // Widen the induction variable expression. + const SCEV *WideIVExpr = getExtendKind(OrigPhi) == SignExtended + ? SE->getSignExtendExpr(AddRec, WideType) + : SE->getZeroExtendExpr(AddRec, WideType); + + assert(SE->getEffectiveSCEVType(WideIVExpr->getType()) == WideType && + "Expect the new IV expression to preserve its type"); + + // Can the IV be extended outside the loop without overflow? + AddRec = dyn_cast(WideIVExpr); + if (!AddRec || AddRec->getLoop() != L) + return nullptr; + + // An AddRec must have loop-invariant operands. Since this AddRec is + // materialized by a loop header phi, the expression cannot have any post-loop + // operands, so they must dominate the loop header. + assert( + SE->properlyDominates(AddRec->getStart(), L->getHeader()) && + SE->properlyDominates(AddRec->getStepRecurrence(*SE), L->getHeader()) && + "Loop header phi recurrence inputs do not dominate the loop"); + + // Iterate over IV uses (including transitive ones) looking for IV increments + // of the form 'add nsw %iv, '. For each increment and each use of + // the increment calculate control-dependent range information basing on + // dominating conditions inside of the loop (e.g. a range check inside of the + // loop). Calculated ranges are stored in PostIncRangeInfos map. + // + // Control-dependent range information is later used to prove that a narrow + // definition is not negative (see pushNarrowIVUsers). It's difficult to do + // this on demand because when pushNarrowIVUsers needs this information some + // of the dominating conditions might be already widened. + if (UsePostIncrementRanges) + calculatePostIncRanges(OrigPhi); + + // The rewriter provides a value for the desired IV expression. This may + // either find an existing phi or materialize a new one. Either way, we + // expect a well-formed cyclic phi-with-increments. i.e. any operand not part + // of the phi-SCC dominates the loop entry. + Instruction *InsertPt = &*L->getHeader()->getFirstInsertionPt(); + Value *ExpandInst = Rewriter.expandCodeFor(AddRec, WideType, InsertPt); + // If the wide phi is not a phi node, for example a cast node, like bitcast, + // inttoptr, ptrtoint, just skip for now. + if (!(WidePhi = dyn_cast(ExpandInst))) { + // if the cast node is an inserted instruction without any user, we should + // remove it to make sure the pass don't touch the function as we can not + // wide the phi. + if (ExpandInst->hasNUses(0) && + Rewriter.isInsertedInstruction(cast(ExpandInst))) + DeadInsts.emplace_back(ExpandInst); + return nullptr; + } + + // Remembering the WideIV increment generated by SCEVExpander allows + // widenIVUse to reuse it when widening the narrow IV's increment. We don't + // employ a general reuse mechanism because the call above is the only call to + // SCEVExpander. Henceforth, we produce 1-to-1 narrow to wide uses. + if (BasicBlock *LatchBlock = L->getLoopLatch()) { + WideInc = + cast(WidePhi->getIncomingValueForBlock(LatchBlock)); + WideIncExpr = SE->getSCEV(WideInc); + // Propagate the debug location associated with the original loop increment + // to the new (widened) increment. + auto *OrigInc = + cast(OrigPhi->getIncomingValueForBlock(LatchBlock)); + WideInc->setDebugLoc(OrigInc->getDebugLoc()); + } + + LLVM_DEBUG(dbgs() << "Wide IV: " << *WidePhi << "\n"); + ++NumWidened; + + // Traverse the def-use chain using a worklist starting at the original IV. + assert(Widened.empty() && NarrowIVUsers.empty() && "expect initial state" ); + + Widened.insert(OrigPhi); + pushNarrowIVUsers(OrigPhi, WidePhi); + + while (!NarrowIVUsers.empty()) { + WidenIV::NarrowIVDefUse DU = NarrowIVUsers.pop_back_val(); + + // Process a def-use edge. This may replace the use, so don't hold a + // use_iterator across it. + Instruction *WideUse = widenIVUse(DU, Rewriter); + + // Follow all def-use edges from the previous narrow use. + if (WideUse) + pushNarrowIVUsers(DU.NarrowUse, WideUse); + + // widenIVUse may have removed the def-use edge. + if (DU.NarrowDef->use_empty()) + DeadInsts.emplace_back(DU.NarrowDef); + } + + // Attach any debug information to the new PHI. + replaceAllDbgUsesWith(*OrigPhi, *WidePhi, *WidePhi, *DT); + + return WidePhi; +} + +/// Calculates control-dependent range for the given def at the given context +/// by looking at dominating conditions inside of the loop +void WidenIV::calculatePostIncRange(Instruction *NarrowDef, + Instruction *NarrowUser) { + using namespace llvm::PatternMatch; + + Value *NarrowDefLHS; + const APInt *NarrowDefRHS; + if (!match(NarrowDef, m_NSWAdd(m_Value(NarrowDefLHS), + m_APInt(NarrowDefRHS))) || + !NarrowDefRHS->isNonNegative()) + return; + + auto UpdateRangeFromCondition = [&] (Value *Condition, + bool TrueDest) { + CmpInst::Predicate Pred; + Value *CmpRHS; + if (!match(Condition, m_ICmp(Pred, m_Specific(NarrowDefLHS), + m_Value(CmpRHS)))) + return; + + CmpInst::Predicate P = + TrueDest ? Pred : CmpInst::getInversePredicate(Pred); + + auto CmpRHSRange = SE->getSignedRange(SE->getSCEV(CmpRHS)); + auto CmpConstrainedLHSRange = + ConstantRange::makeAllowedICmpRegion(P, CmpRHSRange); + auto NarrowDefRange = CmpConstrainedLHSRange.addWithNoWrap( + *NarrowDefRHS, OverflowingBinaryOperator::NoSignedWrap); + + updatePostIncRangeInfo(NarrowDef, NarrowUser, NarrowDefRange); + }; + + auto UpdateRangeFromGuards = [&](Instruction *Ctx) { + if (!HasGuards) + return; + + for (Instruction &I : make_range(Ctx->getIterator().getReverse(), + Ctx->getParent()->rend())) { + Value *C = nullptr; + if (match(&I, m_Intrinsic(m_Value(C)))) + UpdateRangeFromCondition(C, /*TrueDest=*/true); + } + }; + + UpdateRangeFromGuards(NarrowUser); + + BasicBlock *NarrowUserBB = NarrowUser->getParent(); + // If NarrowUserBB is statically unreachable asking dominator queries may + // yield surprising results. (e.g. the block may not have a dom tree node) + if (!DT->isReachableFromEntry(NarrowUserBB)) + return; + + for (auto *DTB = (*DT)[NarrowUserBB]->getIDom(); + L->contains(DTB->getBlock()); + DTB = DTB->getIDom()) { + auto *BB = DTB->getBlock(); + auto *TI = BB->getTerminator(); + UpdateRangeFromGuards(TI); + + auto *BI = dyn_cast(TI); + if (!BI || !BI->isConditional()) + continue; + + auto *TrueSuccessor = BI->getSuccessor(0); + auto *FalseSuccessor = BI->getSuccessor(1); + + auto DominatesNarrowUser = [this, NarrowUser] (BasicBlockEdge BBE) { + return BBE.isSingleEdge() && + DT->dominates(BBE, NarrowUser->getParent()); + }; + + if (DominatesNarrowUser(BasicBlockEdge(BB, TrueSuccessor))) + UpdateRangeFromCondition(BI->getCondition(), /*TrueDest=*/true); + + if (DominatesNarrowUser(BasicBlockEdge(BB, FalseSuccessor))) + UpdateRangeFromCondition(BI->getCondition(), /*TrueDest=*/false); + } +} + +/// Calculates PostIncRangeInfos map for the given IV +void WidenIV::calculatePostIncRanges(PHINode *OrigPhi) { + SmallPtrSet Visited; + SmallVector Worklist; + Worklist.push_back(OrigPhi); + Visited.insert(OrigPhi); + + while (!Worklist.empty()) { + Instruction *NarrowDef = Worklist.pop_back_val(); + + for (Use &U : NarrowDef->uses()) { + auto *NarrowUser = cast(U.getUser()); + + // Don't go looking outside the current loop. + auto *NarrowUserLoop = (*LI)[NarrowUser->getParent()]; + if (!NarrowUserLoop || !L->contains(NarrowUserLoop)) + continue; + + if (!Visited.insert(NarrowUser).second) + continue; + + Worklist.push_back(NarrowUser); + + calculatePostIncRange(NarrowDef, NarrowUser); + } + } +} + +PHINode *llvm::createWideIV(const WideIVInfo &WI, + LoopInfo *LI, ScalarEvolution *SE, SCEVExpander &Rewriter, + DominatorTree *DT, SmallVectorImpl &DeadInsts, + unsigned &NumElimExt, unsigned &NumWidened, + bool HasGuards, bool UsePostIncrementRanges) { + WidenIV Widener(WI, LI, SE, DT, DeadInsts, HasGuards, UsePostIncrementRanges); + PHINode *WidePHI = Widener.createWideIV(Rewriter); + NumElimExt = Widener.getNumElimExt(); + NumWidened = Widener.getNumWidened(); + return WidePHI; +} diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index cfcc3454a210..f9a9dd237b6c 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -20,7 +20,6 @@ #include "llvm/Analysis/ConstantFolding.h" #include "llvm/Analysis/OptimizationRemarkEmitter.h" #include "llvm/Analysis/ProfileSummaryInfo.h" -#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/CaptureTracking.h" @@ -542,6 +541,8 @@ Value *LibCallSimplifier::optimizeStrCpy(CallInst *CI, IRBuilderBase &B) { B.CreateMemCpy(Dst, Align(1), Src, Align(1), ConstantInt::get(DL.getIntPtrType(CI->getContext()), Len)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return Dst; } @@ -569,6 +570,8 @@ Value *LibCallSimplifier::optimizeStpCpy(CallInst *CI, IRBuilderBase &B) { // copy for us. Make a memcpy to copy the nul byte with align = 1. CallInst *NewCI = B.CreateMemCpy(Dst, Align(1), Src, Align(1), LenV); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return DstEnd; } @@ -609,15 +612,27 @@ Value *LibCallSimplifier::optimizeStrNCpy(CallInst *CI, IRBuilderBase &B) { return Dst; } - // Let strncpy handle the zero padding - if (Len > SrcLen + 1) - return nullptr; + // strncpy(a, "a", 4) - > memcpy(a, "a\0\0\0", 4) + if (Len > SrcLen + 1) { + if (Len <= 128) { + StringRef Str; + if (!getConstantStringInfo(Src, Str)) + return nullptr; + std::string SrcStr = Str.str(); + SrcStr.resize(Len, '\0'); + Src = B.CreateGlobalString(SrcStr, "str"); + } else { + return nullptr; + } + } Type *PT = Callee->getFunctionType()->getParamType(0); // strncpy(x, s, c) -> memcpy(align 1 x, align 1 s, c) [s and c are constant] CallInst *NewCI = B.CreateMemCpy(Dst, Align(1), Src, Align(1), ConstantInt::get(DL.getIntPtrType(PT), Len)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return Dst; } @@ -684,8 +699,6 @@ Value *LibCallSimplifier::optimizeStringLength(CallInst *CI, IRBuilderBase &B, Offset); } } - - return nullptr; } // strlen(x?"foo":"bars") --> x ? 3 : 4 @@ -1095,6 +1108,8 @@ Value *LibCallSimplifier::optimizeMemCpy(CallInst *CI, IRBuilderBase &B) { CallInst *NewCI = B.CreateMemCpy(CI->getArgOperand(0), Align(1), CI->getArgOperand(1), Align(1), Size); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } @@ -1143,7 +1158,12 @@ Value *LibCallSimplifier::optimizeMemPCpy(CallInst *CI, IRBuilderBase &B) { // mempcpy(x, y, n) -> llvm.memcpy(align 1 x, align 1 y, n), x + n CallInst *NewCI = B.CreateMemCpy(Dst, Align(1), CI->getArgOperand(1), Align(1), N); + // Propagate attributes, but memcpy has no return value, so make sure that + // any return attributes are compliant. + // TODO: Attach return value attributes to the 1st operand to preserve them? NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return B.CreateInBoundsGEP(B.getInt8Ty(), Dst, N); } @@ -1157,6 +1177,8 @@ Value *LibCallSimplifier::optimizeMemMove(CallInst *CI, IRBuilderBase &B) { CallInst *NewCI = B.CreateMemMove(CI->getArgOperand(0), Align(1), CI->getArgOperand(1), Align(1), Size); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } @@ -1217,6 +1239,8 @@ Value *LibCallSimplifier::optimizeMemSet(CallInst *CI, IRBuilderBase &B) { Value *Val = B.CreateIntCast(CI->getArgOperand(1), B.getInt8Ty(), false); CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val, Size, Align(1)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } @@ -1629,6 +1653,14 @@ Value *LibCallSimplifier::replacePowWithSqrt(CallInst *Pow, IRBuilderBase &B) { if (ExpoF->isNegative() && (!Pow->hasApproxFunc() && !Pow->hasAllowReassoc())) return nullptr; + // If we have a pow() library call (accesses memory) and we can't guarantee + // that the base is not an infinity, give up: + // pow(-Inf, 0.5) is optionally required to have a result of +Inf (not setting + // errno), but sqrt(-Inf) is required by various standards to set errno. + if (!Pow->doesNotAccessMemory() && !Pow->hasNoInfs() && + !isKnownNeverInfinity(Base, TLI)) + return nullptr; + Sqrt = getSqrtCall(Base, Attrs, Pow->doesNotAccessMemory(), Mod, B, TLI); if (!Sqrt) return nullptr; @@ -1715,7 +1747,8 @@ Value *LibCallSimplifier::optimizePow(CallInst *Pow, IRBuilderBase &B) { // pow(x, n) -> x * x * x * ... const APFloat *ExpoF; - if (AllowApprox && match(Expo, m_APFloat(ExpoF))) { + if (AllowApprox && match(Expo, m_APFloat(ExpoF)) && + !ExpoF->isExactlyValue(0.5) && !ExpoF->isExactlyValue(-0.5)) { // We limit to a max of 7 multiplications, thus the maximum exponent is 32. // If the exponent is an integer+0.5 we generate a call to sqrt and an // additional fmul. @@ -1741,6 +1774,8 @@ Value *LibCallSimplifier::optimizePow(CallInst *Pow, IRBuilderBase &B) { Sqrt = getSqrtCall(Base, Pow->getCalledFunction()->getAttributes(), Pow->doesNotAccessMemory(), M, B, TLI); + if (!Sqrt) + return nullptr; } // We will memoize intermediate products of the Addition Chain. @@ -2164,7 +2199,7 @@ Value *LibCallSimplifier::optimizeSinCosPi(CallInst *CI, IRBuilderBase &B) { classifyArgUse(U, F, IsFloat, SinCalls, CosCalls, SinCosCalls); // It's only worthwhile if both sinpi and cospi are actually used. - if (SinCosCalls.empty() && (SinCalls.empty() || CosCalls.empty())) + if (SinCalls.empty() || CosCalls.empty()) return nullptr; Value *Sin, *Cos, *SinCos; @@ -2190,7 +2225,7 @@ void LibCallSimplifier::classifyArgUse( SmallVectorImpl &SinCosCalls) { CallInst *CI = dyn_cast(Val); - if (!CI) + if (!CI || CI->use_empty()) return; // Don't consider calls in other functions. @@ -2487,6 +2522,30 @@ Value *LibCallSimplifier::optimizeSPrintFString(CallInst *CI, if (!CI->getArgOperand(2)->getType()->isPointerTy()) return nullptr; + if (CI->use_empty()) + // sprintf(dest, "%s", str) -> strcpy(dest, str) + return emitStrCpy(CI->getArgOperand(0), CI->getArgOperand(2), B, TLI); + + uint64_t SrcLen = GetStringLength(CI->getArgOperand(2)); + if (SrcLen) { + B.CreateMemCpy( + CI->getArgOperand(0), Align(1), CI->getArgOperand(2), Align(1), + ConstantInt::get(DL.getIntPtrType(CI->getContext()), SrcLen)); + // Returns total number of characters written without null-character. + return ConstantInt::get(CI->getType(), SrcLen - 1); + } else if (Value *V = emitStpCpy(CI->getArgOperand(0), CI->getArgOperand(2), + B, TLI)) { + // sprintf(dest, "%s", str) -> stpcpy(dest, str) - dest + Value *PtrDiff = B.CreatePtrDiff(V, CI->getArgOperand(0)); + return B.CreateIntCast(PtrDiff, CI->getType(), false); + } + + bool OptForSize = CI->getFunction()->hasOptSize() || + llvm::shouldOptimizeForSize(CI->getParent(), PSI, BFI, + PGSOQueryType::IRPass); + if (OptForSize) + return nullptr; + Value *Len = emitStrLen(CI->getArgOperand(2), B, DL, TLI); if (!Len) return nullptr; @@ -3219,6 +3278,8 @@ Value *FortifiedLibCallSimplifier::optimizeMemCpyChk(CallInst *CI, B.CreateMemCpy(CI->getArgOperand(0), Align(1), CI->getArgOperand(1), Align(1), CI->getArgOperand(2)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } return nullptr; @@ -3231,6 +3292,8 @@ Value *FortifiedLibCallSimplifier::optimizeMemMoveChk(CallInst *CI, B.CreateMemMove(CI->getArgOperand(0), Align(1), CI->getArgOperand(1), Align(1), CI->getArgOperand(2)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } return nullptr; @@ -3245,11 +3308,29 @@ Value *FortifiedLibCallSimplifier::optimizeMemSetChk(CallInst *CI, CallInst *NewCI = B.CreateMemSet(CI->getArgOperand(0), Val, CI->getArgOperand(2), Align(1)); NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes(AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); return CI->getArgOperand(0); } return nullptr; } +Value *FortifiedLibCallSimplifier::optimizeMemPCpyChk(CallInst *CI, + IRBuilderBase &B) { + const DataLayout &DL = CI->getModule()->getDataLayout(); + if (isFortifiedCallFoldable(CI, 3, 2)) + if (Value *Call = emitMemPCpy(CI->getArgOperand(0), CI->getArgOperand(1), + CI->getArgOperand(2), B, DL, TLI)) { + CallInst *NewCI = cast(Call); + NewCI->setAttributes(CI->getAttributes()); + NewCI->removeAttributes( + AttributeList::ReturnIndex, + AttributeFuncs::typeIncompatible(NewCI->getType())); + return NewCI; + } + return nullptr; +} + Value *FortifiedLibCallSimplifier::optimizeStrpCpyChk(CallInst *CI, IRBuilderBase &B, LibFunc Func) { @@ -3330,7 +3411,7 @@ Value *FortifiedLibCallSimplifier::optimizeMemCCpyChk(CallInst *CI, Value *FortifiedLibCallSimplifier::optimizeSNPrintfChk(CallInst *CI, IRBuilderBase &B) { if (isFortifiedCallFoldable(CI, 3, 1, None, 2)) { - SmallVector VariadicArgs(CI->arg_begin() + 5, CI->arg_end()); + SmallVector VariadicArgs(drop_begin(CI->args(), 5)); return emitSNPrintf(CI->getArgOperand(0), CI->getArgOperand(1), CI->getArgOperand(4), VariadicArgs, B, TLI); } @@ -3341,7 +3422,7 @@ Value *FortifiedLibCallSimplifier::optimizeSNPrintfChk(CallInst *CI, Value *FortifiedLibCallSimplifier::optimizeSPrintfChk(CallInst *CI, IRBuilderBase &B) { if (isFortifiedCallFoldable(CI, 2, None, None, 1)) { - SmallVector VariadicArgs(CI->arg_begin() + 4, CI->arg_end()); + SmallVector VariadicArgs(drop_begin(CI->args(), 4)); return emitSPrintf(CI->getArgOperand(0), CI->getArgOperand(3), VariadicArgs, B, TLI); } @@ -3439,6 +3520,8 @@ Value *FortifiedLibCallSimplifier::optimizeCall(CallInst *CI, switch (Func) { case LibFunc_memcpy_chk: return optimizeMemCpyChk(CI, Builder); + case LibFunc_mempcpy_chk: + return optimizeMemPCpyChk(CI, Builder); case LibFunc_memmove_chk: return optimizeMemMoveChk(CI, Builder); case LibFunc_memset_chk: diff --git a/llvm/lib/Transforms/Utils/SizeOpts.cpp b/llvm/lib/Transforms/Utils/SizeOpts.cpp index e257c5a015f5..beeb60698f04 100644 --- a/llvm/lib/Transforms/Utils/SizeOpts.cpp +++ b/llvm/lib/Transforms/Utils/SizeOpts.cpp @@ -43,11 +43,6 @@ cl::opt PGSOColdCodeOnlyForPartialSamplePGO( cl::desc("Apply the profile guided size optimizations only " "to cold code under partial-profile sample PGO.")); -cl::opt PGSOIRPassOrTestOnly( - "pgso-ir-pass-or-test-only", cl::Hidden, cl::init(false), - cl::desc("Apply the profile guided size optimizations only" - "to the IR passes or tests.")); - cl::opt ForcePGSO( "force-pgso", cl::Hidden, cl::init(false), cl::desc("Force the (profiled-guided) size optimizations. ")); diff --git a/llvm/lib/Transforms/Utils/StripGCRelocates.cpp b/llvm/lib/Transforms/Utils/StripGCRelocates.cpp index b559811d120b..1fa574f04c37 100644 --- a/llvm/lib/Transforms/Utils/StripGCRelocates.cpp +++ b/llvm/lib/Transforms/Utils/StripGCRelocates.cpp @@ -13,6 +13,7 @@ // present. //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/StripGCRelocates.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" #include "llvm/IR/Instructions.h" @@ -24,22 +25,7 @@ using namespace llvm; -namespace { -struct StripGCRelocates : public FunctionPass { - static char ID; // Pass identification, replacement for typeid - StripGCRelocates() : FunctionPass(ID) { - initializeStripGCRelocatesPass(*PassRegistry::getPassRegistry()); - } - - void getAnalysisUsage(AnalysisUsage &Info) const override {} - - bool runOnFunction(Function &F) override; - -}; -char StripGCRelocates::ID = 0; -} - -bool StripGCRelocates::runOnFunction(Function &F) { +static bool stripGCRelocates(Function &F) { // Nothing to do for declarations. if (F.isDeclaration()) return false; @@ -71,6 +57,32 @@ bool StripGCRelocates::runOnFunction(Function &F) { return !GCRelocates.empty(); } -INITIALIZE_PASS(StripGCRelocates, "strip-gc-relocates", +PreservedAnalyses StripGCRelocates::run(Function &F, + FunctionAnalysisManager &AM) { + if (!stripGCRelocates(F)) + return PreservedAnalyses::all(); + + // Removing gc.relocate preserves the CFG, but most other analysis probably + // need to re-run. + PreservedAnalyses PA; + PA.preserveSet(); + return PA; +} + +namespace { +struct StripGCRelocatesLegacy : public FunctionPass { + static char ID; // Pass identification, replacement for typeid + StripGCRelocatesLegacy() : FunctionPass(ID) { + initializeStripGCRelocatesLegacyPass(*PassRegistry::getPassRegistry()); + } + + void getAnalysisUsage(AnalysisUsage &Info) const override {} + + bool runOnFunction(Function &F) override { return ::stripGCRelocates(F); } +}; +char StripGCRelocatesLegacy::ID = 0; +} // namespace + +INITIALIZE_PASS(StripGCRelocatesLegacy, "strip-gc-relocates", "Strip gc.relocates inserted through RewriteStatepointsForGC", true, false) diff --git a/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp b/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp index 21cbbfb140b6..10fda4df51ba 100644 --- a/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp +++ b/llvm/lib/Transforms/Utils/StripNonLineTableDebugInfo.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/StripNonLineTableDebugInfo.h" #include "llvm/IR/DebugInfo.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" @@ -17,10 +18,11 @@ namespace { /// This pass strips all debug info that is not related line tables. /// The result will be the same as if the program where compiled with /// -gline-tables-only. -struct StripNonLineTableDebugInfo : public ModulePass { +struct StripNonLineTableDebugLegacyPass : public ModulePass { static char ID; // Pass identification, replacement for typeid - StripNonLineTableDebugInfo() : ModulePass(ID) { - initializeStripNonLineTableDebugInfoPass(*PassRegistry::getPassRegistry()); + StripNonLineTableDebugLegacyPass() : ModulePass(ID) { + initializeStripNonLineTableDebugLegacyPassPass( + *PassRegistry::getPassRegistry()); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -33,10 +35,17 @@ struct StripNonLineTableDebugInfo : public ModulePass { }; } -char StripNonLineTableDebugInfo::ID = 0; -INITIALIZE_PASS(StripNonLineTableDebugInfo, "strip-nonlinetable-debuginfo", +char StripNonLineTableDebugLegacyPass::ID = 0; +INITIALIZE_PASS(StripNonLineTableDebugLegacyPass, + "strip-nonlinetable-debuginfo", "Strip all debug info except linetables", false, false) -ModulePass *llvm::createStripNonLineTableDebugInfoPass() { - return new StripNonLineTableDebugInfo(); +ModulePass *llvm::createStripNonLineTableDebugLegacyPass() { + return new StripNonLineTableDebugLegacyPass(); +} + +PreservedAnalyses +StripNonLineTableDebugInfoPass::run(Module &M, ModuleAnalysisManager &AM) { + llvm::stripNonLineTableDebugInfo(M); + return PreservedAnalyses::all(); } diff --git a/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp b/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp index 9af39d9a0dd1..3631733713ab 100644 --- a/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp +++ b/llvm/lib/Transforms/Utils/UnifyFunctionExitNodes.cpp @@ -6,10 +6,8 @@ // //===----------------------------------------------------------------------===// // -// This pass is used to ensure that functions have at most one return -// instruction in them. Additionally, it keeps track of which node is the new -// exit node of the CFG. If there are no exit nodes in the CFG, the getExitNode -// method will return a null pointer. +// This pass is used to ensure that functions have at most one return and one +// unreachable instruction in them. // //===----------------------------------------------------------------------===// @@ -22,73 +20,66 @@ #include "llvm/Transforms/Utils.h" using namespace llvm; -char UnifyFunctionExitNodes::ID = 0; +char UnifyFunctionExitNodesLegacyPass::ID = 0; -UnifyFunctionExitNodes::UnifyFunctionExitNodes() : FunctionPass(ID) { - initializeUnifyFunctionExitNodesPass(*PassRegistry::getPassRegistry()); +UnifyFunctionExitNodesLegacyPass::UnifyFunctionExitNodesLegacyPass() + : FunctionPass(ID) { + initializeUnifyFunctionExitNodesLegacyPassPass( + *PassRegistry::getPassRegistry()); } -INITIALIZE_PASS(UnifyFunctionExitNodes, "mergereturn", +INITIALIZE_PASS(UnifyFunctionExitNodesLegacyPass, "mergereturn", "Unify function exit nodes", false, false) Pass *llvm::createUnifyFunctionExitNodesPass() { - return new UnifyFunctionExitNodes(); + return new UnifyFunctionExitNodesLegacyPass(); } -void UnifyFunctionExitNodes::getAnalysisUsage(AnalysisUsage &AU) const{ +void UnifyFunctionExitNodesLegacyPass::getAnalysisUsage( + AnalysisUsage &AU) const { // We preserve the non-critical-edgeness property AU.addPreservedID(BreakCriticalEdgesID); // This is a cluster of orthogonal Transforms AU.addPreservedID(LowerSwitchID); } -// UnifyAllExitNodes - Unify all exit nodes of the CFG by creating a new -// BasicBlock, and converting all returns to unconditional branches to this -// new basic block. The singular exit node is returned. -// -// If there are no return stmts in the Function, a null pointer is returned. -// -bool UnifyFunctionExitNodes::runOnFunction(Function &F) { - // Loop over all of the blocks in a function, tracking all of the blocks that - // return. - // - std::vector ReturningBlocks; - std::vector UnreachableBlocks; +namespace { + +bool unifyUnreachableBlocks(Function &F) { + std::vector UnreachableBlocks; + for (BasicBlock &I : F) - if (isa(I.getTerminator())) - ReturningBlocks.push_back(&I); - else if (isa(I.getTerminator())) + if (isa(I.getTerminator())) UnreachableBlocks.push_back(&I); - // Then unreachable blocks. - if (UnreachableBlocks.empty()) { - UnreachableBlock = nullptr; - } else if (UnreachableBlocks.size() == 1) { - UnreachableBlock = UnreachableBlocks.front(); - } else { - UnreachableBlock = BasicBlock::Create(F.getContext(), - "UnifiedUnreachableBlock", &F); - new UnreachableInst(F.getContext(), UnreachableBlock); - - for (BasicBlock *BB : UnreachableBlocks) { - BB->getInstList().pop_back(); // Remove the unreachable inst. - BranchInst::Create(UnreachableBlock, BB); - } + if (UnreachableBlocks.size() <= 1) + return false; + + BasicBlock *UnreachableBlock = + BasicBlock::Create(F.getContext(), "UnifiedUnreachableBlock", &F); + new UnreachableInst(F.getContext(), UnreachableBlock); + + for (BasicBlock *BB : UnreachableBlocks) { + BB->getInstList().pop_back(); // Remove the unreachable inst. + BranchInst::Create(UnreachableBlock, BB); } - // Now handle return blocks. - if (ReturningBlocks.empty()) { - ReturnBlock = nullptr; - return false; // No blocks return - } else if (ReturningBlocks.size() == 1) { - ReturnBlock = ReturningBlocks.front(); // Already has a single return block + return true; +} + +bool unifyReturnBlocks(Function &F) { + std::vector ReturningBlocks; + + for (BasicBlock &I : F) + if (isa(I.getTerminator())) + ReturningBlocks.push_back(&I); + + if (ReturningBlocks.size() <= 1) return false; - } - // Otherwise, we need to insert a new basic block into the function, add a PHI - // nodes (if the function returns values), and convert all of the return - // instructions into unconditional branches. - // + // Insert a new basic block into the function, add PHI nodes (if the function + // returns values), and convert all of the return instructions into + // unconditional branches. BasicBlock *NewRetBlock = BasicBlock::Create(F.getContext(), "UnifiedReturnBlock", &F); @@ -105,7 +96,6 @@ bool UnifyFunctionExitNodes::runOnFunction(Function &F) { // Loop over all of the blocks, replacing the return instruction with an // unconditional branch. - // for (BasicBlock *BB : ReturningBlocks) { // Add an incoming element to the PHI node for every return instruction that // is merging into this new block... @@ -115,6 +105,25 @@ bool UnifyFunctionExitNodes::runOnFunction(Function &F) { BB->getInstList().pop_back(); // Remove the return insn BranchInst::Create(NewRetBlock, BB); } - ReturnBlock = NewRetBlock; + return true; } +} // namespace + +// Unify all exit nodes of the CFG by creating a new BasicBlock, and converting +// all returns to unconditional branches to this new basic block. Also, unify +// all unreachable blocks. +bool UnifyFunctionExitNodesLegacyPass::runOnFunction(Function &F) { + bool Changed = false; + Changed |= unifyUnreachableBlocks(F); + Changed |= unifyReturnBlocks(F); + return Changed; +} + +PreservedAnalyses UnifyFunctionExitNodesPass::run(Function &F, + FunctionAnalysisManager &AM) { + bool Changed = false; + Changed |= unifyUnreachableBlocks(F); + Changed |= unifyReturnBlocks(F); + return Changed ? PreservedAnalyses() : PreservedAnalyses::all(); +} diff --git a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp index b10deee3907c..0b718ed6136e 100644 --- a/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp +++ b/llvm/lib/Transforms/Utils/UnifyLoopExits.cpp @@ -16,6 +16,8 @@ // //===----------------------------------------------------------------------===// +#include "llvm/Transforms/Utils/UnifyLoopExits.h" +#include "llvm/ADT/MapVector.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/InitializePasses.h" @@ -27,10 +29,10 @@ using namespace llvm; namespace { -struct UnifyLoopExits : public FunctionPass { +struct UnifyLoopExitsLegacyPass : public FunctionPass { static char ID; - UnifyLoopExits() : FunctionPass(ID) { - initializeUnifyLoopExitsPass(*PassRegistry::getPassRegistry()); + UnifyLoopExitsLegacyPass() : FunctionPass(ID) { + initializeUnifyLoopExitsLegacyPassPass(*PassRegistry::getPassRegistry()); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -46,17 +48,19 @@ struct UnifyLoopExits : public FunctionPass { }; } // namespace -char UnifyLoopExits::ID = 0; +char UnifyLoopExitsLegacyPass::ID = 0; -FunctionPass *llvm::createUnifyLoopExitsPass() { return new UnifyLoopExits(); } +FunctionPass *llvm::createUnifyLoopExitsPass() { + return new UnifyLoopExitsLegacyPass(); +} -INITIALIZE_PASS_BEGIN(UnifyLoopExits, "unify-loop-exits", +INITIALIZE_PASS_BEGIN(UnifyLoopExitsLegacyPass, "unify-loop-exits", "Fixup each natural loop to have a single exit block", false /* Only looks at CFG */, false /* Analysis Pass */) -INITIALIZE_PASS_DEPENDENCY(LowerSwitch) +INITIALIZE_PASS_DEPENDENCY(LowerSwitchLegacyPass) INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LoopInfoWrapperPass) -INITIALIZE_PASS_END(UnifyLoopExits, "unify-loop-exits", +INITIALIZE_PASS_END(UnifyLoopExitsLegacyPass, "unify-loop-exits", "Fixup each natural loop to have a single exit block", false /* Only looks at CFG */, false /* Analysis Pass */) @@ -80,7 +84,7 @@ static void restoreSSA(const DominatorTree &DT, const Loop *L, const SetVector &Incoming, BasicBlock *LoopExitBlock) { using InstVector = SmallVector; - using IIMap = DenseMap; + using IIMap = MapVector; IIMap ExternalUsers; for (auto BB : L->blocks()) { for (auto &I : *BB) { @@ -203,11 +207,7 @@ static bool unifyLoopExits(DominatorTree &DT, LoopInfo &LI, Loop *L) { return true; } -bool UnifyLoopExits::runOnFunction(Function &F) { - LLVM_DEBUG(dbgs() << "===== Unifying loop exits in function " << F.getName() - << "\n"); - auto &LI = getAnalysis().getLoopInfo(); - auto &DT = getAnalysis().getDomTree(); +static bool runImpl(LoopInfo &LI, DominatorTree &DT) { bool Changed = false; auto Loops = LI.getLoopsInPreorder(); @@ -218,3 +218,28 @@ bool UnifyLoopExits::runOnFunction(Function &F) { } return Changed; } + +bool UnifyLoopExitsLegacyPass::runOnFunction(Function &F) { + LLVM_DEBUG(dbgs() << "===== Unifying loop exits in function " << F.getName() + << "\n"); + auto &LI = getAnalysis().getLoopInfo(); + auto &DT = getAnalysis().getDomTree(); + + return runImpl(LI, DT); +} + +namespace llvm { + +PreservedAnalyses UnifyLoopExitsPass::run(Function &F, + FunctionAnalysisManager &AM) { + auto &LI = AM.getResult(F); + auto &DT = AM.getResult(F); + + if (!runImpl(LI, DT)) + return PreservedAnalyses::all(); + PreservedAnalyses PA; + PA.preserve(); + PA.preserve(); + return PA; +} +} // namespace llvm diff --git a/llvm/lib/Transforms/Utils/UniqueInternalLinkageNames.cpp b/llvm/lib/Transforms/Utils/UniqueInternalLinkageNames.cpp index 5b58548e54dc..c57cec6be676 100644 --- a/llvm/lib/Transforms/Utils/UniqueInternalLinkageNames.cpp +++ b/llvm/lib/Transforms/Utils/UniqueInternalLinkageNames.cpp @@ -13,8 +13,11 @@ #include "llvm/Transforms/Utils/UniqueInternalLinkageNames.h" #include "llvm/ADT/SmallString.h" +#include "llvm/IR/DebugInfoMetadata.h" +#include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/InitializePasses.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/MD5.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -27,13 +30,31 @@ static bool uniqueifyInternalLinkageNames(Module &M) { Md5.final(R); SmallString<32> Str; llvm::MD5::stringifyResult(R, Str); - std::string ModuleNameHash = (Twine(".") + Twine(Str)).str(); + // Convert MD5hash to Decimal. Demangler suffixes can either contain numbers + // or characters but not both. + APInt IntHash = APInt(128, Str.str(), 16); + // Prepend "__uniq" before the hash for tools like profilers to understand that + // this symbol is of internal linkage type. + std::string ModuleNameHash = (Twine(".__uniq.") + Twine(IntHash.toString(10, false))).str(); bool Changed = false; + MDBuilder MDB(M.getContext()); // Append the module hash to all internal linkage functions. for (auto &F : M) { if (F.hasInternalLinkage()) { F.setName(F.getName() + ModuleNameHash); + F.addFnAttr("sample-profile-suffix-elision-policy", "selected"); + // Replace linkage names in the debug metadata. + if (DISubprogram *SP = F.getSubprogram()) { + if (SP->getRawLinkageName()) { + auto *Name = MDB.createString(F.getName()); + SP->replaceRawLinkageName(Name); + if (DISubprogram *SPDecl = SP->getDeclaration()) { + if (SPDecl->getRawLinkageName()) + SPDecl->replaceRawLinkageName(Name); + } + } + } Changed = true; } } diff --git a/llvm/lib/Transforms/Utils/Utils.cpp b/llvm/lib/Transforms/Utils/Utils.cpp index ce98a739bea8..73c0532f3fd5 100644 --- a/llvm/lib/Transforms/Utils/Utils.cpp +++ b/llvm/lib/Transforms/Utils/Utils.cpp @@ -34,17 +34,17 @@ void llvm::initializeTransformUtils(PassRegistry &Registry) { initializeLibCallsShrinkWrapLegacyPassPass(Registry); initializeLoopSimplifyPass(Registry); initializeLowerInvokeLegacyPassPass(Registry); - initializeLowerSwitchPass(Registry); + initializeLowerSwitchLegacyPassPass(Registry); initializeNameAnonGlobalLegacyPassPass(Registry); initializePromoteLegacyPassPass(Registry); - initializeStripNonLineTableDebugInfoPass(Registry); - initializeUnifyFunctionExitNodesPass(Registry); + initializeStripNonLineTableDebugLegacyPassPass(Registry); + initializeUnifyFunctionExitNodesLegacyPassPass(Registry); initializeMetaRenamerPass(Registry); - initializeStripGCRelocatesPass(Registry); + initializeStripGCRelocatesLegacyPass(Registry); initializePredicateInfoPrinterLegacyPassPass(Registry); initializeInjectTLIMappingsLegacyPass(Registry); initializeFixIrreduciblePass(Registry); - initializeUnifyLoopExitsPass(Registry); + initializeUnifyLoopExitsLegacyPassPass(Registry); initializeUniqueInternalLinkageNamesLegacyPassPass(Registry); } diff --git a/llvm/lib/Transforms/Utils/VNCoercion.cpp b/llvm/lib/Transforms/Utils/VNCoercion.cpp index 6ff08cd28712..61cd8595a73b 100644 --- a/llvm/lib/Transforms/Utils/VNCoercion.cpp +++ b/llvm/lib/Transforms/Utils/VNCoercion.cpp @@ -17,6 +17,7 @@ static bool isFirstClassAggregateOrScalableType(Type *Ty) { bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, const DataLayout &DL) { Type *StoredTy = StoredVal->getType(); + if (StoredTy == LoadTy) return true; @@ -36,17 +37,29 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy, if (StoreSize < DL.getTypeSizeInBits(LoadTy).getFixedSize()) return false; + bool StoredNI = DL.isNonIntegralPointerType(StoredTy->getScalarType()); + bool LoadNI = DL.isNonIntegralPointerType(LoadTy->getScalarType()); // Don't coerce non-integral pointers to integers or vice versa. - if (DL.isNonIntegralPointerType(StoredVal->getType()->getScalarType()) != - DL.isNonIntegralPointerType(LoadTy->getScalarType())) { + if (StoredNI != LoadNI) { // As a special case, allow coercion of memset used to initialize // an array w/null. Despite non-integral pointers not generally having a // specific bit pattern, we do assume null is zero. if (auto *CI = dyn_cast(StoredVal)) return CI->isNullValue(); return false; + } else if (StoredNI && LoadNI && + StoredTy->getPointerAddressSpace() != + LoadTy->getPointerAddressSpace()) { + return false; } - + + + // The implementation below uses inttoptr for vectors of unequal size; we + // can't allow this for non integral pointers. We could teach it to extract + // exact subvectors if desired. + if (StoredNI && StoreSize != DL.getTypeSizeInBits(LoadTy).getFixedSize()) + return false; + return true; } @@ -223,14 +236,8 @@ int analyzeLoadFromClobberingStore(Type *LoadTy, Value *LoadPtr, if (isFirstClassAggregateOrScalableType(StoredVal->getType())) return -1; - // Don't coerce non-integral pointers to integers or vice versa. - if (DL.isNonIntegralPointerType(StoredVal->getType()->getScalarType()) != - DL.isNonIntegralPointerType(LoadTy->getScalarType())) { - // Allow casts of zero values to null as a special case - auto *CI = dyn_cast(StoredVal); - if (!CI || !CI->isNullValue()) - return -1; - } + if (!canCoerceMustAliasedValueToLoad(StoredVal, LoadTy, DL)) + return -1; Value *StorePtr = DepSI->getPointerOperand(); uint64_t StoreSize = @@ -333,9 +340,7 @@ int analyzeLoadFromClobberingLoad(Type *LoadTy, Value *LoadPtr, LoadInst *DepLI, if (DepLI->getType()->isStructTy() || DepLI->getType()->isArrayTy()) return -1; - // Don't coerce non-integral pointers to integers or vice versa. - if (DL.isNonIntegralPointerType(DepLI->getType()->getScalarType()) != - DL.isNonIntegralPointerType(LoadTy->getScalarType())) + if (!canCoerceMustAliasedValueToLoad(DepLI, LoadTy, DL)) return -1; Value *DepPtr = DepLI->getPointerOperand(); @@ -393,7 +398,7 @@ int analyzeLoadFromClobberingMemInst(Type *LoadTy, Value *LoadPtr, if (!Src) return -1; - GlobalVariable *GV = dyn_cast(GetUnderlyingObject(Src, DL)); + GlobalVariable *GV = dyn_cast(getUnderlyingObject(Src)); if (!GV || !GV->isConstant() || !GV->hasDefinitiveInitializer()) return -1; diff --git a/llvm/lib/Transforms/Utils/ValueMapper.cpp b/llvm/lib/Transforms/Utils/ValueMapper.cpp index f1b3fe8e2fa9..930e0b7ee01a 100644 --- a/llvm/lib/Transforms/Utils/ValueMapper.cpp +++ b/llvm/lib/Transforms/Utils/ValueMapper.cpp @@ -167,12 +167,9 @@ public: void flush(); private: - void mapGlobalInitializer(GlobalVariable &GV, Constant &Init); void mapAppendingVariable(GlobalVariable &GV, Constant *InitPrefix, bool IsOldCtorDtor, ArrayRef NewMembers); - void mapGlobalIndirectSymbol(GlobalIndirectSymbol &GIS, Constant &Target); - void remapFunction(Function &F, ValueToValueMapTy &VM); ValueToValueMapTy &getVM() { return *MCs[CurrentMCID].VM; } ValueMaterializer *getMaterializer() { return MCs[CurrentMCID].Materializer; } @@ -822,11 +819,15 @@ void Mapper::flush() { break; case WorklistEntry::MapAppendingVar: { unsigned PrefixSize = AppendingInits.size() - E.AppendingGVNumNewMembers; + // mapAppendingVariable call can change AppendingInits if initalizer for + // the variable depends on another appending global, because of that inits + // need to be extracted and updated before the call. + SmallVector NewInits( + drop_begin(AppendingInits, PrefixSize)); + AppendingInits.resize(PrefixSize); mapAppendingVariable(*E.Data.AppendingGV.GV, E.Data.AppendingGV.InitPrefix, - E.AppendingGVIsOldCtorDtor, - makeArrayRef(AppendingInits).slice(PrefixSize)); - AppendingInits.resize(PrefixSize); + E.AppendingGVIsOldCtorDtor, makeArrayRef(NewInits)); break; } case WorklistEntry::MapGlobalIndirectSymbol: @@ -900,14 +901,13 @@ void Mapper::remapInstruction(Instruction *I) { LLVMContext &C = CB->getContext(); AttributeList Attrs = CB->getAttributes(); for (unsigned i = 0; i < Attrs.getNumAttrSets(); ++i) { - if (Attrs.hasAttribute(i, Attribute::ByVal)) { - Type *Ty = Attrs.getAttribute(i, Attribute::ByVal).getValueAsType(); - if (!Ty) - continue; - - Attrs = Attrs.removeAttribute(C, i, Attribute::ByVal); - Attrs = Attrs.addAttribute( - C, i, Attribute::getWithByValType(C, TypeMapper->remapType(Ty))); + for (Attribute::AttrKind TypedAttr : + {Attribute::ByVal, Attribute::StructRet, Attribute::ByRef}) { + if (Type *Ty = Attrs.getAttribute(i, TypedAttr).getValueAsType()) { + Attrs = Attrs.replaceAttributeType(C, i, TypedAttr, + TypeMapper->remapType(Ty)); + break; + } } } CB->setAttributes(Attrs); diff --git a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp index 9b81afbb4b6c..6ec5590d76ba 100644 --- a/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/LoadStoreVectorizer.cpp @@ -666,6 +666,10 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { cast(&I)->getIntrinsicID() == Intrinsic::sideeffect) { // Ignore llvm.sideeffect calls. + } else if (isa(&I) && + cast(&I)->getIntrinsicID() == + Intrinsic::pseudoprobe) { + // Ignore llvm.pseudoprobe calls. } else if (IsLoadChain && (I.mayWriteToMemory() || I.mayThrow())) { LLVM_DEBUG(dbgs() << "LSV: Found may-write/throw operation: " << I << '\n'); @@ -762,8 +766,8 @@ Vectorizer::getVectorizablePrefix(ArrayRef Chain) { return Chain.slice(0, ChainIdx); } -static ChainID getChainID(const Value *Ptr, const DataLayout &DL) { - const Value *ObjPtr = GetUnderlyingObject(Ptr, DL); +static ChainID getChainID(const Value *Ptr) { + const Value *ObjPtr = getUnderlyingObject(Ptr); if (const auto *Sel = dyn_cast(ObjPtr)) { // The select's themselves are distinct instructions even if they share the // same condition and evaluate to consecutive pointers for true and false @@ -830,7 +834,7 @@ Vectorizer::collectInstructions(BasicBlock *BB) { continue; // Save the load locations. - const ChainID ID = getChainID(Ptr, DL); + const ChainID ID = getChainID(Ptr); LoadRefs[ID].push_back(LI); } else if (StoreInst *SI = dyn_cast(&I)) { if (!SI->isSimple()) @@ -876,7 +880,7 @@ Vectorizer::collectInstructions(BasicBlock *BB) { continue; // Save store location. - const ChainID ID = getChainID(Ptr, DL); + const ChainID ID = getChainID(Ptr); StoreRefs[ID].push_back(SI); } } @@ -1027,8 +1031,8 @@ bool Vectorizer::vectorizeStoreChain( unsigned EltSzInBytes = Sz / 8; unsigned SzInBytes = EltSzInBytes * ChainSize; - VectorType *VecTy; - VectorType *VecStoreTy = dyn_cast(StoreTy); + FixedVectorType *VecTy; + auto *VecStoreTy = dyn_cast(StoreTy); if (VecStoreTy) VecTy = FixedVectorType::get(StoreTy->getScalarType(), Chain.size() * VecStoreTy->getNumElements()); @@ -1180,7 +1184,7 @@ bool Vectorizer::vectorizeLoadChain( unsigned EltSzInBytes = Sz / 8; unsigned SzInBytes = EltSzInBytes * ChainSize; VectorType *VecTy; - VectorType *VecLoadTy = dyn_cast(LoadTy); + auto *VecLoadTy = dyn_cast(LoadTy); if (VecLoadTy) VecTy = FixedVectorType::get(LoadTy->getScalarType(), Chain.size() * VecLoadTy->getNumElements()); diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp index 23613775d896..2ab0848193f6 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp @@ -13,13 +13,16 @@ // pass. It should be easy to create an analysis pass around it if there // is a need (but D45420 needs to happen first). // + #include "llvm/Transforms/Vectorize/LoopVectorizationLegality.h" #include "llvm/Analysis/Loads.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" #include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/PatternMatch.h" +#include "llvm/Transforms/Utils/SizeOpts.h" #include "llvm/Transforms/Vectorize/LoopVectorize.h" using namespace llvm; @@ -63,6 +66,7 @@ bool LoopVectorizeHints::Hint::validate(unsigned Val) { return (Val <= 1); case HK_ISVECTORIZED: case HK_PREDICATE: + case HK_SCALABLE: return (Val == 0 || Val == 1); } return false; @@ -75,7 +79,8 @@ LoopVectorizeHints::LoopVectorizeHints(const Loop *L, Interleave("interleave.count", InterleaveOnlyWhenForced, HK_UNROLL), Force("vectorize.enable", FK_Undefined, HK_FORCE), IsVectorized("isvectorized", 0, HK_ISVECTORIZED), - Predicate("vectorize.predicate.enable", FK_Undefined, HK_PREDICATE), TheLoop(L), + Predicate("vectorize.predicate.enable", FK_Undefined, HK_PREDICATE), + Scalable("vectorize.scalable.enable", false, HK_SCALABLE), TheLoop(L), ORE(ORE) { // Populate values with existing loop metadata. getHintsFromMetadata(); @@ -88,7 +93,8 @@ LoopVectorizeHints::LoopVectorizeHints(const Loop *L, // If the vectorization width and interleaving count are both 1 then // consider the loop to have been already vectorized because there's // nothing more that we can do. - IsVectorized.Value = Width.Value == 1 && Interleave.Value == 1; + IsVectorized.Value = + getWidth() == ElementCount::getFixed(1) && Interleave.Value == 1; LLVM_DEBUG(if (InterleaveOnlyWhenForced && Interleave.Value == 1) dbgs() << "LV: Interleaving disabled by the pass manager\n"); } @@ -161,7 +167,7 @@ void LoopVectorizeHints::emitRemarkWithHints() const { if (Force.Value == LoopVectorizeHints::FK_Enabled) { R << " (Force=" << NV("Force", true); if (Width.Value != 0) - R << ", Vector Width=" << NV("VectorWidth", Width.Value); + R << ", Vector Width=" << NV("VectorWidth", getWidth()); if (Interleave.Value != 0) R << ", Interleave Count=" << NV("InterleaveCount", Interleave.Value); R << ")"; @@ -172,11 +178,11 @@ void LoopVectorizeHints::emitRemarkWithHints() const { } const char *LoopVectorizeHints::vectorizeAnalysisPassName() const { - if (getWidth() == 1) + if (getWidth() == ElementCount::getFixed(1)) return LV_NAME; if (getForce() == LoopVectorizeHints::FK_Disabled) return LV_NAME; - if (getForce() == LoopVectorizeHints::FK_Undefined && getWidth() == 0) + if (getForce() == LoopVectorizeHints::FK_Undefined && getWidth().isZero()) return LV_NAME; return OptimizationRemarkAnalysis::AlwaysPrint; } @@ -227,7 +233,8 @@ void LoopVectorizeHints::setHint(StringRef Name, Metadata *Arg) { return; unsigned Val = C->getZExtValue(); - Hint *Hints[] = {&Width, &Interleave, &Force, &IsVectorized, &Predicate}; + Hint *Hints[] = {&Width, &Interleave, &Force, + &IsVectorized, &Predicate, &Scalable}; for (auto H : Hints) { if (Name == H->Name) { if (H->validate(Val)) @@ -412,7 +419,11 @@ int LoopVectorizationLegality::isConsecutivePtr(Value *Ptr) { const ValueToValueMap &Strides = getSymbolicStrides() ? *getSymbolicStrides() : ValueToValueMap(); - bool CanAddPredicate = !TheLoop->getHeader()->getParent()->hasOptSize(); + Function *F = TheLoop->getHeader()->getParent(); + bool OptForSize = F->hasOptSize() || + llvm::shouldOptimizeForSize(TheLoop->getHeader(), PSI, BFI, + PGSOQueryType::IRPass); + bool CanAddPredicate = !OptForSize; int Stride = getPtrStride(PSE, Ptr, TheLoop, Strides, CanAddPredicate, false); if (Stride == 1 || Stride == -1) return Stride; @@ -424,7 +435,7 @@ bool LoopVectorizationLegality::isUniform(Value *V) { } bool LoopVectorizationLegality::canVectorizeOuterLoop() { - assert(!TheLoop->empty() && "We are not vectorizing an outer loop."); + assert(!TheLoop->isInnermost() && "We are not vectorizing an outer loop."); // Store the result and return it at the end instead of exiting early, in case // allowExtraAnalysis is used to report multiple reasons for not vectorizing. bool Result = true; @@ -768,7 +779,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { // supported on the target. if (ST->getMetadata(LLVMContext::MD_nontemporal)) { // Arbitrarily try a vector of 2 elements. - auto *VecTy = FixedVectorType::get(T, /*NumElements=*/2); + auto *VecTy = FixedVectorType::get(T, /*NumElts=*/2); assert(VecTy && "did not find vectorized version of stored type"); if (!TTI->isLegalNTStore(VecTy, ST->getAlign())) { reportVectorizationFailure( @@ -783,7 +794,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() { if (LD->getMetadata(LLVMContext::MD_nontemporal)) { // For nontemporal loads, check that a nontemporal vector version is // supported on the target (arbitrarily try a vector of 2 elements). - auto *VecTy = FixedVectorType::get(I.getType(), /*NumElements=*/2); + auto *VecTy = FixedVectorType::get(I.getType(), /*NumElts=*/2); assert(VecTy && "did not find vectorized version of load type"); if (!TTI->isLegalNTLoad(VecTy, LD->getAlign())) { reportVectorizationFailure( @@ -912,7 +923,10 @@ bool LoopVectorizationLegality::blockNeedsPredication(BasicBlock *BB) { } bool LoopVectorizationLegality::blockCanBePredicated( - BasicBlock *BB, SmallPtrSetImpl &SafePtrs, bool PreserveGuards) { + BasicBlock *BB, SmallPtrSetImpl &SafePtrs, + SmallPtrSetImpl &MaskedOp, + SmallPtrSetImpl &ConditionalAssumes, + bool PreserveGuards) const { const bool IsAnnotatedParallel = TheLoop->isAnnotatedParallel(); for (Instruction &I : *BB) { @@ -930,6 +944,12 @@ bool LoopVectorizationLegality::blockCanBePredicated( continue; } + // Do not let llvm.experimental.noalias.scope.decl block the vectorization. + // TODO: there might be cases that it should block the vectorization. Let's + // ignore those for now. + if (isa(&I)) + continue; + // We might be able to hoist the load. if (I.mayReadFromMemory()) { auto *LI = dyn_cast(&I); @@ -999,7 +1019,7 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() { ScalarEvolution &SE = *PSE.getSE(); for (Instruction &I : *BB) { LoadInst *LI = dyn_cast(&I); - if (LI && !mustSuppressSpeculation(*LI) && + if (LI && !LI->getType()->isVectorTy() && !mustSuppressSpeculation(*LI) && isDereferenceableAndAlignedInLoop(LI, TheLoop, SE, *DT)) SafePointers.insert(LI->getPointerOperand()); } @@ -1019,7 +1039,8 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() { // We must be able to predicate all blocks that need to be predicated. if (blockNeedsPredication(BB)) { - if (!blockCanBePredicated(BB, SafePointers)) { + if (!blockCanBePredicated(BB, SafePointers, MaskedOp, + ConditionalAssumes)) { reportVectorizationFailure( "Control flow cannot be substituted for a select", "control flow cannot be substituted for a select", @@ -1044,7 +1065,7 @@ bool LoopVectorizationLegality::canVectorizeWithIfConvert() { // Helper function to canVectorizeLoopNestCFG. bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp, bool UseVPlanNativePath) { - assert((UseVPlanNativePath || Lp->empty()) && + assert((UseVPlanNativePath || Lp->isInnermost()) && "VPlan-native path is not enabled."); // TODO: ORE should be improved to show more accurate information when an @@ -1080,22 +1101,14 @@ bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp, return false; } - // We must have a single exiting block. - if (!Lp->getExitingBlock()) { - reportVectorizationFailure("The loop must have an exiting block", - "loop control flow is not understood by vectorizer", - "CFGNotUnderstood", ORE, TheLoop); - if (DoExtraAnalysis) - Result = false; - else - return false; - } - - // We only handle bottom-tested loops, i.e. loop in which the condition is - // checked at the end of each iteration. With that we can assume that all - // instructions in the loop are executed the same number of times. - if (Lp->getExitingBlock() != Lp->getLoopLatch()) { - reportVectorizationFailure("The exiting block is not the loop latch", + // We currently must have a single "exit block" after the loop. Note that + // multiple "exiting blocks" inside the loop are allowed, provided they all + // reach the single exit block. + // TODO: This restriction can be relaxed in the near future, it's here solely + // to allow separation of changes for review. We need to generalize the phi + // update logic in a number of places. + if (!Lp->getUniqueExitBlock()) { + reportVectorizationFailure("The loop must have a unique exit block", "loop control flow is not understood by vectorizer", "CFGNotUnderstood", ORE, TheLoop); if (DoExtraAnalysis) @@ -1103,7 +1116,6 @@ bool LoopVectorizationLegality::canVectorizeLoopCFG(Loop *Lp, else return false; } - return Result; } @@ -1154,7 +1166,7 @@ bool LoopVectorizationLegality::canVectorize(bool UseVPlanNativePath) { // Specific checks for outer loops. We skip the remaining legal checks at this // point because they don't support outer loops. - if (!TheLoop->empty()) { + if (!TheLoop->isInnermost()) { assert(UseVPlanNativePath && "VPlan-native path is not enabled."); if (!canVectorizeOuterLoop()) { @@ -1171,7 +1183,7 @@ bool LoopVectorizationLegality::canVectorize(bool UseVPlanNativePath) { return Result; } - assert(TheLoop->empty() && "Inner loop expected."); + assert(TheLoop->isInnermost() && "Inner loop expected."); // Check if we can if-convert non-single-bb loops. unsigned NumBlocks = TheLoop->getNumBlocks(); if (NumBlocks != 1 && !canVectorizeWithIfConvert()) { @@ -1246,10 +1258,10 @@ bool LoopVectorizationLegality::prepareToFoldTailByMasking() { Instruction *UI = cast(U); if (TheLoop->contains(UI)) continue; - reportVectorizationFailure( - "Cannot fold tail by masking, loop has an outside user for", - "Cannot fold tail by masking in the presence of live outs.", - "LiveOutFoldingTailByMasking", ORE, TheLoop, UI); + LLVM_DEBUG( + dbgs() + << "LV: Cannot fold tail by masking, loop has an outside user for " + << *UI << "\n"); return false; } } @@ -1257,20 +1269,26 @@ bool LoopVectorizationLegality::prepareToFoldTailByMasking() { // The list of pointers that we can safely read and write to remains empty. SmallPtrSet SafePointers; + SmallPtrSet TmpMaskedOp; + SmallPtrSet TmpConditionalAssumes; + // Check and mark all blocks for predication, including those that ordinarily // do not need predication such as the header block. for (BasicBlock *BB : TheLoop->blocks()) { - if (!blockCanBePredicated(BB, SafePointers, /* MaskAllLoads= */ true)) { - reportVectorizationFailure( - "Cannot fold tail by masking as required", - "control flow cannot be substituted for a select", - "NoCFGForSelect", ORE, TheLoop, - BB->getTerminator()); + if (!blockCanBePredicated(BB, SafePointers, TmpMaskedOp, + TmpConditionalAssumes, + /* MaskAllLoads= */ true)) { + LLVM_DEBUG(dbgs() << "LV: Cannot fold tail by masking as requested.\n"); return false; } } LLVM_DEBUG(dbgs() << "LV: can fold tail by masking.\n"); + + MaskedOp.insert(TmpMaskedOp.begin(), TmpMaskedOp.end()); + ConditionalAssumes.insert(TmpConditionalAssumes.begin(), + TmpConditionalAssumes.end()); + return true; } diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h index 8dd06983cd84..1795470fa58c 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h +++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h @@ -34,6 +34,7 @@ namespace llvm { class LoopVectorizationLegality; class LoopVectorizationCostModel; class PredicatedScalarEvolution; +class VPRecipeBuilder; /// VPlan-based builder utility analogous to IRBuilder. class VPBuilder { @@ -171,16 +172,22 @@ public: /// Information about vectorization costs struct VectorizationFactor { // Vector width with best cost - unsigned Width; + ElementCount Width; // Cost of the loop with that width unsigned Cost; // Width 1 means no vectorization, cost 0 means uncomputed cost. - static VectorizationFactor Disabled() { return {1, 0}; } + static VectorizationFactor Disabled() { + return {ElementCount::getFixed(1), 0}; + } bool operator==(const VectorizationFactor &rhs) const { return Width == rhs.Width && Cost == rhs.Cost; } + + bool operator!=(const VectorizationFactor &rhs) const { + return !(*this == rhs); + } }; /// Planner drives the vectorization process after having passed @@ -226,7 +233,10 @@ class LoopVectorizationPlanner { /// A builder used to construct the current plan. VPBuilder Builder; - unsigned BestVF = 0; + /// The best number of elements of the vector types used in the + /// transformed loop. BestVF = None means that vectorization is + /// disabled. + Optional BestVF = None; unsigned BestUF = 0; public: @@ -241,14 +251,14 @@ public: /// Plan how to best vectorize, return the best VF and its cost, or None if /// vectorization and interleaving should be avoided up front. - Optional plan(unsigned UserVF, unsigned UserIC); + Optional plan(ElementCount UserVF, unsigned UserIC); /// Use the VPlan-native path to plan how to best vectorize, return the best /// VF and its cost. - VectorizationFactor planInVPlanNativePath(unsigned UserVF); + VectorizationFactor planInVPlanNativePath(ElementCount UserVF); /// Finalize the best decision and dispose of all other VPlans. - void setBestPlan(unsigned VF, unsigned UF); + void setBestPlan(ElementCount VF, unsigned UF); /// Generate the IR code for the body of the vectorized loop according to the /// best selected VPlan. @@ -259,11 +269,21 @@ public: O << *Plan; } + /// Look through the existing plans and return true if we have one with all + /// the vectorization factors in question. + bool hasPlanWithVFs(const ArrayRef VFs) const { + return any_of(VPlans, [&](const VPlanPtr &Plan) { + return all_of(VFs, [&](const ElementCount &VF) { + return Plan->hasVF(VF); + }); + }); + } + /// Test a \p Predicate on a \p Range of VF's. Return the value of applying /// \p Predicate on Range.Start, possibly decreasing Range.End such that the /// returned value holds for the entire \p Range. static bool - getDecisionAndClampRange(const std::function &Predicate, + getDecisionAndClampRange(const std::function &Predicate, VFRange &Range); protected: @@ -275,7 +295,7 @@ protected: /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, /// according to the information gathered by Legal when it checked if it is /// legal to vectorize the loop. - void buildVPlans(unsigned MinVF, unsigned MaxVF); + void buildVPlans(ElementCount MinVF, ElementCount MaxVF); private: /// Build a VPlan according to the information gathered by Legal. \return a @@ -286,14 +306,20 @@ private: /// Build a VPlan using VPRecipes according to the information gather by /// Legal. This method is only used for the legacy inner loop vectorizer. VPlanPtr buildVPlanWithVPRecipes( - VFRange &Range, SmallPtrSetImpl &NeedDef, - SmallPtrSetImpl &DeadInstructions, + VFRange &Range, SmallPtrSetImpl &DeadInstructions, const DenseMap &SinkAfter); /// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive, /// according to the information gathered by Legal when it checked if it is /// legal to vectorize the loop. This method creates VPlans using VPRecipes. - void buildVPlansWithVPRecipes(unsigned MinVF, unsigned MaxVF); + void buildVPlansWithVPRecipes(ElementCount MinVF, ElementCount MaxVF); + + /// Adjust the recipes for any inloop reductions. The chain of instructions + /// leading from the loop exit instr to the phi need to be converted to + /// reductions, with one operand being vector and the other being the scalar + /// reduction chain. + void adjustRecipesForInLoopReductions(VPlanPtr &Plan, + VPRecipeBuilder &RecipeBuilder); }; } // namespace llvm diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp index 35af8e425778..ea0d7673edf6 100644 --- a/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ b/llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -130,6 +130,7 @@ #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/InstructionCost.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" @@ -157,18 +158,37 @@ using namespace llvm; #define LV_NAME "loop-vectorize" #define DEBUG_TYPE LV_NAME +#ifndef NDEBUG +const char VerboseDebug[] = DEBUG_TYPE "-verbose"; +#endif + /// @{ /// Metadata attribute names -static const char *const LLVMLoopVectorizeFollowupAll = - "llvm.loop.vectorize.followup_all"; -static const char *const LLVMLoopVectorizeFollowupVectorized = +const char LLVMLoopVectorizeFollowupAll[] = "llvm.loop.vectorize.followup_all"; +const char LLVMLoopVectorizeFollowupVectorized[] = "llvm.loop.vectorize.followup_vectorized"; -static const char *const LLVMLoopVectorizeFollowupEpilogue = +const char LLVMLoopVectorizeFollowupEpilogue[] = "llvm.loop.vectorize.followup_epilogue"; /// @} STATISTIC(LoopsVectorized, "Number of loops vectorized"); STATISTIC(LoopsAnalyzed, "Number of loops analyzed for vectorization"); +STATISTIC(LoopsEpilogueVectorized, "Number of epilogues vectorized"); + +static cl::opt EnableEpilogueVectorization( + "enable-epilogue-vectorization", cl::init(true), cl::Hidden, + cl::desc("Enable vectorization of epilogue loops.")); + +static cl::opt EpilogueVectorizationForceVF( + "epilogue-vectorization-force-VF", cl::init(1), cl::Hidden, + cl::desc("When epilogue vectorization is enabled, and a value greater than " + "1 is specified, forces the given VF for all applicable epilogue " + "loops.")); + +static cl::opt EpilogueVectorizationMinVF( + "epilogue-vectorization-minimum-VF", cl::init(16), cl::Hidden, + cl::desc("Only loops with vectorization factor equal to or larger than " + "the specified value are considered for epilogue vectorization.")); /// Loops with a known constant trip count below this number are vectorized only /// if no scalar iteration overheads are incurred. @@ -178,13 +198,36 @@ static cl::opt TinyTripCountVectorThreshold( "value are vectorized only if no scalar iteration overheads " "are incurred.")); -// Indicates that an epilogue is undesired, predication is preferred. -// This means that the vectorizer will try to fold the loop-tail (epilogue) -// into the loop and predicate the loop body accordingly. -static cl::opt PreferPredicateOverEpilog( - "prefer-predicate-over-epilog", cl::init(false), cl::Hidden, - cl::desc("Indicate that an epilogue is undesired, predication should be " - "used instead.")); +// Option prefer-predicate-over-epilogue indicates that an epilogue is undesired, +// that predication is preferred, and this lists all options. I.e., the +// vectorizer will try to fold the tail-loop (epilogue) into the vector body +// and predicate the instructions accordingly. If tail-folding fails, there are +// different fallback strategies depending on these values: +namespace PreferPredicateTy { + enum Option { + ScalarEpilogue = 0, + PredicateElseScalarEpilogue, + PredicateOrDontVectorize + }; +} // namespace PreferPredicateTy + +static cl::opt PreferPredicateOverEpilogue( + "prefer-predicate-over-epilogue", + cl::init(PreferPredicateTy::ScalarEpilogue), + cl::Hidden, + cl::desc("Tail-folding and predication preferences over creating a scalar " + "epilogue loop."), + cl::values(clEnumValN(PreferPredicateTy::ScalarEpilogue, + "scalar-epilogue", + "Don't tail-predicate loops, create scalar epilogue"), + clEnumValN(PreferPredicateTy::PredicateElseScalarEpilogue, + "predicate-else-scalar-epilogue", + "prefer tail-folding, create scalar epilogue if tail " + "folding fails."), + clEnumValN(PreferPredicateTy::PredicateOrDontVectorize, + "predicate-dont-vectorize", + "prefers tail-folding, don't attempt vectorization if " + "tail-folding fails."))); static cl::opt MaximizeBandwidth( "vectorizer-maximize-bandwidth", cl::init(false), cl::Hidden, @@ -196,7 +239,7 @@ static cl::opt EnableInterleavedMemAccesses( cl::desc("Enable vectorization on interleaved memory accesses in a loop")); /// An interleave-group may need masking if it resides in a block that needs -/// predication, or in order to mask away gaps. +/// predication, or in order to mask away gaps. static cl::opt EnableMaskedInterleavedMemAccesses( "enable-masked-interleaved-mem-accesses", cl::init(false), cl::Hidden, cl::desc("Enable vectorization on masked interleaved memory accesses in a loop")); @@ -230,6 +273,12 @@ static cl::opt ForceTargetInstructionCost( "an instruction to a single constant value. Mostly " "useful for getting consistent testing.")); +static cl::opt ForceTargetSupportsScalableVectors( + "force-target-supports-scalable-vectors", cl::init(false), cl::Hidden, + cl::desc( + "Pretend that scalable vectors are supported, even if the target does " + "not support them. This flag should only be used for testing.")); + static cl::opt SmallLoopCost( "small-loop-cost", cl::init(20), cl::Hidden, cl::desc( @@ -247,6 +296,12 @@ static cl::opt EnableLoadStoreRuntimeInterleave( cl::desc( "Enable runtime interleaving until load/store ports are saturated")); +/// Interleave small loops with scalar reductions. +static cl::opt InterleaveSmallLoopScalarReduction( + "interleave-small-loop-scalar-reduction", cl::init(false), cl::Hidden, + cl::desc("Enable interleaving for loops with small iteration counts that " + "contain scalar reductions to expose ILP.")); + /// The number of stores in a loop that are allowed to need predication. static cl::opt NumberOfStoresToPredicate( "vectorize-num-stores-pred", cl::init(1), cl::Hidden, @@ -265,6 +320,17 @@ static cl::opt MaxNestedScalarReductionIC( cl::desc("The maximum interleave count to use when interleaving a scalar " "reduction in a nested loop.")); +static cl::opt + PreferInLoopReductions("prefer-inloop-reductions", cl::init(false), + cl::Hidden, + cl::desc("Prefer in-loop vector reductions, " + "overriding the targets preference.")); + +static cl::opt PreferPredicatedReductionSelect( + "prefer-predicated-reduction-select", cl::init(false), cl::Hidden, + cl::desc( + "Prefer predicating a reduction operation over an after loop select.")); + cl::opt EnableVPlanNativePath( "enable-vplan-native-path", cl::init(false), cl::Hidden, cl::desc("Enable VPlan-native vectorization path with " @@ -307,12 +373,14 @@ static Type *getMemInstValueType(Value *I) { /// A helper function that returns true if the given type is irregular. The /// type is irregular if its allocated size doesn't equal the store size of an /// element of the corresponding vector type at the given vectorization factor. -static bool hasIrregularType(Type *Ty, const DataLayout &DL, unsigned VF) { +static bool hasIrregularType(Type *Ty, const DataLayout &DL, ElementCount VF) { // Determine if an array of VF elements of type Ty is "bitcast compatible" // with a vector. - if (VF > 1) { - auto *VectorTy = FixedVectorType::get(Ty, VF); - return VF * DL.getTypeAllocSize(Ty) != DL.getTypeStoreSize(VectorTy); + if (VF.isVector()) { + auto *VectorTy = VectorType::get(Ty, VF); + return TypeSize::get(VF.getKnownMinValue() * + DL.getTypeAllocSize(Ty).getFixedValue(), + VF.isScalable()) != DL.getTypeStoreSize(VectorTy); } // If the vectorization factor is one, we just check if an array of type Ty @@ -393,29 +461,42 @@ public: LoopInfo *LI, DominatorTree *DT, const TargetLibraryInfo *TLI, const TargetTransformInfo *TTI, AssumptionCache *AC, - OptimizationRemarkEmitter *ORE, unsigned VecWidth, + OptimizationRemarkEmitter *ORE, ElementCount VecWidth, unsigned UnrollFactor, LoopVectorizationLegality *LVL, - LoopVectorizationCostModel *CM) + LoopVectorizationCostModel *CM, BlockFrequencyInfo *BFI, + ProfileSummaryInfo *PSI) : OrigLoop(OrigLoop), PSE(PSE), LI(LI), DT(DT), TLI(TLI), TTI(TTI), AC(AC), ORE(ORE), VF(VecWidth), UF(UnrollFactor), Builder(PSE.getSE()->getContext()), - VectorLoopValueMap(UnrollFactor, VecWidth), Legal(LVL), Cost(CM) {} + VectorLoopValueMap(UnrollFactor, VecWidth), Legal(LVL), Cost(CM), + BFI(BFI), PSI(PSI) { + // Query this against the original loop and save it here because the profile + // of the original loop header may change as the transformation happens. + OptForSizeBasedOnProfile = llvm::shouldOptimizeForSize( + OrigLoop->getHeader(), PSI, BFI, PGSOQueryType::IRPass); + } + virtual ~InnerLoopVectorizer() = default; - /// Create a new empty loop. Unlink the old loop and connect the new one. - /// Return the pre-header block of the new loop. - BasicBlock *createVectorizedLoopSkeleton(); + /// Create a new empty loop that will contain vectorized instructions later + /// on, while the old loop will be used as the scalar remainder. Control flow + /// is generated around the vectorized (and scalar epilogue) loops consisting + /// of various checks and bypasses. Return the pre-header block of the new + /// loop. + /// In the case of epilogue vectorization, this function is overriden to + /// handle the more complex control flow around the loops. + virtual BasicBlock *createVectorizedLoopSkeleton(); /// Widen a single instruction within the innermost loop. - void widenInstruction(Instruction &I, VPUser &Operands, + void widenInstruction(Instruction &I, VPValue *Def, VPUser &Operands, VPTransformState &State); /// Widen a single call instruction within the innermost loop. - void widenCallInstruction(CallInst &I, VPUser &ArgOperands, + void widenCallInstruction(CallInst &I, VPValue *Def, VPUser &ArgOperands, VPTransformState &State); /// Widen a single select instruction within the innermost loop. - void widenSelectInstruction(SelectInst &I, VPUser &Operands, + void widenSelectInstruction(SelectInst &I, VPValue *VPDef, VPUser &Operands, bool InvariantCond, VPTransformState &State); /// Fix the vectorized code, taking care of header phi's, live-outs, and more. @@ -431,14 +512,15 @@ public: /// Vectorize a single GetElementPtrInst based on information gathered and /// decisions taken during planning. - void widenGEP(GetElementPtrInst *GEP, VPUser &Indices, unsigned UF, - unsigned VF, bool IsPtrLoopInvariant, + void widenGEP(GetElementPtrInst *GEP, VPValue *VPDef, VPUser &Indices, + unsigned UF, ElementCount VF, bool IsPtrLoopInvariant, SmallBitVector &IsIndexLoopInvariant, VPTransformState &State); /// Vectorize a single PHINode in a block. This method handles the induction /// variable canonicalization. It supports both VF = 1 for unrolled loops and /// arbitrary length vectors. - void widenPHIInstruction(Instruction *PN, unsigned UF, unsigned VF); + void widenPHIInstruction(Instruction *PN, RecurrenceDescriptor *RdxDesc, + Value *StartV, unsigned UF, ElementCount VF); /// A helper function to scalarize a single Instruction in the innermost loop. /// Generates a sequence of scalar instances for each lane between \p MinLane @@ -452,7 +534,8 @@ public: /// Widen an integer or floating-point induction variable \p IV. If \p Trunc /// is provided, the integer induction variable will first be truncated to /// the corresponding type. - void widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc = nullptr); + void widenIntOrFpInduction(PHINode *IV, Value *Start, + TruncInst *Trunc = nullptr); /// getOrCreateVectorValue and getOrCreateScalarValue coordinate to generate a /// vector or scalar value on-demand if one is not yet available. When @@ -477,6 +560,10 @@ public: /// value into a vector. Value *getOrCreateVectorValue(Value *V, unsigned Part); + void setVectorValue(Value *Scalar, unsigned Part, Value *Vector) { + VectorLoopValueMap.setVectorValue(Scalar, Part, Vector); + } + /// Return a value in the new loop corresponding to \p V from the original /// loop at unroll and vector indices \p Instance. If the value has been /// vectorized but not scalarized, the necessary extractelement instruction @@ -491,7 +578,9 @@ public: /// BlockInMask is non-null. Use \p State to translate given VPValues to IR /// values in the vectorized loop. void vectorizeInterleaveGroup(const InterleaveGroup *Group, + ArrayRef VPDefs, VPTransformState &State, VPValue *Addr, + ArrayRef StoredValues, VPValue *BlockInMask = nullptr); /// Vectorize Load and Store instructions with the base address given in \p @@ -499,8 +588,8 @@ public: /// non-null. Use \p State to translate given VPValues to IR values in the /// vectorized loop. void vectorizeMemoryInstruction(Instruction *Instr, VPTransformState &State, - VPValue *Addr, VPValue *StoredValue, - VPValue *BlockInMask); + VPValue *Def, VPValue *Addr, + VPValue *StoredValue, VPValue *BlockInMask); /// Set the debug location in the builder using the debug location in /// the instruction. @@ -544,10 +633,11 @@ protected: /// Clear NSW/NUW flags from reduction instructions if necessary. void clearReductionWrapFlags(RecurrenceDescriptor &RdxDesc); - /// The Loop exit block may have single value PHI nodes with some - /// incoming value. While vectorizing we only handled real values - /// that were defined inside the loop and we should have one value for - /// each predecessor of its parent basic block. See PR14725. + /// Fixup the LCSSA phi nodes in the unique exit block. This simply + /// means we need to add the appropriate incoming value from the middle + /// block as exiting edges from the scalar epilogue loop (if present) are + /// already in place, and we exit the vector loop exclusively to the middle + /// block. void fixLCSSAPHIs(); /// Iteratively sink the scalarized operands of a predicated instruction into @@ -586,7 +676,8 @@ protected: /// truncate instruction, instead of widening the original IV, we widen a /// version of the IV truncated to \p EntryVal's type. void createVectorIntOrFpInductionPHI(const InductionDescriptor &II, - Value *Step, Instruction *EntryVal); + Value *Step, Value *Start, + Instruction *EntryVal); /// Returns true if an instruction \p I should be scalarized instead of /// vectorized for the chosen vectorization factor. @@ -654,6 +745,28 @@ protected: const DataLayout &DL, const InductionDescriptor &ID) const; + /// Emit basic blocks (prefixed with \p Prefix) for the iteration check, + /// vector loop preheader, middle block and scalar preheader. Also + /// allocate a loop object for the new vector loop and return it. + Loop *createVectorLoopSkeleton(StringRef Prefix); + + /// Create new phi nodes for the induction variables to resume iteration count + /// in the scalar epilogue, from where the vectorized loop left off (given by + /// \p VectorTripCount). + /// In cases where the loop skeleton is more complicated (eg. epilogue + /// vectorization) and the resume values can come from an additional bypass + /// block, the \p AdditionalBypass pair provides information about the bypass + /// block and the end value on the edge from bypass to this loop. + void createInductionResumeValues( + Loop *L, Value *VectorTripCount, + std::pair AdditionalBypass = {nullptr, nullptr}); + + /// Complete the loop skeleton by adding debug MDs, creating appropriate + /// conditional branches in the middle block, preparing the builder and + /// running the verifier. Take in the vector loop \p L as argument, and return + /// the preheader of the completed vector loop. + BasicBlock *completeLoopSkeleton(Loop *L, MDNode *OrigLoopID); + /// Add additional metadata to \p To that was not present on \p Orig. /// /// Currently this is used to add the noalias annotations based on the @@ -672,6 +785,11 @@ protected: /// vector of instructions. void addMetadata(ArrayRef To, Instruction *From); + /// Allow subclasses to override and print debug traces before/after vplan + /// execution, when trace information is requested. + virtual void printDebugTracesAtStart(){}; + virtual void printDebugTracesAtEnd(){}; + /// The original loop. Loop *OrigLoop; @@ -710,7 +828,7 @@ protected: /// The vectorization SIMD factor to use. Each vector will have this many /// vector elements. - unsigned VF; + ElementCount VF; /// The vectorization unroll factor to use. Each scalar is vectorized to this /// many different vector instructions. @@ -730,7 +848,8 @@ protected: /// Middle Block between the vector and the scalar. BasicBlock *LoopMiddleBlock; - /// The ExitBlock of the scalar loop. + /// The (unique) ExitBlock of the scalar loop. Note that + /// there can be multiple exiting edges reaching this block. BasicBlock *LoopExitBlock; /// The vector loop body. @@ -779,6 +898,14 @@ protected: // Vector of original scalar PHIs whose corresponding widened PHIs need to be // fixed up at the end of vector code generation. SmallVector OrigPHIsToFix; + + /// BFI and PSI are used to check for profile guided size optimizations. + BlockFrequencyInfo *BFI; + ProfileSummaryInfo *PSI; + + // Whether this loop should be optimized for size based on profile guided size + // optimizatios. + bool OptForSizeBasedOnProfile; }; class InnerLoopUnroller : public InnerLoopVectorizer { @@ -789,9 +916,11 @@ public: const TargetTransformInfo *TTI, AssumptionCache *AC, OptimizationRemarkEmitter *ORE, unsigned UnrollFactor, LoopVectorizationLegality *LVL, - LoopVectorizationCostModel *CM) - : InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE, 1, - UnrollFactor, LVL, CM) {} + LoopVectorizationCostModel *CM, BlockFrequencyInfo *BFI, + ProfileSummaryInfo *PSI) + : InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE, + ElementCount::getFixed(1), UnrollFactor, LVL, CM, + BFI, PSI) {} private: Value *getBroadcastInstrs(Value *V) override; @@ -801,6 +930,128 @@ private: Value *reverseVector(Value *Vec) override; }; +/// Encapsulate information regarding vectorization of a loop and its epilogue. +/// This information is meant to be updated and used across two stages of +/// epilogue vectorization. +struct EpilogueLoopVectorizationInfo { + ElementCount MainLoopVF = ElementCount::getFixed(0); + unsigned MainLoopUF = 0; + ElementCount EpilogueVF = ElementCount::getFixed(0); + unsigned EpilogueUF = 0; + BasicBlock *MainLoopIterationCountCheck = nullptr; + BasicBlock *EpilogueIterationCountCheck = nullptr; + BasicBlock *SCEVSafetyCheck = nullptr; + BasicBlock *MemSafetyCheck = nullptr; + Value *TripCount = nullptr; + Value *VectorTripCount = nullptr; + + EpilogueLoopVectorizationInfo(unsigned MVF, unsigned MUF, unsigned EVF, + unsigned EUF) + : MainLoopVF(ElementCount::getFixed(MVF)), MainLoopUF(MUF), + EpilogueVF(ElementCount::getFixed(EVF)), EpilogueUF(EUF) { + assert(EUF == 1 && + "A high UF for the epilogue loop is likely not beneficial."); + } +}; + +/// An extension of the inner loop vectorizer that creates a skeleton for a +/// vectorized loop that has its epilogue (residual) also vectorized. +/// The idea is to run the vplan on a given loop twice, firstly to setup the +/// skeleton and vectorize the main loop, and secondly to complete the skeleton +/// from the first step and vectorize the epilogue. This is achieved by +/// deriving two concrete strategy classes from this base class and invoking +/// them in succession from the loop vectorizer planner. +class InnerLoopAndEpilogueVectorizer : public InnerLoopVectorizer { +public: + InnerLoopAndEpilogueVectorizer( + Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI, + DominatorTree *DT, const TargetLibraryInfo *TLI, + const TargetTransformInfo *TTI, AssumptionCache *AC, + OptimizationRemarkEmitter *ORE, EpilogueLoopVectorizationInfo &EPI, + LoopVectorizationLegality *LVL, llvm::LoopVectorizationCostModel *CM, + BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI) + : InnerLoopVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE, + EPI.MainLoopVF, EPI.MainLoopUF, LVL, CM, BFI, PSI), + EPI(EPI) {} + + // Override this function to handle the more complex control flow around the + // three loops. + BasicBlock *createVectorizedLoopSkeleton() final override { + return createEpilogueVectorizedLoopSkeleton(); + } + + /// The interface for creating a vectorized skeleton using one of two + /// different strategies, each corresponding to one execution of the vplan + /// as described above. + virtual BasicBlock *createEpilogueVectorizedLoopSkeleton() = 0; + + /// Holds and updates state information required to vectorize the main loop + /// and its epilogue in two separate passes. This setup helps us avoid + /// regenerating and recomputing runtime safety checks. It also helps us to + /// shorten the iteration-count-check path length for the cases where the + /// iteration count of the loop is so small that the main vector loop is + /// completely skipped. + EpilogueLoopVectorizationInfo &EPI; +}; + +/// A specialized derived class of inner loop vectorizer that performs +/// vectorization of *main* loops in the process of vectorizing loops and their +/// epilogues. +class EpilogueVectorizerMainLoop : public InnerLoopAndEpilogueVectorizer { +public: + EpilogueVectorizerMainLoop( + Loop *OrigLoop, PredicatedScalarEvolution &PSE, LoopInfo *LI, + DominatorTree *DT, const TargetLibraryInfo *TLI, + const TargetTransformInfo *TTI, AssumptionCache *AC, + OptimizationRemarkEmitter *ORE, EpilogueLoopVectorizationInfo &EPI, + LoopVectorizationLegality *LVL, llvm::LoopVectorizationCostModel *CM, + BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI) + : InnerLoopAndEpilogueVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE, + EPI, LVL, CM, BFI, PSI) {} + /// Implements the interface for creating a vectorized skeleton using the + /// *main loop* strategy (ie the first pass of vplan execution). + BasicBlock *createEpilogueVectorizedLoopSkeleton() final override; + +protected: + /// Emits an iteration count bypass check once for the main loop (when \p + /// ForEpilogue is false) and once for the epilogue loop (when \p + /// ForEpilogue is true). + BasicBlock *emitMinimumIterationCountCheck(Loop *L, BasicBlock *Bypass, + bool ForEpilogue); + void printDebugTracesAtStart() override; + void printDebugTracesAtEnd() override; +}; + +// A specialized derived class of inner loop vectorizer that performs +// vectorization of *epilogue* loops in the process of vectorizing loops and +// their epilogues. +class EpilogueVectorizerEpilogueLoop : public InnerLoopAndEpilogueVectorizer { +public: + EpilogueVectorizerEpilogueLoop(Loop *OrigLoop, PredicatedScalarEvolution &PSE, + LoopInfo *LI, DominatorTree *DT, + const TargetLibraryInfo *TLI, + const TargetTransformInfo *TTI, AssumptionCache *AC, + OptimizationRemarkEmitter *ORE, + EpilogueLoopVectorizationInfo &EPI, + LoopVectorizationLegality *LVL, + llvm::LoopVectorizationCostModel *CM, + BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI) + : InnerLoopAndEpilogueVectorizer(OrigLoop, PSE, LI, DT, TLI, TTI, AC, ORE, + EPI, LVL, CM, BFI, PSI) {} + /// Implements the interface for creating a vectorized skeleton using the + /// *epilogue loop* strategy (ie the second pass of vplan execution). + BasicBlock *createEpilogueVectorizedLoopSkeleton() final override; + +protected: + /// Emits an iteration count bypass check after the main vector loop has + /// finished to see if there are any iterations left to execute by either + /// the vector epilogue or the scalar epilogue. + BasicBlock *emitMinimumVectorEpilogueIterCountCheck(Loop *L, + BasicBlock *Bypass, + BasicBlock *Insert); + void printDebugTracesAtStart() override; + void printDebugTracesAtEnd() override; +}; } // end namespace llvm /// Look for a meaningful debug location on the instruction or it's @@ -827,7 +1078,9 @@ void InnerLoopVectorizer::setDebugLocFromInst(IRBuilder<> &B, const Value *Ptr) const DILocation *DIL = Inst->getDebugLoc(); if (DIL && Inst->getFunction()->isDebugInfoForProfiling() && !isa(Inst)) { - auto NewDIL = DIL->cloneByMultiplyingDuplicationFactor(UF * VF); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + auto NewDIL = + DIL->cloneByMultiplyingDuplicationFactor(UF * VF.getKnownMinValue()); if (NewDIL) B.SetCurrentDebugLocation(NewDIL.getValue()); else @@ -881,6 +1134,15 @@ static OptimizationRemarkAnalysis createLVAnalysis(const char *PassName, return R; } +/// Return a value for Step multiplied by VF. +static Value *createStepForVF(IRBuilder<> &B, Constant *Step, ElementCount VF) { + assert(isa(Step) && "Expected an integer step"); + Constant *StepVal = ConstantInt::get( + Step->getType(), + cast(Step)->getSExtValue() * VF.getKnownMinValue()); + return VF.isScalable() ? B.CreateVScale(StepVal) : StepVal; +} + namespace llvm { void reportVectorizationFailure(const StringRef DebugMsg, @@ -952,7 +1214,10 @@ enum ScalarEpilogueLowering { CM_ScalarEpilogueNotAllowedLowTripLoop, // Loop hint predicate indicating an epilogue is undesired. - CM_ScalarEpilogueNotNeededUsePredicate + CM_ScalarEpilogueNotNeededUsePredicate, + + // Directive indicating we must either tail fold or not vectorize + CM_ScalarEpilogueNotAllowedUsePredicate }; /// LoopVectorizationCostModel - estimates the expected speedups due to @@ -979,7 +1244,7 @@ public: /// \return An upper bound for the vectorization factor, or None if /// vectorization and interleaving should be avoided up front. - Optional computeMaxVF(unsigned UserVF, unsigned UserIC); + Optional computeMaxVF(ElementCount UserVF, unsigned UserIC); /// \return True if runtime checks are required for vectorization, and false /// otherwise. @@ -989,10 +1254,13 @@ public: /// This method checks every power of two up to MaxVF. If UserVF is not ZERO /// then this vectorization factor will be selected if vectorization is /// possible. - VectorizationFactor selectVectorizationFactor(unsigned MaxVF); + VectorizationFactor selectVectorizationFactor(ElementCount MaxVF); + VectorizationFactor + selectEpilogueVectorizationFactor(const ElementCount MaxVF, + const LoopVectorizationPlanner &LVP); /// Setup cost-based decisions for user vectorization factor. - void selectUserVectorizationFactor(unsigned UserVF) { + void selectUserVectorizationFactor(ElementCount UserVF) { collectUniformsAndScalars(UserVF); collectInstsToScalarize(UserVF); } @@ -1006,7 +1274,7 @@ public: /// If interleave count has been specified by metadata it will be returned. /// Otherwise, the interleave count is computed and returned. VF and LoopCost /// are the selected vectorization factor and the cost of the selected VF. - unsigned selectInterleaveCount(unsigned VF, unsigned LoopCost); + unsigned selectInterleaveCount(ElementCount VF, unsigned LoopCost); /// Memory access instruction may be vectorized in more than one way. /// Form of instruction after vectorization depends on cost. @@ -1015,7 +1283,7 @@ public: /// the lists of loop-uniform and loop-scalar instructions. /// The calculated cost is saved with widening decision in order to /// avoid redundant calculations. - void setCostBasedWideningDecision(unsigned VF); + void setCostBasedWideningDecision(ElementCount VF); /// A struct that represents some properties of the register usage /// of a loop. @@ -1030,11 +1298,16 @@ public: /// \return Returns information about the register usages of the loop for the /// given vectorization factors. - SmallVector calculateRegisterUsage(ArrayRef VFs); + SmallVector + calculateRegisterUsage(ArrayRef VFs); /// Collect values we want to ignore in the cost model. void collectValuesToIgnore(); + /// Split reductions into those that happen in the loop, and those that happen + /// outside. In loop reductions are collected into InLoopReductionChains. + void collectInLoopReductions(); + /// \returns The smallest bitwidth each instruction can be represented with. /// The vector equivalents of these instructions should be truncated to this /// type. @@ -1044,8 +1317,9 @@ public: /// \returns True if it is more profitable to scalarize instruction \p I for /// vectorization factor \p VF. - bool isProfitableToScalarize(Instruction *I, unsigned VF) const { - assert(VF > 1 && "Profitable to scalarize relevant only for VF > 1."); + bool isProfitableToScalarize(Instruction *I, ElementCount VF) const { + assert(VF.isVector() && + "Profitable to scalarize relevant only for VF > 1."); // Cost model is not run in the VPlan-native path - return conservative // result until this changes. @@ -1059,8 +1333,8 @@ public: } /// Returns true if \p I is known to be uniform after vectorization. - bool isUniformAfterVectorization(Instruction *I, unsigned VF) const { - if (VF == 1) + bool isUniformAfterVectorization(Instruction *I, ElementCount VF) const { + if (VF.isScalar()) return true; // Cost model is not run in the VPlan-native path - return conservative @@ -1075,8 +1349,8 @@ public: } /// Returns true if \p I is known to be scalar after vectorization. - bool isScalarAfterVectorization(Instruction *I, unsigned VF) const { - if (VF == 1) + bool isScalarAfterVectorization(Instruction *I, ElementCount VF) const { + if (VF.isScalar()) return true; // Cost model is not run in the VPlan-native path - return conservative @@ -1092,8 +1366,8 @@ public: /// \returns True if instruction \p I can be truncated to a smaller bitwidth /// for vectorization factor \p VF. - bool canTruncateToMinimalBitwidth(Instruction *I, unsigned VF) const { - return VF > 1 && MinBWs.find(I) != MinBWs.end() && + bool canTruncateToMinimalBitwidth(Instruction *I, ElementCount VF) const { + return VF.isVector() && MinBWs.find(I) != MinBWs.end() && !isProfitableToScalarize(I, VF) && !isScalarAfterVectorization(I, VF); } @@ -1110,17 +1384,18 @@ public: /// Save vectorization decision \p W and \p Cost taken by the cost model for /// instruction \p I and vector width \p VF. - void setWideningDecision(Instruction *I, unsigned VF, InstWidening W, - unsigned Cost) { - assert(VF >= 2 && "Expected VF >=2"); + void setWideningDecision(Instruction *I, ElementCount VF, InstWidening W, + InstructionCost Cost) { + assert(VF.isVector() && "Expected VF >=2"); WideningDecisions[std::make_pair(I, VF)] = std::make_pair(W, Cost); } /// Save vectorization decision \p W and \p Cost taken by the cost model for /// interleaving group \p Grp and vector width \p VF. - void setWideningDecision(const InterleaveGroup *Grp, unsigned VF, - InstWidening W, unsigned Cost) { - assert(VF >= 2 && "Expected VF >=2"); + void setWideningDecision(const InterleaveGroup *Grp, + ElementCount VF, InstWidening W, + InstructionCost Cost) { + assert(VF.isVector() && "Expected VF >=2"); /// Broadcast this decicion to all instructions inside the group. /// But the cost will be assigned to one instruction only. for (unsigned i = 0; i < Grp->getFactor(); ++i) { @@ -1136,15 +1411,14 @@ public: /// Return the cost model decision for the given instruction \p I and vector /// width \p VF. Return CM_Unknown if this instruction did not pass /// through the cost modeling. - InstWidening getWideningDecision(Instruction *I, unsigned VF) { - assert(VF >= 2 && "Expected VF >=2"); - + InstWidening getWideningDecision(Instruction *I, ElementCount VF) { + assert(VF.isVector() && "Expected VF to be a vector VF"); // Cost model is not run in the VPlan-native path - return conservative // result until this changes. if (EnableVPlanNativePath) return CM_GatherScatter; - std::pair InstOnVF = std::make_pair(I, VF); + std::pair InstOnVF = std::make_pair(I, VF); auto Itr = WideningDecisions.find(InstOnVF); if (Itr == WideningDecisions.end()) return CM_Unknown; @@ -1153,9 +1427,9 @@ public: /// Return the vectorization cost for the given instruction \p I and vector /// width \p VF. - unsigned getWideningCost(Instruction *I, unsigned VF) { - assert(VF >= 2 && "Expected VF >=2"); - std::pair InstOnVF = std::make_pair(I, VF); + InstructionCost getWideningCost(Instruction *I, ElementCount VF) { + assert(VF.isVector() && "Expected VF >=2"); + std::pair InstOnVF = std::make_pair(I, VF); assert(WideningDecisions.find(InstOnVF) != WideningDecisions.end() && "The cost is not calculated"); return WideningDecisions[InstOnVF].second; @@ -1164,7 +1438,7 @@ public: /// Return True if instruction \p I is an optimizable truncate whose operand /// is an induction variable. Such a truncate will be removed by adding a new /// induction variable with the destination type. - bool isOptimizableIVTruncate(Instruction *I, unsigned VF) { + bool isOptimizableIVTruncate(Instruction *I, ElementCount VF) { // If the instruction is not a truncate, return false. auto *Trunc = dyn_cast(I); if (!Trunc) @@ -1189,14 +1463,14 @@ public: /// Collects the instructions to scalarize for each predicated instruction in /// the loop. - void collectInstsToScalarize(unsigned VF); + void collectInstsToScalarize(ElementCount VF); /// Collect Uniform and Scalar values for the given \p VF. /// The sets depend on CM decision for Load/Store instructions /// that may be vectorized as interleave, gather-scatter or scalarized. - void collectUniformsAndScalars(unsigned VF) { + void collectUniformsAndScalars(ElementCount VF) { // Do the analysis once. - if (VF == 1 || Uniforms.find(VF) != Uniforms.end()) + if (VF.isScalar() || Uniforms.find(VF) != Uniforms.end()) return; setCostBasedWideningDecision(VF); collectLoopUniforms(VF); @@ -1247,7 +1521,8 @@ public: /// instructions that may divide by zero. /// If a non-zero VF has been calculated, we check if I will be scalarized /// predication for that VF. - bool isScalarWithPredication(Instruction *I, unsigned VF = 1); + bool isScalarWithPredication(Instruction *I, + ElementCount VF = ElementCount::getFixed(1)); // Returns true if \p I is an instruction that will be predicated either // through scalar predication or masked load/store or masked gather/scatter. @@ -1264,12 +1539,16 @@ public: /// Returns true if \p I is a memory instruction with consecutive memory /// access that can be widened. - bool memoryInstructionCanBeWidened(Instruction *I, unsigned VF = 1); + bool + memoryInstructionCanBeWidened(Instruction *I, + ElementCount VF = ElementCount::getFixed(1)); /// Returns true if \p I is a memory instruction in an interleaved-group /// of memory accesses that can be vectorized with wide vector loads/stores /// and shuffles. - bool interleavedAccessCanBeWidened(Instruction *I, unsigned VF = 1); + bool + interleavedAccessCanBeWidened(Instruction *I, + ElementCount VF = ElementCount::getFixed(1)); /// Check if \p Instr belongs to any interleaved access group. bool isAccessInterleaved(Instruction *Instr) { @@ -1282,11 +1561,16 @@ public: return InterleaveInfo.getInterleaveGroup(Instr); } - /// Returns true if an interleaved group requires a scalar iteration - /// to handle accesses with gaps, and there is nothing preventing us from - /// creating a scalar epilogue. + /// Returns true if we're required to use a scalar epilogue for at least + /// the final iteration of the original loop. bool requiresScalarEpilogue() const { - return isScalarEpilogueAllowed() && InterleaveInfo.requiresScalarEpilogue(); + if (!isScalarEpilogueAllowed()) + return false; + // If we might exit from anywhere but the latch, must run the exiting + // iteration in scalar form. + if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) + return true; + return InterleaveInfo.requiresScalarEpilogue(); } /// Returns true if a scalar epilogue is not allowed due to optsize or a @@ -1302,17 +1586,34 @@ public: return foldTailByMasking() || Legal->blockNeedsPredication(BB); } + /// A SmallMapVector to store the InLoop reduction op chains, mapping phi + /// nodes to the chain of instructions representing the reductions. Uses a + /// MapVector to ensure deterministic iteration order. + using ReductionChainMap = + SmallMapVector, 4>; + + /// Return the chain of instructions representing an inloop reduction. + const ReductionChainMap &getInLoopReductionChains() const { + return InLoopReductionChains; + } + + /// Returns true if the Phi is part of an inloop reduction. + bool isInLoopReduction(PHINode *Phi) const { + return InLoopReductionChains.count(Phi); + } + /// Estimate cost of an intrinsic call instruction CI if it were vectorized /// with factor VF. Return the cost of the instruction, including /// scalarization overhead if it's needed. - unsigned getVectorIntrinsicCost(CallInst *CI, unsigned VF); + InstructionCost getVectorIntrinsicCost(CallInst *CI, ElementCount VF); /// Estimate cost of a call instruction CI if it were vectorized with factor /// VF. Return the cost of the instruction, including scalarization overhead /// if it's needed. The flag NeedToScalarize shows if the call needs to be /// scalarized - /// i.e. either vector version isn't available, or is too expensive. - unsigned getVectorCallCost(CallInst *CI, unsigned VF, bool &NeedToScalarize); + InstructionCost getVectorCallCost(CallInst *CI, ElementCount VF, + bool &NeedToScalarize); /// Invalidates decisions already taken by the cost model. void invalidateCostModelingDecisions() { @@ -1327,7 +1628,8 @@ private: /// \return An upper bound for the vectorization factor, a power-of-2 larger /// than zero. One is returned if vectorization should best be avoided due /// to cost. - unsigned computeFeasibleMaxVF(unsigned ConstTripCount); + ElementCount computeFeasibleMaxVF(unsigned ConstTripCount, + ElementCount UserVF); /// The vectorization cost is a combination of the cost itself and a boolean /// indicating whether any of the contributing operations will actually @@ -1336,47 +1638,54 @@ private: /// is /// false, then all operations will be scalarized (i.e. no vectorization has /// actually taken place). - using VectorizationCostTy = std::pair; + using VectorizationCostTy = std::pair; /// Returns the expected execution cost. The unit of the cost does /// not matter because we use the 'cost' units to compare different /// vector widths. The cost that is returned is *not* normalized by /// the factor width. - VectorizationCostTy expectedCost(unsigned VF); + VectorizationCostTy expectedCost(ElementCount VF); /// Returns the execution time cost of an instruction for a given vector /// width. Vector width of one means scalar. - VectorizationCostTy getInstructionCost(Instruction *I, unsigned VF); + VectorizationCostTy getInstructionCost(Instruction *I, ElementCount VF); /// The cost-computation logic from getInstructionCost which provides /// the vector type as an output parameter. - unsigned getInstructionCost(Instruction *I, unsigned VF, Type *&VectorTy); + InstructionCost getInstructionCost(Instruction *I, ElementCount VF, + Type *&VectorTy); + + /// Return the cost of instructions in an inloop reduction pattern, if I is + /// part of that pattern. + InstructionCost getReductionPatternCost(Instruction *I, ElementCount VF, + Type *VectorTy, + TTI::TargetCostKind CostKind); /// Calculate vectorization cost of memory instruction \p I. - unsigned getMemoryInstructionCost(Instruction *I, unsigned VF); + InstructionCost getMemoryInstructionCost(Instruction *I, ElementCount VF); /// The cost computation for scalarized memory instruction. - unsigned getMemInstScalarizationCost(Instruction *I, unsigned VF); + InstructionCost getMemInstScalarizationCost(Instruction *I, ElementCount VF); /// The cost computation for interleaving group of memory instructions. - unsigned getInterleaveGroupCost(Instruction *I, unsigned VF); + InstructionCost getInterleaveGroupCost(Instruction *I, ElementCount VF); /// The cost computation for Gather/Scatter instruction. - unsigned getGatherScatterCost(Instruction *I, unsigned VF); + InstructionCost getGatherScatterCost(Instruction *I, ElementCount VF); /// The cost computation for widening instruction \p I with consecutive /// memory access. - unsigned getConsecutiveMemOpCost(Instruction *I, unsigned VF); + InstructionCost getConsecutiveMemOpCost(Instruction *I, ElementCount VF); /// The cost calculation for Load/Store instruction \p I with uniform pointer - /// Load: scalar load + broadcast. /// Store: scalar store + (loop invariant value stored? 0 : extract of last /// element) - unsigned getUniformMemOpCost(Instruction *I, unsigned VF); + InstructionCost getUniformMemOpCost(Instruction *I, ElementCount VF); /// Estimate the overhead of scalarizing an instruction. This is a /// convenience wrapper for the type-based getScalarizationOverhead API. - unsigned getScalarizationOverhead(Instruction *I, unsigned VF); + InstructionCost getScalarizationOverhead(Instruction *I, ElementCount VF); /// Returns whether the instruction is a load or store and will be a emitted /// as a vector operation. @@ -1394,7 +1703,7 @@ private: /// A type representing the costs for instructions if they were to be /// scalarized rather than vectorized. The entries are Instruction-Cost /// pairs. - using ScalarCostsTy = DenseMap; + using ScalarCostsTy = DenseMap; /// A set containing all BasicBlocks that are known to present after /// vectorization as a predicated block. @@ -1416,19 +1725,30 @@ private: /// presence of a cost for an instruction in the mapping indicates that the /// instruction will be scalarized when vectorizing with the associated /// vectorization factor. The entries are VF-ScalarCostTy pairs. - DenseMap InstsToScalarize; + DenseMap InstsToScalarize; /// Holds the instructions known to be uniform after vectorization. /// The data is collected per VF. - DenseMap> Uniforms; + DenseMap> Uniforms; /// Holds the instructions known to be scalar after vectorization. /// The data is collected per VF. - DenseMap> Scalars; + DenseMap> Scalars; /// Holds the instructions (address computations) that are forced to be /// scalarized. - DenseMap> ForcedScalars; + DenseMap> ForcedScalars; + + /// PHINodes of the reductions that should be expanded in-loop along with + /// their associated chains of reduction operations, in program order from top + /// (PHI) to bottom + ReductionChainMap InLoopReductionChains; + + /// A Map of inloop reduction operations and their immediate chain operand. + /// FIXME: This can be removed once reductions can be costed correctly in + /// vplan. This was added to allow quick lookup to the inloop operations, + /// without having to loop through InLoopReductionChains. + DenseMap InLoopReductionImmediateChains; /// Returns the expected difference in cost from scalarizing the expression /// feeding a predicated instruction \p PredInst. The instructions to @@ -1436,7 +1756,7 @@ private: /// non-negative return value implies the expression will be scalarized. /// Currently, only single-use chains are considered for scalarization. int computePredInstDiscount(Instruction *PredInst, ScalarCostsTy &ScalarCosts, - unsigned VF); + ElementCount VF); /// Collect the instructions that are uniform after vectorization. An /// instruction is uniform if we represent it with a single scalar value in @@ -1447,27 +1767,28 @@ private: /// scalarized instruction will be represented by VF scalar values in the /// vectorized loop, each corresponding to an iteration of the original /// scalar loop. - void collectLoopUniforms(unsigned VF); + void collectLoopUniforms(ElementCount VF); /// Collect the instructions that are scalar after vectorization. An /// instruction is scalar if it is known to be uniform or will be scalarized /// during vectorization. Non-uniform scalarized instructions will be /// represented by VF values in the vectorized loop, each corresponding to an /// iteration of the original scalar loop. - void collectLoopScalars(unsigned VF); + void collectLoopScalars(ElementCount VF); /// Keeps cost model vectorization decision and cost for instructions. /// Right now it is used for memory instructions only. - using DecisionList = DenseMap, - std::pair>; + using DecisionList = DenseMap, + std::pair>; DecisionList WideningDecisions; /// Returns true if \p V is expected to be vectorized and it needs to be /// extracted. - bool needsExtract(Value *V, unsigned VF) const { + bool needsExtract(Value *V, ElementCount VF) const { Instruction *I = dyn_cast(V); - if (VF == 1 || !I || !TheLoop->contains(I) || TheLoop->isLoopInvariant(I)) + if (VF.isScalar() || !I || !TheLoop->contains(I) || + TheLoop->isLoopInvariant(I)) return false; // Assume we can vectorize V (and hence we need extraction) if the @@ -1482,11 +1803,21 @@ private: /// Returns a range containing only operands needing to be extracted. SmallVector filterExtractingOperands(Instruction::op_range Ops, - unsigned VF) { + ElementCount VF) { return SmallVector(make_filter_range( Ops, [this, VF](Value *V) { return this->needsExtract(V, VF); })); } + /// Determines if we have the infrastructure to vectorize loop \p L and its + /// epilogue, assuming the main loop is vectorized by \p VF. + bool isCandidateForEpilogueVectorization(const Loop &L, + const ElementCount VF) const; + + /// Returns true if epilogue vectorization is considered profitable, and + /// false otherwise. + /// \p VF is the vectorization factor chosen for the original loop. + bool isEpilogueVectorizationProfitable(const ElementCount VF) const; + public: /// The loop that we evaluate. Loop *TheLoop; @@ -1529,6 +1860,9 @@ public: /// Values to ignore in the cost model when VF > 1. SmallPtrSet VecValuesToIgnore; + + /// Profitable vector factors. + SmallVector ProfitableVFs; }; } // end namespace llvm @@ -1549,7 +1883,7 @@ public: // representation for pragma 'omp simd' is introduced. static bool isExplicitVecOuterLoop(Loop *OuterLp, OptimizationRemarkEmitter *ORE) { - assert(!OuterLp->empty() && "This is not an outer loop"); + assert(!OuterLp->isInnermost() && "This is not an outer loop"); LoopVectorizeHints Hints(OuterLp, true /*DisableInterleaving*/, *ORE); // Only outer loops with an explicit vectorization hint are supported. @@ -1582,7 +1916,7 @@ static void collectSupportedLoops(Loop &L, LoopInfo *LI, // now, only collect outer loops that have explicit vectorization hints. If we // are stress testing the VPlan H-CFG construction, we collect the outermost // loop of every loop nest. - if (L.empty() || VPlanBuildStressTest || + if (L.isInnermost() || VPlanBuildStressTest || (EnableVPlanNativePath && isExplicitVecOuterLoop(&L, ORE))) { LoopBlocksRPO RPOT(&L); RPOT.perform(LI); @@ -1696,10 +2030,10 @@ Value *InnerLoopVectorizer::getBroadcastInstrs(Value *V) { } void InnerLoopVectorizer::createVectorIntOrFpInductionPHI( - const InductionDescriptor &II, Value *Step, Instruction *EntryVal) { + const InductionDescriptor &II, Value *Step, Value *Start, + Instruction *EntryVal) { assert((isa(EntryVal) || isa(EntryVal)) && "Expected either an induction phi-node or a truncate of it!"); - Value *Start = II.getStartValue(); // Construct the initial value of the vector IV in the vector loop preheader auto CurrIP = Builder.saveIP(); @@ -1729,7 +2063,8 @@ void InnerLoopVectorizer::createVectorIntOrFpInductionPHI( // Multiply the vectorization factor by the step using integer or // floating-point arithmetic as appropriate. - Value *ConstVF = getSignedIntOrFpConstant(Step->getType(), VF); + Value *ConstVF = + getSignedIntOrFpConstant(Step->getType(), VF.getKnownMinValue()); Value *Mul = addFastMathFlag(Builder.CreateBinOp(MulOp, Step, ConstVF)); // Create a vector splat to use in the induction update. @@ -1737,10 +2072,10 @@ void InnerLoopVectorizer::createVectorIntOrFpInductionPHI( // FIXME: If the step is non-constant, we create the vector splat with // IRBuilder. IRBuilder can constant-fold the multiply, but it doesn't // handle a constant vector splat. - Value *SplatVF = - isa(Mul) - ? ConstantVector::getSplat({VF, false}, cast(Mul)) - : Builder.CreateVectorSplat(VF, Mul); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + Value *SplatVF = isa(Mul) + ? ConstantVector::getSplat(VF, cast(Mul)) + : Builder.CreateVectorSplat(VF, Mul); Builder.restoreIP(CurrIP); // We may need to add the step a number of times, depending on the unroll @@ -1816,7 +2151,8 @@ void InnerLoopVectorizer::recordVectorLoopValueForInductionCast( VectorLoopValueMap.setVectorValue(CastInst, Part, VectorLoopVal); } -void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { +void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, Value *Start, + TruncInst *Trunc) { assert((IV->getType()->isIntegerTy() || IV != OldInduction) && "Primary induction variable must have an integer type"); @@ -1874,8 +2210,10 @@ void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { auto CreateSplatIV = [&](Value *ScalarIV, Value *Step) { Value *Broadcasted = getBroadcastInstrs(ScalarIV); for (unsigned Part = 0; Part < UF; ++Part) { + assert(!VF.isScalable() && "scalable vectors not yet supported."); Value *EntryPart = - getStepVector(Broadcasted, VF * Part, Step, ID.getInductionOpcode()); + getStepVector(Broadcasted, VF.getKnownMinValue() * Part, Step, + ID.getInductionOpcode()); VectorLoopValueMap.setVectorValue(EntryVal, Part, EntryPart); if (Trunc) addMetadata(EntryPart, Trunc); @@ -1885,7 +2223,7 @@ void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { // Now do the actual transformations, and start with creating the step value. Value *Step = CreateStepValue(ID.getStep()); - if (VF <= 1) { + if (VF.isZero() || VF.isScalar()) { Value *ScalarIV = CreateScalarIV(Step); CreateSplatIV(ScalarIV, Step); return; @@ -1896,7 +2234,7 @@ void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { // least one user in the loop that is not widened. auto NeedsScalarIV = needsScalarInduction(EntryVal); if (!NeedsScalarIV) { - createVectorIntOrFpInductionPHI(ID, Step, EntryVal); + createVectorIntOrFpInductionPHI(ID, Step, Start, EntryVal); return; } @@ -1904,7 +2242,7 @@ void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { // create the phi node, we will splat the scalar induction variable in each // loop iteration. if (!shouldScalarizeInstruction(EntryVal)) { - createVectorIntOrFpInductionPHI(ID, Step, EntryVal); + createVectorIntOrFpInductionPHI(ID, Step, Start, EntryVal); Value *ScalarIV = CreateScalarIV(Step); // Create scalar steps that can be used by instructions we will later // scalarize. Note that the addition of the scalar steps will not increase @@ -1926,7 +2264,7 @@ void InnerLoopVectorizer::widenIntOrFpInduction(PHINode *IV, TruncInst *Trunc) { Value *InnerLoopVectorizer::getStepVector(Value *Val, int StartIdx, Value *Step, Instruction::BinaryOps BinOp) { // Create and check the types. - auto *ValVTy = cast(Val->getType()); + auto *ValVTy = cast(Val->getType()); int VLen = ValVTy->getNumElements(); Type *STy = Val->getType()->getScalarType(); @@ -1983,8 +2321,7 @@ void InnerLoopVectorizer::buildScalarSteps(Value *ScalarIV, Value *Step, Instruction *EntryVal, const InductionDescriptor &ID) { // We shouldn't have to build scalar steps if we aren't vectorizing. - assert(VF > 1 && "VF should be greater than one"); - + assert(VF.isVector() && "VF should be greater than one"); // Get the value type and ensure it and the step have the same integer type. Type *ScalarIVTy = ScalarIV->getType()->getScalarType(); assert(ScalarIVTy == Step->getType() && @@ -2006,12 +2343,27 @@ void InnerLoopVectorizer::buildScalarSteps(Value *ScalarIV, Value *Step, // iteration. If EntryVal is uniform, we only need to generate the first // lane. Otherwise, we generate all VF values. unsigned Lanes = - Cost->isUniformAfterVectorization(cast(EntryVal), VF) ? 1 - : VF; + Cost->isUniformAfterVectorization(cast(EntryVal), VF) + ? 1 + : VF.getKnownMinValue(); + assert((!VF.isScalable() || Lanes == 1) && + "Should never scalarize a scalable vector"); // Compute the scalar steps and save the results in VectorLoopValueMap. for (unsigned Part = 0; Part < UF; ++Part) { for (unsigned Lane = 0; Lane < Lanes; ++Lane) { - auto *StartIdx = getSignedIntOrFpConstant(ScalarIVTy, VF * Part + Lane); + auto *IntStepTy = IntegerType::get(ScalarIVTy->getContext(), + ScalarIVTy->getScalarSizeInBits()); + Value *StartIdx = + createStepForVF(Builder, ConstantInt::get(IntStepTy, Part), VF); + if (ScalarIVTy->isFloatingPointTy()) + StartIdx = Builder.CreateSIToFP(StartIdx, ScalarIVTy); + StartIdx = addFastMathFlag(Builder.CreateBinOp( + AddOp, StartIdx, getSignedIntOrFpConstant(ScalarIVTy, Lane))); + // The step returned by `createStepForVF` is a runtime-evaluated value + // when VF is scalable. Otherwise, it should be folded into a Constant. + assert((VF.isScalable() || isa(StartIdx)) && + "Expected StartIdx to be folded to a constant when VF is not " + "scalable"); auto *Mul = addFastMathFlag(Builder.CreateBinOp(MulOp, StartIdx, Step)); auto *Add = addFastMathFlag(Builder.CreateBinOp(AddOp, ScalarIV, Mul)); VectorLoopValueMap.setScalarValue(EntryVal, {Part, Lane}, Add); @@ -2045,7 +2397,7 @@ Value *InnerLoopVectorizer::getOrCreateVectorValue(Value *V, unsigned Part) { // If we aren't vectorizing, we can just copy the scalar map values over to // the vector map. - if (VF == 1) { + if (VF.isScalar()) { VectorLoopValueMap.setVectorValue(V, Part, ScalarValue); return ScalarValue; } @@ -2054,7 +2406,11 @@ Value *InnerLoopVectorizer::getOrCreateVectorValue(Value *V, unsigned Part) { // is known to be uniform after vectorization, this corresponds to lane zero // of the Part unroll iteration. Otherwise, the last instruction is the one // we created for the last vector lane of the Part unroll iteration. - unsigned LastLane = Cost->isUniformAfterVectorization(I, VF) ? 0 : VF - 1; + unsigned LastLane = Cost->isUniformAfterVectorization(I, VF) + ? 0 + : VF.getKnownMinValue() - 1; + assert((!VF.isScalable() || LastLane == 0) && + "Scalable vectorization can't lead to any scalarized values."); auto *LastInst = cast( VectorLoopValueMap.getScalarValue(V, {Part, LastLane})); @@ -2075,10 +2431,11 @@ Value *InnerLoopVectorizer::getOrCreateVectorValue(Value *V, unsigned Part) { VectorValue = getBroadcastInstrs(ScalarValue); VectorLoopValueMap.setVectorValue(V, Part, VectorValue); } else { - // Initialize packing with insertelements to start from undef. - Value *Undef = UndefValue::get(FixedVectorType::get(V->getType(), VF)); - VectorLoopValueMap.setVectorValue(V, Part, Undef); - for (unsigned Lane = 0; Lane < VF; ++Lane) + // Initialize packing with insertelements to start from poison. + assert(!VF.isScalable() && "VF is assumed to be non scalable."); + Value *Poison = PoisonValue::get(VectorType::get(V->getType(), VF)); + VectorLoopValueMap.setVectorValue(V, Part, Poison); + for (unsigned Lane = 0; Lane < VF.getKnownMinValue(); ++Lane) packScalarIntoVectorValue(V, {Part, Lane}); VectorValue = VectorLoopValueMap.getVectorValue(V, Part); } @@ -2117,7 +2474,7 @@ InnerLoopVectorizer::getOrCreateScalarValue(Value *V, // extractelement instruction. auto *U = getOrCreateVectorValue(V, Instance.Part); if (!U->getType()->isVectorTy()) { - assert(VF == 1 && "Value not scalarized has non-vector type"); + assert(VF.isScalar() && "Value not scalarized has non-vector type"); return U; } @@ -2142,12 +2499,12 @@ void InnerLoopVectorizer::packScalarIntoVectorValue( Value *InnerLoopVectorizer::reverseVector(Value *Vec) { assert(Vec->getType()->isVectorTy() && "Invalid type"); + assert(!VF.isScalable() && "Cannot reverse scalable vectors"); SmallVector ShuffleMask; - for (unsigned i = 0; i < VF; ++i) - ShuffleMask.push_back(VF - i - 1); + for (unsigned i = 0; i < VF.getKnownMinValue(); ++i) + ShuffleMask.push_back(VF.getKnownMinValue() - i - 1); - return Builder.CreateShuffleVector(Vec, UndefValue::get(Vec->getType()), - ShuffleMask, "reverse"); + return Builder.CreateShuffleVector(Vec, ShuffleMask, "reverse"); } // Return whether we allow using masked interleave-groups (for dealing with @@ -2172,9 +2529,9 @@ static bool useMaskedInterleavedAccesses(const TargetTransformInfo &TTI) { // } // To: // %wide.vec = load <12 x i32> ; Read 4 tuples of R,G,B -// %R.vec = shuffle %wide.vec, undef, <0, 3, 6, 9> ; R elements -// %G.vec = shuffle %wide.vec, undef, <1, 4, 7, 10> ; G elements -// %B.vec = shuffle %wide.vec, undef, <2, 5, 8, 11> ; B elements +// %R.vec = shuffle %wide.vec, poison, <0, 3, 6, 9> ; R elements +// %G.vec = shuffle %wide.vec, poison, <1, 4, 7, 10> ; G elements +// %B.vec = shuffle %wide.vec, poison, <2, 5, 8, 11> ; B elements // // Or translate following interleaved store group (factor = 3): // for (i = 0; i < N; i+=3) { @@ -2185,20 +2542,22 @@ static bool useMaskedInterleavedAccesses(const TargetTransformInfo &TTI) { // } // To: // %R_G.vec = shuffle %R.vec, %G.vec, <0, 1, 2, ..., 7> -// %B_U.vec = shuffle %B.vec, undef, <0, 1, 2, 3, u, u, u, u> +// %B_U.vec = shuffle %B.vec, poison, <0, 1, 2, 3, u, u, u, u> // %interleaved.vec = shuffle %R_G.vec, %B_U.vec, // <0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11> ; Interleave R,G,B elements // store <12 x i32> %interleaved.vec ; Write 4 tuples of R,G,B void InnerLoopVectorizer::vectorizeInterleaveGroup( - const InterleaveGroup *Group, VPTransformState &State, - VPValue *Addr, VPValue *BlockInMask) { + const InterleaveGroup *Group, ArrayRef VPDefs, + VPTransformState &State, VPValue *Addr, ArrayRef StoredValues, + VPValue *BlockInMask) { Instruction *Instr = Group->getInsertPos(); const DataLayout &DL = Instr->getModule()->getDataLayout(); // Prepare for the vector type of the interleaved load/store. Type *ScalarTy = getMemInstValueType(Instr); unsigned InterleaveFactor = Group->getFactor(); - auto *VecTy = FixedVectorType::get(ScalarTy, InterleaveFactor * VF); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + auto *VecTy = VectorType::get(ScalarTy, VF * InterleaveFactor); // Prepare for the new pointers. SmallVector AddrParts; @@ -2214,8 +2573,10 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( // pointer operand of the interleaved access is supposed to be uniform. For // uniform instructions, we're only required to generate a value for the // first vector lane in each unroll iteration. + assert(!VF.isScalable() && + "scalable vector reverse operation is not implemented"); if (Group->isReverse()) - Index += (VF - 1) * Group->getFactor(); + Index += (VF.getKnownMinValue() - 1) * Group->getFactor(); for (unsigned Part = 0; Part < UF; Part++) { Value *AddrPart = State.get(Addr, {Part, 0}); @@ -2246,11 +2607,12 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( } setDebugLocFromInst(Builder, Instr); - Value *UndefVec = UndefValue::get(VecTy); + Value *PoisonVec = PoisonValue::get(VecTy); Value *MaskForGaps = nullptr; if (Group->requiresScalarEpilogue() && !Cost->isScalarEpilogueAllowed()) { - MaskForGaps = createBitMaskForGaps(Builder, VF, *Group); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + MaskForGaps = createBitMaskForGaps(Builder, VF.getKnownMinValue(), *Group); assert(MaskForGaps && "Mask for Gaps is required but it is null"); } @@ -2266,10 +2628,11 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( Value *GroupMask = MaskForGaps; if (BlockInMask) { Value *BlockInMaskPart = State.get(BlockInMask, Part); - auto *Undefs = UndefValue::get(BlockInMaskPart->getType()); + assert(!VF.isScalable() && "scalable vectors not yet supported."); Value *ShuffledMask = Builder.CreateShuffleVector( - BlockInMaskPart, Undefs, - createReplicatedMask(InterleaveFactor, VF), "interleaved.mask"); + BlockInMaskPart, + createReplicatedMask(InterleaveFactor, VF.getKnownMinValue()), + "interleaved.mask"); GroupMask = MaskForGaps ? Builder.CreateBinOp(Instruction::And, ShuffledMask, MaskForGaps) @@ -2277,7 +2640,7 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( } NewLoad = Builder.CreateMaskedLoad(AddrParts[Part], Group->getAlign(), - GroupMask, UndefVec, "wide.masked.vec"); + GroupMask, PoisonVec, "wide.masked.vec"); } else NewLoad = Builder.CreateAlignedLoad(VecTy, AddrParts[Part], @@ -2288,6 +2651,7 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( // For each member in the group, shuffle out the appropriate data from the // wide loads. + unsigned J = 0; for (unsigned I = 0; I < InterleaveFactor; ++I) { Instruction *Member = Group->getMember(I); @@ -2295,28 +2659,33 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( if (!Member) continue; - auto StrideMask = createStrideMask(I, InterleaveFactor, VF); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + auto StrideMask = + createStrideMask(I, InterleaveFactor, VF.getKnownMinValue()); for (unsigned Part = 0; Part < UF; Part++) { Value *StridedVec = Builder.CreateShuffleVector( - NewLoads[Part], UndefVec, StrideMask, "strided.vec"); + NewLoads[Part], StrideMask, "strided.vec"); // If this member has different type, cast the result type. if (Member->getType() != ScalarTy) { - VectorType *OtherVTy = FixedVectorType::get(Member->getType(), VF); + assert(!VF.isScalable() && "VF is assumed to be non scalable."); + VectorType *OtherVTy = VectorType::get(Member->getType(), VF); StridedVec = createBitOrPointerCast(StridedVec, OtherVTy, DL); } if (Group->isReverse()) StridedVec = reverseVector(StridedVec); - VectorLoopValueMap.setVectorValue(Member, Part, StridedVec); + State.set(VPDefs[J], Member, StridedVec, Part); } + ++J; } return; } // The sub vector type for current instruction. - auto *SubVT = FixedVectorType::get(ScalarTy, VF); + assert(!VF.isScalable() && "VF is assumed to be non scalable."); + auto *SubVT = VectorType::get(ScalarTy, VF); // Vectorize the interleaved store group. for (unsigned Part = 0; Part < UF; Part++) { @@ -2324,11 +2693,10 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( SmallVector StoredVecs; for (unsigned i = 0; i < InterleaveFactor; i++) { // Interleaved store group doesn't allow a gap, so each index has a member - Instruction *Member = Group->getMember(i); - assert(Member && "Fail to get a member from an interleaved store group"); + assert(Group->getMember(i) && "Fail to get a member from an interleaved store group"); + + Value *StoredVec = State.get(StoredValues[i], Part); - Value *StoredVec = getOrCreateVectorValue( - cast(Member)->getValueOperand(), Part); if (Group->isReverse()) StoredVec = reverseVector(StoredVec); @@ -2344,16 +2712,17 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( Value *WideVec = concatenateVectors(Builder, StoredVecs); // Interleave the elements in the wide vector. + assert(!VF.isScalable() && "scalable vectors not yet supported."); Value *IVec = Builder.CreateShuffleVector( - WideVec, UndefVec, createInterleaveMask(VF, InterleaveFactor), + WideVec, createInterleaveMask(VF.getKnownMinValue(), InterleaveFactor), "interleaved.vec"); Instruction *NewStoreInstr; if (BlockInMask) { Value *BlockInMaskPart = State.get(BlockInMask, Part); - auto *Undefs = UndefValue::get(BlockInMaskPart->getType()); Value *ShuffledMask = Builder.CreateShuffleVector( - BlockInMaskPart, Undefs, createReplicatedMask(InterleaveFactor, VF), + BlockInMaskPart, + createReplicatedMask(InterleaveFactor, VF.getKnownMinValue()), "interleaved.mask"); NewStoreInstr = Builder.CreateMaskedStore( IVec, AddrParts[Part], Group->getAlign(), ShuffledMask); @@ -2366,11 +2735,9 @@ void InnerLoopVectorizer::vectorizeInterleaveGroup( } } -void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr, - VPTransformState &State, - VPValue *Addr, - VPValue *StoredValue, - VPValue *BlockInMask) { +void InnerLoopVectorizer::vectorizeMemoryInstruction( + Instruction *Instr, VPTransformState &State, VPValue *Def, VPValue *Addr, + VPValue *StoredValue, VPValue *BlockInMask) { // Attempt to issue a wide load. LoadInst *LI = dyn_cast(Instr); StoreInst *SI = dyn_cast(Instr); @@ -2387,7 +2754,8 @@ void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr, "CM decision is not to widen the memory instruction"); Type *ScalarDataTy = getMemInstValueType(Instr); - auto *DataTy = FixedVectorType::get(ScalarDataTy, VF); + + auto *DataTy = VectorType::get(ScalarDataTy, VF); const Align Alignment = getLoadStoreAlignment(Instr); // Determine if the pointer operand of the access is either consecutive or @@ -2419,19 +2787,23 @@ void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr, InBounds = gep->isInBounds(); if (Reverse) { + assert(!VF.isScalable() && + "Reversing vectors is not yet supported for scalable vectors."); + // If the address is consecutive but reversed, then the // wide store needs to start at the last vector element. - PartPtr = cast( - Builder.CreateGEP(ScalarDataTy, Ptr, Builder.getInt32(-Part * VF))); + PartPtr = cast(Builder.CreateGEP( + ScalarDataTy, Ptr, Builder.getInt32(-Part * VF.getKnownMinValue()))); PartPtr->setIsInBounds(InBounds); - PartPtr = cast( - Builder.CreateGEP(ScalarDataTy, PartPtr, Builder.getInt32(1 - VF))); + PartPtr = cast(Builder.CreateGEP( + ScalarDataTy, PartPtr, Builder.getInt32(1 - VF.getKnownMinValue()))); PartPtr->setIsInBounds(InBounds); if (isMaskRequired) // Reverse of a null all-one mask is a null mask. BlockInMaskParts[Part] = reverseVector(BlockInMaskParts[Part]); } else { + Value *Increment = createStepForVF(Builder, Builder.getInt32(Part), VF); PartPtr = cast( - Builder.CreateGEP(ScalarDataTy, Ptr, Builder.getInt32(Part * VF))); + Builder.CreateGEP(ScalarDataTy, Ptr, Increment)); PartPtr->setIsInBounds(InBounds); } @@ -2486,7 +2858,7 @@ void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr, auto *VecPtr = CreateVecPtr(Part, State.get(Addr, {0, 0})); if (isMaskRequired) NewLI = Builder.CreateMaskedLoad( - VecPtr, Alignment, BlockInMaskParts[Part], UndefValue::get(DataTy), + VecPtr, Alignment, BlockInMaskParts[Part], PoisonValue::get(DataTy), "wide.masked.load"); else NewLI = @@ -2497,7 +2869,8 @@ void InnerLoopVectorizer::vectorizeMemoryInstruction(Instruction *Instr, if (Reverse) NewLI = reverseVector(NewLI); } - VectorLoopValueMap.setVectorValue(Instr, Part, NewLI); + + State.set(Def, Instr, NewLI, Part); } } @@ -2507,6 +2880,12 @@ void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr, VPUser &User, VPTransformState &State) { assert(!Instr->getType()->isAggregateType() && "Can't handle vectors"); + // llvm.experimental.noalias.scope.decl intrinsics must only be duplicated for + // the first lane and part. + if (isa(Instr)) + if (Instance.Lane != 0 || Instance.Part != 0) + return; + setDebugLocFromInst(Builder, Instr); // Does this instruction return a value ? @@ -2519,7 +2898,12 @@ void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr, VPUser &User, // Replace the operands of the cloned instructions with their scalar // equivalents in the new loop. for (unsigned op = 0, e = User.getNumOperands(); op != e; ++op) { - auto *NewOp = State.get(User.getOperand(op), Instance); + auto *Operand = dyn_cast(Instr->getOperand(op)); + auto InputInstance = Instance; + if (!Operand || !OrigLoop->contains(Operand) || + (Cost->isUniformAfterVectorization(Operand, State.VF))) + InputInstance.Lane = 0; + auto *NewOp = State.get(User.getOperand(op), InputInstance); Cloned->setOperand(op, NewOp); } addNewMetadata(Cloned, Instr); @@ -2527,7 +2911,9 @@ void InnerLoopVectorizer::scalarizeInstruction(Instruction *Instr, VPUser &User, // Place the cloned scalar in the new loop. Builder.Insert(Cloned); - // Add the cloned scalar to the scalar map entry. + // TODO: Set result for VPValue of VPReciplicateRecipe. This requires + // representing scalar values in VPTransformState. Add the cloned scalar to + // the scalar map entry. VectorLoopValueMap.setScalarValue(Instr, Instance, Cloned); // If we just cloned a new assumption, add it the assumption cache. @@ -2564,7 +2950,7 @@ PHINode *InnerLoopVectorizer::createInductionVariable(Loop *L, Value *Start, Induction->addIncoming(Next, Latch); // Create the compare. Value *ICmp = Builder.CreateICmpEQ(Next, End); - Builder.CreateCondBr(ICmp, L->getExitBlock(), Header); + Builder.CreateCondBr(ICmp, L->getUniqueExitBlock(), Header); // Now we have two terminators. Remove the old one from the block. Latch->getTerminator()->eraseFromParent(); @@ -2581,7 +2967,7 @@ Value *InnerLoopVectorizer::getOrCreateTripCount(Loop *L) { // Find the loop boundaries. ScalarEvolution *SE = PSE.getSE(); const SCEV *BackedgeTakenCount = PSE.getBackedgeTakenCount(); - assert(BackedgeTakenCount != SE->getCouldNotCompute() && + assert(!isa(BackedgeTakenCount) && "Invalid loop count"); Type *IdxTy = Legal->getWidestInductionType(); @@ -2627,7 +3013,8 @@ Value *InnerLoopVectorizer::getOrCreateVectorTripCount(Loop *L) { IRBuilder<> Builder(L->getLoopPreheader()->getTerminator()); Type *Ty = TC->getType(); - Constant *Step = ConstantInt::get(Ty, VF * UF); + // This is where we can make the step a runtime constant. + Value *Step = createStepForVF(Builder, ConstantInt::get(Ty, UF), VF); // If the tail is to be folded by masking, round the number of iterations N // up to a multiple of Step instead of rounding down. This is done by first @@ -2636,9 +3023,12 @@ Value *InnerLoopVectorizer::getOrCreateVectorTripCount(Loop *L) { // that it starts at zero and its Step is a power of two; the loop will then // exit, with the last early-exit vector comparison also producing all-true. if (Cost->foldTailByMasking()) { - assert(isPowerOf2_32(VF * UF) && + assert(isPowerOf2_32(VF.getKnownMinValue() * UF) && "VF*UF must be a power of 2 when folding tail by masking"); - TC = Builder.CreateAdd(TC, ConstantInt::get(Ty, VF * UF - 1), "n.rnd.up"); + assert(!VF.isScalable() && + "Tail folding not yet supported for scalable vectors"); + TC = Builder.CreateAdd( + TC, ConstantInt::get(Ty, VF.getKnownMinValue() * UF - 1), "n.rnd.up"); } // Now we need to generate the expression for the part of the loop that the @@ -2648,14 +3038,18 @@ Value *InnerLoopVectorizer::getOrCreateVectorTripCount(Loop *L) { // unroll factor (number of SIMD instructions). Value *R = Builder.CreateURem(TC, Step, "n.mod.vf"); - // If there is a non-reversed interleaved group that may speculatively access - // memory out-of-bounds, we need to ensure that there will be at least one - // iteration of the scalar epilogue loop. Thus, if the step evenly divides + // There are two cases where we need to ensure (at least) the last iteration + // runs in the scalar remainder loop. Thus, if the step evenly divides // the trip count, we set the remainder to be equal to the step. If the step // does not evenly divide the trip count, no adjustment is necessary since // there will already be scalar iterations. Note that the minimum iterations - // check ensures that N >= Step. - if (VF > 1 && Cost->requiresScalarEpilogue()) { + // check ensures that N >= Step. The cases are: + // 1) If there is a non-reversed interleaved group that may speculatively + // access memory out-of-bounds. + // 2) If any instruction may follow a conditionally taken exit. That is, if + // the loop contains multiple exiting blocks, or a single exiting block + // which is not the latch. + if (VF.isVector() && Cost->requiresScalarEpilogue()) { auto *IsZero = Builder.CreateICmpEQ(R, ConstantInt::get(R->getType(), 0)); R = Builder.CreateSelect(IsZero, Step, R); } @@ -2668,17 +3062,18 @@ Value *InnerLoopVectorizer::getOrCreateVectorTripCount(Loop *L) { Value *InnerLoopVectorizer::createBitOrPointerCast(Value *V, VectorType *DstVTy, const DataLayout &DL) { // Verify that V is a vector type with same number of elements as DstVTy. - unsigned VF = DstVTy->getNumElements(); - VectorType *SrcVecTy = cast(V->getType()); + auto *DstFVTy = cast(DstVTy); + unsigned VF = DstFVTy->getNumElements(); + auto *SrcVecTy = cast(V->getType()); assert((VF == SrcVecTy->getNumElements()) && "Vector dimensions do not match"); Type *SrcElemTy = SrcVecTy->getElementType(); - Type *DstElemTy = DstVTy->getElementType(); + Type *DstElemTy = DstFVTy->getElementType(); assert((DL.getTypeSizeInBits(SrcElemTy) == DL.getTypeSizeInBits(DstElemTy)) && "Vector elements must have same size"); // Do a direct cast if element types are castable. if (CastInst::isBitOrNoopPointerCastable(SrcElemTy, DstElemTy, DL)) { - return Builder.CreateBitOrPointerCast(V, DstVTy); + return Builder.CreateBitOrPointerCast(V, DstFVTy); } // V cannot be directly casted to desired vector type. // May happen when V is a floating point vector but DstVTy is a vector of @@ -2692,7 +3087,7 @@ Value *InnerLoopVectorizer::createBitOrPointerCast(Value *V, VectorType *DstVTy, IntegerType::getIntNTy(V->getContext(), DL.getTypeSizeInBits(SrcElemTy)); auto *VecIntTy = FixedVectorType::get(IntTy, VF); Value *CastVal = Builder.CreateBitOrPointerCast(V, VecIntTy); - return Builder.CreateBitOrPointerCast(CastVal, DstVTy); + return Builder.CreateBitOrPointerCast(CastVal, DstFVTy); } void InnerLoopVectorizer::emitMinimumIterationCountCheck(Loop *L, @@ -2713,11 +3108,11 @@ void InnerLoopVectorizer::emitMinimumIterationCountCheck(Loop *L, // If tail is to be folded, vector loop takes care of all iterations. Value *CheckMinIters = Builder.getFalse(); - if (!Cost->foldTailByMasking()) - CheckMinIters = Builder.CreateICmp( - P, Count, ConstantInt::get(Count->getType(), VF * UF), - "min.iters.check"); - + if (!Cost->foldTailByMasking()) { + Value *Step = + createStepForVF(Builder, ConstantInt::get(Count->getType(), UF), VF); + CheckMinIters = Builder.CreateICmp(P, Count, Step, "min.iters.check"); + } // Create new preheader for vector loop. LoopVectorPreHeader = SplitBlock(TCCheckBlock, TCCheckBlock->getTerminator(), DT, LI, nullptr, @@ -2754,7 +3149,9 @@ void InnerLoopVectorizer::emitSCEVChecks(Loop *L, BasicBlock *Bypass) { if (C->isZero()) return; - assert(!SCEVCheckBlock->getParent()->hasOptSize() && + assert(!(SCEVCheckBlock->getParent()->hasOptSize() || + (OptForSizeBasedOnProfile && + Cost->Hints->getForce() != LoopVectorizeHints::FK_Enabled)) && "Cannot SCEV check stride or overflow when optimizing for size"); SCEVCheckBlock->setName("vector.scevcheck"); @@ -2792,15 +3189,8 @@ void InnerLoopVectorizer::emitMemRuntimeChecks(Loop *L, BasicBlock *Bypass) { const auto &RtPtrChecking = *LAI->getRuntimePointerChecking(); if (!RtPtrChecking.Need) return; - Instruction *FirstCheckInst; - Instruction *MemRuntimeCheck; - std::tie(FirstCheckInst, MemRuntimeCheck) = - addRuntimeChecks(MemCheckBlock->getTerminator(), OrigLoop, - RtPtrChecking.getChecks(), RtPtrChecking.getSE()); - assert(MemRuntimeCheck && "no RT checks generated although RtPtrChecking " - "claimed checks are required"); - if (MemCheckBlock->getParent()->hasOptSize()) { + if (MemCheckBlock->getParent()->hasOptSize() || OptForSizeBasedOnProfile) { assert(Cost->Hints->getForce() == LoopVectorizeHints::FK_Enabled && "Cannot emit memory checks when optimizing for size, unless forced " "to vectorize."); @@ -2820,22 +3210,33 @@ void InnerLoopVectorizer::emitMemRuntimeChecks(Loop *L, BasicBlock *Bypass) { SplitBlock(MemCheckBlock, MemCheckBlock->getTerminator(), DT, LI, nullptr, "vector.ph"); + auto *CondBranch = cast( + Builder.CreateCondBr(Builder.getTrue(), Bypass, LoopVectorPreHeader)); + ReplaceInstWithInst(MemCheckBlock->getTerminator(), CondBranch); + LoopBypassBlocks.push_back(MemCheckBlock); + AddedSafetyChecks = true; + // Update dominator only if this is first RT check. if (LoopBypassBlocks.empty()) { DT->changeImmediateDominator(Bypass, MemCheckBlock); DT->changeImmediateDominator(LoopExitBlock, MemCheckBlock); } - ReplaceInstWithInst( - MemCheckBlock->getTerminator(), - BranchInst::Create(Bypass, LoopVectorPreHeader, MemRuntimeCheck)); - LoopBypassBlocks.push_back(MemCheckBlock); - AddedSafetyChecks = true; + Instruction *FirstCheckInst; + Instruction *MemRuntimeCheck; + std::tie(FirstCheckInst, MemRuntimeCheck) = + addRuntimeChecks(MemCheckBlock->getTerminator(), OrigLoop, + RtPtrChecking.getChecks(), RtPtrChecking.getSE()); + assert(MemRuntimeCheck && "no RT checks generated although RtPtrChecking " + "claimed checks are required"); + CondBranch->setCondition(MemRuntimeCheck); // We currently don't use LoopVersioning for the actual loop cloning but we // still use it to add the noalias metadata. - LVer = std::make_unique(*Legal->getLAI(), OrigLoop, LI, DT, - PSE.getSE()); + LVer = std::make_unique( + *Legal->getLAI(), + Legal->getLAI()->getRuntimePointerChecking()->getChecks(), OrigLoop, LI, + DT, PSE.getSE()); LVer->prepareNoAliasMetadata(); } @@ -2939,74 +3340,35 @@ Value *InnerLoopVectorizer::emitTransformedIndex( llvm_unreachable("invalid enum"); } -BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { - /* - In this function we generate a new loop. The new loop will contain - the vectorized instructions while the old loop will continue to run the - scalar remainder. - - [ ] <-- loop iteration number check. - / | - / v - | [ ] <-- vector loop bypass (may consist of multiple blocks). - | / | - | / v - || [ ] <-- vector pre header. - |/ | - | v - | [ ] \ - | [ ]_| <-- vector loop. - | | - | v - | -[ ] <--- middle-block. - | / | - | / v - -|- >[ ] <--- new preheader. - | | - | v - | [ ] \ - | [ ]_| <-- old scalar loop to handle remainder. - \ | - \ v - >[ ] <-- exit block. - ... - */ - - MDNode *OrigLoopID = OrigLoop->getLoopID(); - - // Some loops have a single integer induction variable, while other loops - // don't. One example is c++ iterators that often have multiple pointer - // induction variables. In the code below we also support a case where we - // don't have a single induction variable. - // - // We try to obtain an induction variable from the original loop as hard - // as possible. However if we don't find one that: - // - is an integer - // - counts from zero, stepping by one - // - is the size of the widest induction variable type - // then we create a new one. - OldInduction = Legal->getPrimaryInduction(); - Type *IdxTy = Legal->getWidestInductionType(); - - // Split the single block loop into the two loop structure described above. +Loop *InnerLoopVectorizer::createVectorLoopSkeleton(StringRef Prefix) { LoopScalarBody = OrigLoop->getHeader(); LoopVectorPreHeader = OrigLoop->getLoopPreheader(); - LoopExitBlock = OrigLoop->getExitBlock(); + LoopExitBlock = OrigLoop->getUniqueExitBlock(); assert(LoopExitBlock && "Must have an exit block"); assert(LoopVectorPreHeader && "Invalid loop structure"); LoopMiddleBlock = SplitBlock(LoopVectorPreHeader, LoopVectorPreHeader->getTerminator(), DT, - LI, nullptr, "middle.block"); + LI, nullptr, Twine(Prefix) + "middle.block"); LoopScalarPreHeader = SplitBlock(LoopMiddleBlock, LoopMiddleBlock->getTerminator(), DT, LI, - nullptr, "scalar.ph"); + nullptr, Twine(Prefix) + "scalar.ph"); + + // Set up branch from middle block to the exit and scalar preheader blocks. + // completeLoopSkeleton will update the condition to use an iteration check, + // if required to decide whether to execute the remainder. + BranchInst *BrInst = + BranchInst::Create(LoopExitBlock, LoopScalarPreHeader, Builder.getTrue()); + auto *ScalarLatchTerm = OrigLoop->getLoopLatch()->getTerminator(); + BrInst->setDebugLoc(ScalarLatchTerm->getDebugLoc()); + ReplaceInstWithInst(LoopMiddleBlock->getTerminator(), BrInst); + // We intentionally don't let SplitBlock to update LoopInfo since // LoopVectorBody should belong to another loop than LoopVectorPreHeader. // LoopVectorBody is explicitly added to the correct place few lines later. LoopVectorBody = SplitBlock(LoopVectorPreHeader, LoopVectorPreHeader->getTerminator(), DT, - nullptr, nullptr, "vector.body"); + nullptr, nullptr, Twine(Prefix) + "vector.body"); // Update dominator for loop exit. DT->changeImmediateDominator(LoopExitBlock, LoopMiddleBlock); @@ -3023,37 +3385,16 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { LI->addTopLevelLoop(Lp); } Lp->addBasicBlockToLoop(LoopVectorBody, *LI); + return Lp; +} - // Find the loop boundaries. - Value *Count = getOrCreateTripCount(Lp); - - Value *StartIdx = ConstantInt::get(IdxTy, 0); - - // Now, compare the new count to zero. If it is zero skip the vector loop and - // jump to the scalar loop. This check also covers the case where the - // backedge-taken count is uint##_max: adding one to it will overflow leading - // to an incorrect trip count of zero. In this (rare) case we will also jump - // to the scalar loop. - emitMinimumIterationCountCheck(Lp, LoopScalarPreHeader); - - // Generate the code to check any assumptions that we've made for SCEV - // expressions. - emitSCEVChecks(Lp, LoopScalarPreHeader); - - // Generate the code that checks in runtime if arrays overlap. We put the - // checks into a separate block to make the more common case of few elements - // faster. - emitMemRuntimeChecks(Lp, LoopScalarPreHeader); - - // Generate the induction variable. - // The loop step is equal to the vectorization factor (num of SIMD elements) - // times the unroll factor (num of SIMD instructions). - Value *CountRoundDown = getOrCreateVectorTripCount(Lp); - Constant *Step = ConstantInt::get(IdxTy, VF * UF); - Induction = - createInductionVariable(Lp, StartIdx, CountRoundDown, Step, - getDebugLocFromInstOrOperands(OldInduction)); - +void InnerLoopVectorizer::createInductionResumeValues( + Loop *L, Value *VectorTripCount, + std::pair AdditionalBypass) { + assert(VectorTripCount && L && "Expected valid arguments"); + assert(((AdditionalBypass.first && AdditionalBypass.second) || + (!AdditionalBypass.first && !AdditionalBypass.second)) && + "Inconsistent information about additional bypass."); // We are going to resume the execution of the scalar loop. // Go over all of the induction variables that we found and fix the // PHIs that are left in the scalar version of the loop. @@ -3061,10 +3402,6 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { // iteration in the vectorized loop. // If we come from a bypass edge then we need to start from the original // start value. - - // This variable saves the new starting index for the scalar loop. It is used - // to test if there are any tail iterations left once the vector loop has - // completed. for (auto &InductionEntry : Legal->getInductionVars()) { PHINode *OrigPhi = InductionEntry.first; InductionDescriptor II = InductionEntry.second; @@ -3076,20 +3413,32 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { // Copy original phi DL over to the new one. BCResumeVal->setDebugLoc(OrigPhi->getDebugLoc()); Value *&EndValue = IVEndValues[OrigPhi]; + Value *EndValueFromAdditionalBypass = AdditionalBypass.second; if (OrigPhi == OldInduction) { // We know what the end value is. - EndValue = CountRoundDown; + EndValue = VectorTripCount; } else { - IRBuilder<> B(Lp->getLoopPreheader()->getTerminator()); + IRBuilder<> B(L->getLoopPreheader()->getTerminator()); Type *StepType = II.getStep()->getType(); Instruction::CastOps CastOp = - CastInst::getCastOpcode(CountRoundDown, true, StepType, true); - Value *CRD = B.CreateCast(CastOp, CountRoundDown, StepType, "cast.crd"); + CastInst::getCastOpcode(VectorTripCount, true, StepType, true); + Value *CRD = B.CreateCast(CastOp, VectorTripCount, StepType, "cast.crd"); const DataLayout &DL = LoopScalarBody->getModule()->getDataLayout(); EndValue = emitTransformedIndex(B, CRD, PSE.getSE(), DL, II); EndValue->setName("ind.end"); - } + // Compute the end value for the additional bypass (if applicable). + if (AdditionalBypass.first) { + B.SetInsertPoint(&(*AdditionalBypass.first->getFirstInsertionPt())); + CastOp = CastInst::getCastOpcode(AdditionalBypass.second, true, + StepType, true); + CRD = + B.CreateCast(CastOp, AdditionalBypass.second, StepType, "cast.crd"); + EndValueFromAdditionalBypass = + emitTransformedIndex(B, CRD, PSE.getSE(), DL, II); + EndValueFromAdditionalBypass->setName("ind.end"); + } + } // The new PHI merges the original incoming value, in case of a bypass, // or the value at the end of the vectorized loop. BCResumeVal->addIncoming(EndValue, LoopMiddleBlock); @@ -3099,42 +3448,44 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { // value. for (BasicBlock *BB : LoopBypassBlocks) BCResumeVal->addIncoming(II.getStartValue(), BB); + + if (AdditionalBypass.first) + BCResumeVal->setIncomingValueForBlock(AdditionalBypass.first, + EndValueFromAdditionalBypass); + OrigPhi->setIncomingValueForBlock(LoopScalarPreHeader, BCResumeVal); } +} + +BasicBlock *InnerLoopVectorizer::completeLoopSkeleton(Loop *L, + MDNode *OrigLoopID) { + assert(L && "Expected valid loop."); - // We need the OrigLoop (scalar loop part) latch terminator to help - // produce correct debug info for the middle block BB instructions. - // The legality check stage guarantees that the loop will have a single - // latch. - assert(isa(OrigLoop->getLoopLatch()->getTerminator()) && - "Scalar loop latch terminator isn't a branch"); - BranchInst *ScalarLatchBr = - cast(OrigLoop->getLoopLatch()->getTerminator()); + // The trip counts should be cached by now. + Value *Count = getOrCreateTripCount(L); + Value *VectorTripCount = getOrCreateVectorTripCount(L); + + auto *ScalarLatchTerm = OrigLoop->getLoopLatch()->getTerminator(); // Add a check in the middle block to see if we have completed // all of the iterations in the first vector loop. // If (N - N%VF) == N, then we *don't* need to run the remainder. // If tail is to be folded, we know we don't need to run the remainder. - Value *CmpN = Builder.getTrue(); if (!Cost->foldTailByMasking()) { - CmpN = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, Count, - CountRoundDown, "cmp.n", - LoopMiddleBlock->getTerminator()); + Instruction *CmpN = CmpInst::Create(Instruction::ICmp, CmpInst::ICMP_EQ, + Count, VectorTripCount, "cmp.n", + LoopMiddleBlock->getTerminator()); - // Here we use the same DebugLoc as the scalar loop latch branch instead + // Here we use the same DebugLoc as the scalar loop latch terminator instead // of the corresponding compare because they may have ended up with // different line numbers and we want to avoid awkward line stepping while // debugging. Eg. if the compare has got a line number inside the loop. - cast(CmpN)->setDebugLoc(ScalarLatchBr->getDebugLoc()); + CmpN->setDebugLoc(ScalarLatchTerm->getDebugLoc()); + cast(LoopMiddleBlock->getTerminator())->setCondition(CmpN); } - BranchInst *BrInst = - BranchInst::Create(LoopExitBlock, LoopScalarPreHeader, CmpN); - BrInst->setDebugLoc(ScalarLatchBr->getDebugLoc()); - ReplaceInstWithInst(LoopMiddleBlock->getTerminator(), BrInst); - // Get ready to start creating new instructions into the vectorized body. - assert(LoopVectorPreHeader == Lp->getLoopPreheader() && + assert(LoopVectorPreHeader == L->getLoopPreheader() && "Inconsistent vector loop preheader"); Builder.SetInsertPoint(&*LoopVectorBody->getFirstInsertionPt()); @@ -3142,7 +3493,7 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { makeFollowupLoopID(OrigLoopID, {LLVMLoopVectorizeFollowupAll, LLVMLoopVectorizeFollowupVectorized}); if (VectorizedLoopID.hasValue()) { - Lp->setLoopID(VectorizedLoopID.getValue()); + L->setLoopID(VectorizedLoopID.getValue()); // Do not setAlreadyVectorized if loop attributes have been defined // explicitly. @@ -3152,9 +3503,9 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { // Keep all loop hints from the original loop on the vector loop (we'll // replace the vectorizer-specific hints below). if (MDNode *LID = OrigLoop->getLoopID()) - Lp->setLoopID(LID); + L->setLoopID(LID); - LoopVectorizeHints Hints(Lp, true, *ORE); + LoopVectorizeHints Hints(L, true, *ORE); Hints.setAlreadyVectorized(); #ifdef EXPENSIVE_CHECKS @@ -3165,46 +3516,131 @@ BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { return LoopVectorPreHeader; } -// Fix up external users of the induction variable. At this point, we are -// in LCSSA form, with all external PHIs that use the IV having one input value, -// coming from the remainder loop. We need those PHIs to also have a correct -// value for the IV when arriving directly from the middle block. -void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi, - const InductionDescriptor &II, - Value *CountRoundDown, Value *EndValue, - BasicBlock *MiddleBlock) { - // There are two kinds of external IV usages - those that use the value - // computed in the last iteration (the PHI) and those that use the penultimate - // value (the value that feeds into the phi from the loop latch). - // We allow both, but they, obviously, have different values. - - assert(OrigLoop->getExitBlock() && "Expected a single exit block"); +BasicBlock *InnerLoopVectorizer::createVectorizedLoopSkeleton() { + /* + In this function we generate a new loop. The new loop will contain + the vectorized instructions while the old loop will continue to run the + scalar remainder. - DenseMap MissingVals; + [ ] <-- loop iteration number check. + / | + / v + | [ ] <-- vector loop bypass (may consist of multiple blocks). + | / | + | / v + || [ ] <-- vector pre header. + |/ | + | v + | [ ] \ + | [ ]_| <-- vector loop. + | | + | v + | -[ ] <--- middle-block. + | / | + | / v + -|- >[ ] <--- new preheader. + | | + | v + | [ ] \ + | [ ]_| <-- old scalar loop to handle remainder. + \ | + \ v + >[ ] <-- exit block. + ... + */ - // An external user of the last iteration's value should see the value that - // the remainder loop uses to initialize its own IV. - Value *PostInc = OrigPhi->getIncomingValueForBlock(OrigLoop->getLoopLatch()); - for (User *U : PostInc->users()) { - Instruction *UI = cast(U); - if (!OrigLoop->contains(UI)) { - assert(isa(UI) && "Expected LCSSA form"); - MissingVals[UI] = EndValue; - } - } + // Get the metadata of the original loop before it gets modified. + MDNode *OrigLoopID = OrigLoop->getLoopID(); - // An external user of the penultimate value need to see EndValue - Step. - // The simplest way to get this is to recompute it from the constituent SCEVs, - // that is Start + (Step * (CRD - 1)). - for (User *U : OrigPhi->users()) { - auto *UI = cast(U); - if (!OrigLoop->contains(UI)) { - const DataLayout &DL = - OrigLoop->getHeader()->getModule()->getDataLayout(); - assert(isa(UI) && "Expected LCSSA form"); + // Create an empty vector loop, and prepare basic blocks for the runtime + // checks. + Loop *Lp = createVectorLoopSkeleton(""); - IRBuilder<> B(MiddleBlock->getTerminator()); - Value *CountMinusOne = B.CreateSub( + // Now, compare the new count to zero. If it is zero skip the vector loop and + // jump to the scalar loop. This check also covers the case where the + // backedge-taken count is uint##_max: adding one to it will overflow leading + // to an incorrect trip count of zero. In this (rare) case we will also jump + // to the scalar loop. + emitMinimumIterationCountCheck(Lp, LoopScalarPreHeader); + + // Generate the code to check any assumptions that we've made for SCEV + // expressions. + emitSCEVChecks(Lp, LoopScalarPreHeader); + + // Generate the code that checks in runtime if arrays overlap. We put the + // checks into a separate block to make the more common case of few elements + // faster. + emitMemRuntimeChecks(Lp, LoopScalarPreHeader); + + // Some loops have a single integer induction variable, while other loops + // don't. One example is c++ iterators that often have multiple pointer + // induction variables. In the code below we also support a case where we + // don't have a single induction variable. + // + // We try to obtain an induction variable from the original loop as hard + // as possible. However if we don't find one that: + // - is an integer + // - counts from zero, stepping by one + // - is the size of the widest induction variable type + // then we create a new one. + OldInduction = Legal->getPrimaryInduction(); + Type *IdxTy = Legal->getWidestInductionType(); + Value *StartIdx = ConstantInt::get(IdxTy, 0); + // The loop step is equal to the vectorization factor (num of SIMD elements) + // times the unroll factor (num of SIMD instructions). + Builder.SetInsertPoint(&*Lp->getHeader()->getFirstInsertionPt()); + Value *Step = createStepForVF(Builder, ConstantInt::get(IdxTy, UF), VF); + Value *CountRoundDown = getOrCreateVectorTripCount(Lp); + Induction = + createInductionVariable(Lp, StartIdx, CountRoundDown, Step, + getDebugLocFromInstOrOperands(OldInduction)); + + // Emit phis for the new starting index of the scalar loop. + createInductionResumeValues(Lp, CountRoundDown); + + return completeLoopSkeleton(Lp, OrigLoopID); +} + +// Fix up external users of the induction variable. At this point, we are +// in LCSSA form, with all external PHIs that use the IV having one input value, +// coming from the remainder loop. We need those PHIs to also have a correct +// value for the IV when arriving directly from the middle block. +void InnerLoopVectorizer::fixupIVUsers(PHINode *OrigPhi, + const InductionDescriptor &II, + Value *CountRoundDown, Value *EndValue, + BasicBlock *MiddleBlock) { + // There are two kinds of external IV usages - those that use the value + // computed in the last iteration (the PHI) and those that use the penultimate + // value (the value that feeds into the phi from the loop latch). + // We allow both, but they, obviously, have different values. + + assert(OrigLoop->getUniqueExitBlock() && "Expected a single exit block"); + + DenseMap MissingVals; + + // An external user of the last iteration's value should see the value that + // the remainder loop uses to initialize its own IV. + Value *PostInc = OrigPhi->getIncomingValueForBlock(OrigLoop->getLoopLatch()); + for (User *U : PostInc->users()) { + Instruction *UI = cast(U); + if (!OrigLoop->contains(UI)) { + assert(isa(UI) && "Expected LCSSA form"); + MissingVals[UI] = EndValue; + } + } + + // An external user of the penultimate value need to see EndValue - Step. + // The simplest way to get this is to recompute it from the constituent SCEVs, + // that is Start + (Step * (CRD - 1)). + for (User *U : OrigPhi->users()) { + auto *UI = cast(U); + if (!OrigLoop->contains(UI)) { + const DataLayout &DL = + OrigLoop->getHeader()->getModule()->getDataLayout(); + assert(isa(UI) && "Expected LCSSA form"); + + IRBuilder<> B(MiddleBlock->getTerminator()); + Value *CountMinusOne = B.CreateSub( CountRoundDown, ConstantInt::get(CountRoundDown->getType(), 1)); Value *CMO = !II.getStep()->getType()->isIntegerTy() @@ -3284,9 +3720,10 @@ static void cse(BasicBlock *BB) { } } -unsigned LoopVectorizationCostModel::getVectorCallCost(CallInst *CI, - unsigned VF, - bool &NeedToScalarize) { +InstructionCost +LoopVectorizationCostModel::getVectorCallCost(CallInst *CI, ElementCount VF, + bool &NeedToScalarize) { + assert(!VF.isScalable() && "scalable vectors not yet supported."); Function *F = CI->getCalledFunction(); Type *ScalarRetTy = CI->getType(); SmallVector Tys, ScalarTys; @@ -3297,9 +3734,9 @@ unsigned LoopVectorizationCostModel::getVectorCallCost(CallInst *CI, // to be vectors, so we need to extract individual elements from there, // execute VF scalar calls, and then gather the result into the vector return // value. - unsigned ScalarCallCost = TTI.getCallInstrCost(F, ScalarRetTy, ScalarTys, - TTI::TCK_RecipThroughput); - if (VF == 1) + InstructionCost ScalarCallCost = + TTI.getCallInstrCost(F, ScalarRetTy, ScalarTys, TTI::TCK_RecipThroughput); + if (VF.isScalar()) return ScalarCallCost; // Compute corresponding vector type for return value and arguments. @@ -3309,31 +3746,33 @@ unsigned LoopVectorizationCostModel::getVectorCallCost(CallInst *CI, // Compute costs of unpacking argument values for the scalar calls and // packing the return values to a vector. - unsigned ScalarizationCost = getScalarizationOverhead(CI, VF); + InstructionCost ScalarizationCost = getScalarizationOverhead(CI, VF); - unsigned Cost = ScalarCallCost * VF + ScalarizationCost; + InstructionCost Cost = + ScalarCallCost * VF.getKnownMinValue() + ScalarizationCost; // If we can't emit a vector call for this function, then the currently found // cost is the cost we need to return. NeedToScalarize = true; - VFShape Shape = VFShape::get(*CI, {VF, false}, false /*HasGlobalPred*/); + VFShape Shape = VFShape::get(*CI, VF, false /*HasGlobalPred*/); Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape); if (!TLI || CI->isNoBuiltin() || !VecFunc) return Cost; // If the corresponding vector cost is cheaper, return its cost. - unsigned VectorCallCost = TTI.getCallInstrCost(nullptr, RetTy, Tys, - TTI::TCK_RecipThroughput); + InstructionCost VectorCallCost = + TTI.getCallInstrCost(nullptr, RetTy, Tys, TTI::TCK_RecipThroughput); if (VectorCallCost < Cost) { NeedToScalarize = false; - return VectorCallCost; + Cost = VectorCallCost; } return Cost; } -unsigned LoopVectorizationCostModel::getVectorIntrinsicCost(CallInst *CI, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getVectorIntrinsicCost(CallInst *CI, + ElementCount VF) { Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); assert(ID && "Expected intrinsic call!"); @@ -3373,7 +3812,8 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { Type *ScalarTruncatedTy = IntegerType::get(OriginalTy->getContext(), KV.second); auto *TruncatedTy = FixedVectorType::get( - ScalarTruncatedTy, cast(OriginalTy)->getNumElements()); + ScalarTruncatedTy, + cast(OriginalTy)->getNumElements()); if (TruncatedTy == OriginalTy) continue; @@ -3423,13 +3863,13 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { break; } } else if (auto *SI = dyn_cast(I)) { - auto Elements0 = - cast(SI->getOperand(0)->getType())->getNumElements(); + auto Elements0 = cast(SI->getOperand(0)->getType()) + ->getNumElements(); auto *O0 = B.CreateZExtOrTrunc( SI->getOperand(0), FixedVectorType::get(ScalarTruncatedTy, Elements0)); - auto Elements1 = - cast(SI->getOperand(1)->getType())->getNumElements(); + auto Elements1 = cast(SI->getOperand(1)->getType()) + ->getNumElements(); auto *O1 = B.CreateZExtOrTrunc( SI->getOperand(1), FixedVectorType::get(ScalarTruncatedTy, Elements1)); @@ -3439,16 +3879,16 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { // Don't do anything with the operands, just extend the result. continue; } else if (auto *IE = dyn_cast(I)) { - auto Elements = - cast(IE->getOperand(0)->getType())->getNumElements(); + auto Elements = cast(IE->getOperand(0)->getType()) + ->getNumElements(); auto *O0 = B.CreateZExtOrTrunc( IE->getOperand(0), FixedVectorType::get(ScalarTruncatedTy, Elements)); auto *O1 = B.CreateZExtOrTrunc(IE->getOperand(1), ScalarTruncatedTy); NewI = B.CreateInsertElement(O0, O1, IE->getOperand(2)); } else if (auto *EE = dyn_cast(I)) { - auto Elements = - cast(EE->getOperand(0)->getType())->getNumElements(); + auto Elements = cast(EE->getOperand(0)->getType()) + ->getNumElements(); auto *O0 = B.CreateZExtOrTrunc( EE->getOperand(0), FixedVectorType::get(ScalarTruncatedTy, Elements)); @@ -3490,7 +3930,7 @@ void InnerLoopVectorizer::truncateToMinimalBitwidths() { void InnerLoopVectorizer::fixVectorizedLoop() { // Insert truncates and extends for any truncated instructions as hints to // InstCombine. - if (VF > 1) + if (VF.isVector()) truncateToMinimalBitwidths(); // Fix widened non-induction PHIs by setting up the PHI operands. @@ -3531,9 +3971,13 @@ void InnerLoopVectorizer::fixVectorizedLoop() { // profile is not inherently precise anyway. Note also possible bypass of // vector code caused by legality checks is ignored, assigning all the weight // to the vector loop, optimistically. - setProfileInfoAfterUnrolling(LI->getLoopFor(LoopScalarBody), - LI->getLoopFor(LoopVectorBody), - LI->getLoopFor(LoopScalarBody), VF * UF); + // + // For scalable vectorization we can't know at compile time how many iterations + // of the loop are handled in one vector iteration, so instead assume a pessimistic + // vscale of '1'. + setProfileInfoAfterUnrolling( + LI->getLoopFor(LoopScalarBody), LI->getLoopFor(LoopVectorBody), + LI->getLoopFor(LoopScalarBody), VF.getKnownMinValue() * UF); } void InnerLoopVectorizer::fixCrossIterationPHIs() { @@ -3612,11 +4056,12 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { // Create a vector from the initial value. auto *VectorInit = ScalarInit; - if (VF > 1) { + if (VF.isVector()) { Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator()); + assert(!VF.isScalable() && "VF is assumed to be non scalable."); VectorInit = Builder.CreateInsertElement( - UndefValue::get(FixedVectorType::get(VectorInit->getType(), VF)), - VectorInit, Builder.getInt32(VF - 1), "vector.recur.init"); + PoisonValue::get(VectorType::get(VectorInit->getType(), VF)), VectorInit, + Builder.getInt32(VF.getKnownMinValue() - 1), "vector.recur.init"); } // We constructed a temporary phi node in the first phase of vectorization. @@ -3657,10 +4102,11 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { // We will construct a vector for the recurrence by combining the values for // the current and previous iterations. This is the required shuffle mask. - SmallVector ShuffleMask(VF); - ShuffleMask[0] = VF - 1; - for (unsigned I = 1; I < VF; ++I) - ShuffleMask[I] = I + VF - 1; + assert(!VF.isScalable()); + SmallVector ShuffleMask(VF.getKnownMinValue()); + ShuffleMask[0] = VF.getKnownMinValue() - 1; + for (unsigned I = 1; I < VF.getKnownMinValue(); ++I) + ShuffleMask[I] = I + VF.getKnownMinValue() - 1; // The vector from which to take the initial value for the current iteration // (actual or unrolled). Initially, this is the vector phi node. @@ -3670,9 +4116,10 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { for (unsigned Part = 0; Part < UF; ++Part) { Value *PreviousPart = getOrCreateVectorValue(Previous, Part); Value *PhiPart = VectorLoopValueMap.getVectorValue(Phi, Part); - auto *Shuffle = VF > 1 ? Builder.CreateShuffleVector(Incoming, PreviousPart, - ShuffleMask) - : Incoming; + auto *Shuffle = + VF.isVector() + ? Builder.CreateShuffleVector(Incoming, PreviousPart, ShuffleMask) + : Incoming; PhiPart->replaceAllUsesWith(Shuffle); cast(PhiPart)->eraseFromParent(); VectorLoopValueMap.resetVectorValue(Phi, Part, Shuffle); @@ -3685,10 +4132,11 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { // Extract the last vector element in the middle block. This will be the // initial value for the recurrence when jumping to the scalar loop. auto *ExtractForScalar = Incoming; - if (VF > 1) { + if (VF.isVector()) { Builder.SetInsertPoint(LoopMiddleBlock->getTerminator()); ExtractForScalar = Builder.CreateExtractElement( - ExtractForScalar, Builder.getInt32(VF - 1), "vector.recur.extract"); + ExtractForScalar, Builder.getInt32(VF.getKnownMinValue() - 1), + "vector.recur.extract"); } // Extract the second last element in the middle block if the // Phi is used outside the loop. We need to extract the phi itself @@ -3696,9 +4144,10 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { // will be the value when jumping to the exit block from the LoopMiddleBlock, // when the scalar loop is not run at all. Value *ExtractForPhiUsedOutsideLoop = nullptr; - if (VF > 1) + if (VF.isVector()) ExtractForPhiUsedOutsideLoop = Builder.CreateExtractElement( - Incoming, Builder.getInt32(VF - 2), "vector.recur.extract.for.phi"); + Incoming, Builder.getInt32(VF.getKnownMinValue() - 2), + "vector.recur.extract.for.phi"); // When loop is unrolled without vectorizing, initialize // ExtractForPhiUsedOutsideLoop with the value just prior to unrolled value of // `Incoming`. This is analogous to the vectorized case above: extracting the @@ -3722,69 +4171,31 @@ void InnerLoopVectorizer::fixFirstOrderRecurrence(PHINode *Phi) { // vector recurrence we extracted in the middle block. Since the loop is in // LCSSA form, we just need to find all the phi nodes for the original scalar // recurrence in the exit block, and then add an edge for the middle block. - for (PHINode &LCSSAPhi : LoopExitBlock->phis()) { - if (LCSSAPhi.getIncomingValue(0) == Phi) { + // Note that LCSSA does not imply single entry when the original scalar loop + // had multiple exiting edges (as we always run the last iteration in the + // scalar epilogue); in that case, the exiting path through middle will be + // dynamically dead and the value picked for the phi doesn't matter. + for (PHINode &LCSSAPhi : LoopExitBlock->phis()) + if (any_of(LCSSAPhi.incoming_values(), + [Phi](Value *V) { return V == Phi; })) LCSSAPhi.addIncoming(ExtractForPhiUsedOutsideLoop, LoopMiddleBlock); - } - } } void InnerLoopVectorizer::fixReduction(PHINode *Phi) { - Constant *Zero = Builder.getInt32(0); - // Get it's reduction variable descriptor. assert(Legal->isReductionVariable(Phi) && "Unable to find the reduction variable"); RecurrenceDescriptor RdxDesc = Legal->getReductionVars()[Phi]; - RecurrenceDescriptor::RecurrenceKind RK = RdxDesc.getRecurrenceKind(); + RecurKind RK = RdxDesc.getRecurrenceKind(); TrackingVH ReductionStartValue = RdxDesc.getRecurrenceStartValue(); Instruction *LoopExitInst = RdxDesc.getLoopExitInstr(); - RecurrenceDescriptor::MinMaxRecurrenceKind MinMaxKind = - RdxDesc.getMinMaxRecurrenceKind(); setDebugLocFromInst(Builder, ReductionStartValue); - - // We need to generate a reduction vector from the incoming scalar. - // To do so, we need to generate the 'identity' vector and override - // one of the elements with the incoming scalar reduction. We need - // to do it in the vector-loop preheader. - Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator()); + bool IsInLoopReductionPhi = Cost->isInLoopReduction(Phi); // This is the vector-clone of the value that leaves the loop. Type *VecTy = getOrCreateVectorValue(LoopExitInst, 0)->getType(); - // Find the reduction identity variable. Zero for addition, or, xor, - // one for multiplication, -1 for And. - Value *Identity; - Value *VectorStart; - if (RK == RecurrenceDescriptor::RK_IntegerMinMax || - RK == RecurrenceDescriptor::RK_FloatMinMax) { - // MinMax reduction have the start value as their identify. - if (VF == 1) { - VectorStart = Identity = ReductionStartValue; - } else { - VectorStart = Identity = - Builder.CreateVectorSplat(VF, ReductionStartValue, "minmax.ident"); - } - } else { - // Handle other reduction kinds: - Constant *Iden = RecurrenceDescriptor::getRecurrenceIdentity( - RK, VecTy->getScalarType()); - if (VF == 1) { - Identity = Iden; - // This vector is the Identity vector where the first element is the - // incoming scalar reduction. - VectorStart = ReductionStartValue; - } else { - Identity = ConstantVector::getSplat({VF, false}, Iden); - - // This vector is the Identity vector where the first element is the - // incoming scalar reduction. - VectorStart = - Builder.CreateInsertElement(Identity, ReductionStartValue, Zero); - } - } - // Wrap flags are in general invalid after vectorization, clear them. clearReductionWrapFlags(RdxDesc); @@ -3798,10 +4209,6 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { for (unsigned Part = 0; Part < UF; ++Part) { Value *VecRdxPhi = getOrCreateVectorValue(Phi, Part); Value *Val = getOrCreateVectorValue(LoopVal, Part); - // Make sure to add the reduction start value only to the - // first unroll part. - Value *StartVal = (Part == 0) ? VectorStart : Identity; - cast(VecRdxPhi)->addIncoming(StartVal, LoopVectorPreHeader); cast(VecRdxPhi) ->addIncoming(Val, LI->getLoopFor(LoopVectorBody)->getLoopLatch()); } @@ -3816,8 +4223,9 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { // If tail is folded by masking, the vector value to leave the loop should be // a Select choosing between the vectorized LoopExitInst and vectorized Phi, - // instead of the former. - if (Cost->foldTailByMasking()) { + // instead of the former. For an inloop reduction the reduction will already + // be predicated, and does not need to be handled here. + if (Cost->foldTailByMasking() && !IsInLoopReductionPhi) { for (unsigned Part = 0; Part < UF; ++Part) { Value *VecLoopExitInst = VectorLoopValueMap.getVectorValue(LoopExitInst, Part); @@ -3831,14 +4239,31 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { } assert(Sel && "Reduction exit feeds no select"); VectorLoopValueMap.resetVectorValue(LoopExitInst, Part, Sel); + + // If the target can create a predicated operator for the reduction at no + // extra cost in the loop (for example a predicated vadd), it can be + // cheaper for the select to remain in the loop than be sunk out of it, + // and so use the select value for the phi instead of the old + // LoopExitValue. + RecurrenceDescriptor RdxDesc = Legal->getReductionVars()[Phi]; + if (PreferPredicatedReductionSelect || + TTI->preferPredicatedReductionSelect( + RdxDesc.getOpcode(), Phi->getType(), + TargetTransformInfo::ReductionFlags())) { + auto *VecRdxPhi = cast(getOrCreateVectorValue(Phi, Part)); + VecRdxPhi->setIncomingValueForBlock( + LI->getLoopFor(LoopVectorBody)->getLoopLatch(), Sel); + } } } // If the vector reduction can be performed in a smaller type, we truncate // then extend the loop exit value to enable InstCombine to evaluate the // entire expression in the smaller type. - if (VF > 1 && Phi->getType() != RdxDesc.getRecurrenceType()) { - Type *RdxVecTy = FixedVectorType::get(RdxDesc.getRecurrenceType(), VF); + if (VF.isVector() && Phi->getType() != RdxDesc.getRecurrenceType()) { + assert(!IsInLoopReductionPhi && "Unexpected truncated inloop reduction!"); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + Type *RdxVecTy = VectorType::get(RdxDesc.getRecurrenceType(), VF); Builder.SetInsertPoint( LI->getLoopFor(LoopVectorBody)->getLoopLatch()->getTerminator()); VectorParts RdxParts(UF); @@ -3865,7 +4290,7 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { // Reduce all of the unrolled parts into a single vector. Value *ReducedPartRdx = VectorLoopValueMap.getVectorValue(LoopExitInst, 0); - unsigned Op = RecurrenceDescriptor::getRecurrenceBinOp(RK); + unsigned Op = RecurrenceDescriptor::getOpcode(RK); // The middle block terminator has already been assigned a DebugLoc here (the // OrigLoop's single latch terminator). We want the whole middle block to @@ -3884,14 +4309,14 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { ReducedPartRdx, "bin.rdx"), RdxDesc.getFastMathFlags()); else - ReducedPartRdx = createMinMaxOp(Builder, MinMaxKind, ReducedPartRdx, - RdxPart); + ReducedPartRdx = createMinMaxOp(Builder, RK, ReducedPartRdx, RdxPart); } - if (VF > 1) { - bool NoNaN = Legal->hasFunNoNaNAttr(); + // Create the reduction after the loop. Note that inloop reductions create the + // target reduction in the loop using a Reduction recipe. + if (VF.isVector() && !IsInLoopReductionPhi) { ReducedPartRdx = - createTargetReduction(Builder, TTI, RdxDesc, ReducedPartRdx, NoNaN); + createTargetReduction(Builder, TTI, RdxDesc, ReducedPartRdx); // If the reduction can be performed in a smaller type, we need to extend // the reduction to the wider type before we branch to the original loop. if (Phi->getType() != RdxDesc.getRecurrenceType()) @@ -3911,21 +4336,17 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { // Now, we need to fix the users of the reduction variable // inside and outside of the scalar remainder loop. - // We know that the loop is in LCSSA form. We need to update the - // PHI nodes in the exit blocks. - for (PHINode &LCSSAPhi : LoopExitBlock->phis()) { - // All PHINodes need to have a single entry edge, or two if - // we already fixed them. - assert(LCSSAPhi.getNumIncomingValues() < 3 && "Invalid LCSSA PHI"); - // We found a reduction value exit-PHI. Update it with the - // incoming bypass edge. - if (LCSSAPhi.getIncomingValue(0) == LoopExitInst) + // We know that the loop is in LCSSA form. We need to update the PHI nodes + // in the exit blocks. See comment on analogous loop in + // fixFirstOrderRecurrence for a more complete explaination of the logic. + for (PHINode &LCSSAPhi : LoopExitBlock->phis()) + if (any_of(LCSSAPhi.incoming_values(), + [LoopExitInst](Value *V) { return V == LoopExitInst; })) LCSSAPhi.addIncoming(ReducedPartRdx, LoopMiddleBlock); - } // end of the LCSSA phi scan. - // Fix the scalar loop reduction variable with the incoming reduction sum - // from the vector body and from the backedge value. + // Fix the scalar loop reduction variable with the incoming reduction sum + // from the vector body and from the backedge value. int IncomingEdgeBlockIdx = Phi->getBasicBlockIndex(OrigLoop->getLoopLatch()); assert(IncomingEdgeBlockIdx >= 0 && "Invalid block index"); @@ -3937,9 +4358,8 @@ void InnerLoopVectorizer::fixReduction(PHINode *Phi) { void InnerLoopVectorizer::clearReductionWrapFlags( RecurrenceDescriptor &RdxDesc) { - RecurrenceDescriptor::RecurrenceKind RK = RdxDesc.getRecurrenceKind(); - if (RK != RecurrenceDescriptor::RK_IntegerAdd && - RK != RecurrenceDescriptor::RK_IntegerMult) + RecurKind RK = RdxDesc.getRecurrenceKind(); + if (RK != RecurKind::Add && RK != RecurKind::Mul) return; Instruction *LoopExitInstr = RdxDesc.getLoopExitInstr(); @@ -3968,22 +4388,27 @@ void InnerLoopVectorizer::clearReductionWrapFlags( void InnerLoopVectorizer::fixLCSSAPHIs() { for (PHINode &LCSSAPhi : LoopExitBlock->phis()) { - if (LCSSAPhi.getNumIncomingValues() == 1) { - auto *IncomingValue = LCSSAPhi.getIncomingValue(0); - // Non-instruction incoming values will have only one value. - unsigned LastLane = 0; - if (isa(IncomingValue)) - LastLane = Cost->isUniformAfterVectorization( - cast(IncomingValue), VF) - ? 0 - : VF - 1; - // Can be a loop invariant incoming value or the last scalar value to be - // extracted from the vectorized loop. - Builder.SetInsertPoint(LoopMiddleBlock->getTerminator()); - Value *lastIncomingValue = - getOrCreateScalarValue(IncomingValue, { UF - 1, LastLane }); - LCSSAPhi.addIncoming(lastIncomingValue, LoopMiddleBlock); - } + if (LCSSAPhi.getBasicBlockIndex(LoopMiddleBlock) != -1) + // Some phis were already hand updated by the reduction and recurrence + // code above, leave them alone. + continue; + + auto *IncomingValue = LCSSAPhi.getIncomingValue(0); + // Non-instruction incoming values will have only one value. + unsigned LastLane = 0; + if (isa(IncomingValue)) + LastLane = Cost->isUniformAfterVectorization( + cast(IncomingValue), VF) + ? 0 + : VF.getKnownMinValue() - 1; + assert((!VF.isScalable() || LastLane == 0) && + "scalable vectors dont support non-uniform scalars yet"); + // Can be a loop invariant incoming value or the last scalar value to be + // extracted from the vectorized loop. + Builder.SetInsertPoint(LoopMiddleBlock->getTerminator()); + Value *lastIncomingValue = + getOrCreateScalarValue(IncomingValue, { UF - 1, LastLane }); + LCSSAPhi.addIncoming(lastIncomingValue, LoopMiddleBlock); } } @@ -4087,9 +4512,9 @@ void InnerLoopVectorizer::fixNonInductionPHIs() { } } -void InnerLoopVectorizer::widenGEP(GetElementPtrInst *GEP, VPUser &Operands, - unsigned UF, unsigned VF, - bool IsPtrLoopInvariant, +void InnerLoopVectorizer::widenGEP(GetElementPtrInst *GEP, VPValue *VPDef, + VPUser &Operands, unsigned UF, + ElementCount VF, bool IsPtrLoopInvariant, SmallBitVector &IsIndexLoopInvariant, VPTransformState &State) { // Construct a vector GEP by widening the operands of the scalar GEP as @@ -4098,7 +4523,7 @@ void InnerLoopVectorizer::widenGEP(GetElementPtrInst *GEP, VPUser &Operands, // is vector-typed. Thus, to keep the representation compact, we only use // vector-typed operands for loop-varying values. - if (VF > 1 && IsPtrLoopInvariant && IsIndexLoopInvariant.all()) { + if (VF.isVector() && IsPtrLoopInvariant && IsIndexLoopInvariant.all()) { // If we are vectorizing, but the GEP has only loop-invariant operands, // the GEP we build (by only using vector-typed operands for // loop-varying values) would be a scalar pointer. Thus, to ensure we @@ -4114,7 +4539,7 @@ void InnerLoopVectorizer::widenGEP(GetElementPtrInst *GEP, VPUser &Operands, auto *Clone = Builder.Insert(GEP->clone()); for (unsigned Part = 0; Part < UF; ++Part) { Value *EntryPart = Builder.CreateVectorSplat(VF, Clone); - VectorLoopValueMap.setVectorValue(GEP, Part, EntryPart); + State.set(VPDef, GEP, EntryPart, Part); addMetadata(EntryPart, GEP); } } else { @@ -4149,16 +4574,19 @@ void InnerLoopVectorizer::widenGEP(GetElementPtrInst *GEP, VPUser &Operands, ? Builder.CreateInBoundsGEP(GEP->getSourceElementType(), Ptr, Indices) : Builder.CreateGEP(GEP->getSourceElementType(), Ptr, Indices); - assert((VF == 1 || NewGEP->getType()->isVectorTy()) && + assert((VF.isScalar() || NewGEP->getType()->isVectorTy()) && "NewGEP is not a pointer vector"); - VectorLoopValueMap.setVectorValue(GEP, Part, NewGEP); + State.set(VPDef, GEP, NewGEP, Part); addMetadata(NewGEP, GEP); } } } -void InnerLoopVectorizer::widenPHIInstruction(Instruction *PN, unsigned UF, - unsigned VF) { +void InnerLoopVectorizer::widenPHIInstruction(Instruction *PN, + RecurrenceDescriptor *RdxDesc, + Value *StartV, unsigned UF, + ElementCount VF) { + assert(!VF.isScalable() && "scalable vectors not yet supported."); PHINode *P = cast(PN); if (EnableVPlanNativePath) { // Currently we enter here in the VPlan-native path for non-induction @@ -4166,7 +4594,7 @@ void InnerLoopVectorizer::widenPHIInstruction(Instruction *PN, unsigned UF, // Create a vector phi with no operands - the vector phi operands will be // set at the end of vector code generation. Type *VecTy = - (VF == 1) ? PN->getType() : FixedVectorType::get(PN->getType(), VF); + (VF.isScalar()) ? PN->getType() : VectorType::get(PN->getType(), VF); Value *VecPhi = Builder.CreatePHI(VecTy, PN->getNumOperands(), "vec.phi"); VectorLoopValueMap.setVectorValue(P, 0, VecPhi); OrigPHIsToFix.push_back(P); @@ -4181,18 +4609,60 @@ void InnerLoopVectorizer::widenPHIInstruction(Instruction *PN, unsigned UF, // Phi nodes have cycles, so we need to vectorize them in two stages. This is // stage #1: We create a new vector PHI node with no incoming edges. We'll use // this value when we vectorize all of the instructions that use the PHI. - if (Legal->isReductionVariable(P) || Legal->isFirstOrderRecurrence(P)) { + if (RdxDesc || Legal->isFirstOrderRecurrence(P)) { + Value *Iden = nullptr; + bool ScalarPHI = + (VF.isScalar()) || Cost->isInLoopReduction(cast(PN)); + Type *VecTy = + ScalarPHI ? PN->getType() : VectorType::get(PN->getType(), VF); + + if (RdxDesc) { + assert(Legal->isReductionVariable(P) && StartV && + "RdxDesc should only be set for reduction variables; in that case " + "a StartV is also required"); + RecurKind RK = RdxDesc->getRecurrenceKind(); + if (RecurrenceDescriptor::isMinMaxRecurrenceKind(RK)) { + // MinMax reduction have the start value as their identify. + if (ScalarPHI) { + Iden = StartV; + } else { + IRBuilderBase::InsertPointGuard IPBuilder(Builder); + Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator()); + StartV = Iden = Builder.CreateVectorSplat(VF, StartV, "minmax.ident"); + } + } else { + Constant *IdenC = RecurrenceDescriptor::getRecurrenceIdentity( + RK, VecTy->getScalarType()); + Iden = IdenC; + + if (!ScalarPHI) { + Iden = ConstantVector::getSplat(VF, IdenC); + IRBuilderBase::InsertPointGuard IPBuilder(Builder); + Builder.SetInsertPoint(LoopVectorPreHeader->getTerminator()); + Constant *Zero = Builder.getInt32(0); + StartV = Builder.CreateInsertElement(Iden, StartV, Zero); + } + } + } + for (unsigned Part = 0; Part < UF; ++Part) { // This is phase one of vectorizing PHIs. - Type *VecTy = - (VF == 1) ? PN->getType() : FixedVectorType::get(PN->getType(), VF); Value *EntryPart = PHINode::Create( VecTy, 2, "vec.phi", &*LoopVectorBody->getFirstInsertionPt()); VectorLoopValueMap.setVectorValue(P, Part, EntryPart); + if (StartV) { + // Make sure to add the reduction start value only to the + // first unroll part. + Value *StartVal = (Part == 0) ? StartV : Iden; + cast(EntryPart)->addIncoming(StartVal, LoopVectorPreHeader); + } } return; } + assert(!Legal->isReductionVariable(P) && + "reductions should be handled above"); + setDebugLocFromInst(Builder, P); // This PHINode must be an induction variable. @@ -4213,26 +4683,74 @@ void InnerLoopVectorizer::widenPHIInstruction(Instruction *PN, unsigned UF, case InductionDescriptor::IK_PtrInduction: { // Handle the pointer induction variable case. assert(P->getType()->isPointerTy() && "Unexpected type."); - // This is the normalized GEP that starts counting at zero. - Value *PtrInd = Induction; - PtrInd = Builder.CreateSExtOrTrunc(PtrInd, II.getStep()->getType()); - // Determine the number of scalars we need to generate for each unroll - // iteration. If the instruction is uniform, we only need to generate the - // first lane. Otherwise, we generate all VF values. - unsigned Lanes = Cost->isUniformAfterVectorization(P, VF) ? 1 : VF; - // These are the scalar results. Notice that we don't generate vector GEPs - // because scalar GEPs result in better code. - for (unsigned Part = 0; Part < UF; ++Part) { - for (unsigned Lane = 0; Lane < Lanes; ++Lane) { - Constant *Idx = ConstantInt::get(PtrInd->getType(), Lane + Part * VF); - Value *GlobalIdx = Builder.CreateAdd(PtrInd, Idx); - Value *SclrGep = - emitTransformedIndex(Builder, GlobalIdx, PSE.getSE(), DL, II); - SclrGep->setName("next.gep"); - VectorLoopValueMap.setScalarValue(P, {Part, Lane}, SclrGep); + + if (Cost->isScalarAfterVectorization(P, VF)) { + // This is the normalized GEP that starts counting at zero. + Value *PtrInd = + Builder.CreateSExtOrTrunc(Induction, II.getStep()->getType()); + // Determine the number of scalars we need to generate for each unroll + // iteration. If the instruction is uniform, we only need to generate the + // first lane. Otherwise, we generate all VF values. + unsigned Lanes = + Cost->isUniformAfterVectorization(P, VF) ? 1 : VF.getKnownMinValue(); + for (unsigned Part = 0; Part < UF; ++Part) { + for (unsigned Lane = 0; Lane < Lanes; ++Lane) { + Constant *Idx = ConstantInt::get(PtrInd->getType(), + Lane + Part * VF.getKnownMinValue()); + Value *GlobalIdx = Builder.CreateAdd(PtrInd, Idx); + Value *SclrGep = + emitTransformedIndex(Builder, GlobalIdx, PSE.getSE(), DL, II); + SclrGep->setName("next.gep"); + VectorLoopValueMap.setScalarValue(P, {Part, Lane}, SclrGep); + } } + return; + } + assert(isa(II.getStep()) && + "Induction step not a SCEV constant!"); + Type *PhiType = II.getStep()->getType(); + + // Build a pointer phi + Value *ScalarStartValue = II.getStartValue(); + Type *ScStValueType = ScalarStartValue->getType(); + PHINode *NewPointerPhi = + PHINode::Create(ScStValueType, 2, "pointer.phi", Induction); + NewPointerPhi->addIncoming(ScalarStartValue, LoopVectorPreHeader); + + // A pointer induction, performed by using a gep + BasicBlock *LoopLatch = LI->getLoopFor(LoopVectorBody)->getLoopLatch(); + Instruction *InductionLoc = LoopLatch->getTerminator(); + const SCEV *ScalarStep = II.getStep(); + SCEVExpander Exp(*PSE.getSE(), DL, "induction"); + Value *ScalarStepValue = + Exp.expandCodeFor(ScalarStep, PhiType, InductionLoc); + Value *InductionGEP = GetElementPtrInst::Create( + ScStValueType->getPointerElementType(), NewPointerPhi, + Builder.CreateMul( + ScalarStepValue, + ConstantInt::get(PhiType, VF.getKnownMinValue() * UF)), + "ptr.ind", InductionLoc); + NewPointerPhi->addIncoming(InductionGEP, LoopLatch); + + // Create UF many actual address geps that use the pointer + // phi as base and a vectorized version of the step value + // () as offset. + for (unsigned Part = 0; Part < UF; ++Part) { + SmallVector Indices; + // Create a vector of consecutive numbers from zero to VF. + for (unsigned i = 0; i < VF.getKnownMinValue(); ++i) + Indices.push_back( + ConstantInt::get(PhiType, i + Part * VF.getKnownMinValue())); + Constant *StartOffset = ConstantVector::get(Indices); + + Value *GEP = Builder.CreateGEP( + ScStValueType->getPointerElementType(), NewPointerPhi, + Builder.CreateMul( + StartOffset, + Builder.CreateVectorSplat(VF.getKnownMinValue(), ScalarStepValue), + "vector.gep")); + VectorLoopValueMap.setVectorValue(P, Part, GEP); } - return; } } } @@ -4255,7 +4773,8 @@ static bool mayDivideByZero(Instruction &I) { return !CInt || CInt->isZero(); } -void InnerLoopVectorizer::widenInstruction(Instruction &I, VPUser &User, +void InnerLoopVectorizer::widenInstruction(Instruction &I, VPValue *Def, + VPUser &User, VPTransformState &State) { switch (I.getOpcode()) { case Instruction::Call: @@ -4297,7 +4816,7 @@ void InnerLoopVectorizer::widenInstruction(Instruction &I, VPUser &User, VecOp->copyIRFlags(&I); // Use this vector value for all users of the original instruction. - VectorLoopValueMap.setVectorValue(&I, Part, V); + State.set(Def, &I, V, Part); addMetadata(V, &I); } @@ -4321,7 +4840,7 @@ void InnerLoopVectorizer::widenInstruction(Instruction &I, VPUser &User, } else { C = Builder.CreateICmp(Cmp->getPredicate(), A, B); } - VectorLoopValueMap.setVectorValue(&I, Part, C); + State.set(Def, &I, C, Part); addMetadata(C, &I); } @@ -4345,12 +4864,12 @@ void InnerLoopVectorizer::widenInstruction(Instruction &I, VPUser &User, /// Vectorize casts. Type *DestTy = - (VF == 1) ? CI->getType() : FixedVectorType::get(CI->getType(), VF); + (VF.isScalar()) ? CI->getType() : VectorType::get(CI->getType(), VF); for (unsigned Part = 0; Part < UF; ++Part) { Value *A = State.get(User.getOperand(0), Part); Value *Cast = Builder.CreateCast(CI->getOpcode(), A, DestTy); - VectorLoopValueMap.setVectorValue(&I, Part, Cast); + State.set(Def, &I, Cast, Part); addMetadata(Cast, &I); } break; @@ -4362,7 +4881,8 @@ void InnerLoopVectorizer::widenInstruction(Instruction &I, VPUser &User, } // end of switch. } -void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPUser &ArgOperands, +void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPValue *Def, + VPUser &ArgOperands, VPTransformState &State) { assert(!isa(I) && "DbgInfoIntrinsic should have been dropped during VPlan construction"); @@ -4373,7 +4893,7 @@ void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPUser &ArgOperands, SmallVector Tys; for (Value *ArgOperand : CI->arg_operands()) - Tys.push_back(ToVectorTy(ArgOperand->getType(), VF)); + Tys.push_back(ToVectorTy(ArgOperand->getType(), VF.getKnownMinValue())); Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); @@ -4381,11 +4901,13 @@ void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPUser &ArgOperands, // version of the instruction. // Is it beneficial to perform intrinsic call compared to lib call? bool NeedToScalarize = false; - unsigned CallCost = Cost->getVectorCallCost(CI, VF, NeedToScalarize); - bool UseVectorIntrinsic = - ID && Cost->getVectorIntrinsicCost(CI, VF) <= CallCost; + InstructionCost CallCost = Cost->getVectorCallCost(CI, VF, NeedToScalarize); + InstructionCost IntrinsicCost = ID ? Cost->getVectorIntrinsicCost(CI, VF) : 0; + bool UseVectorIntrinsic = ID && IntrinsicCost <= CallCost; assert((UseVectorIntrinsic || !NeedToScalarize) && "Instruction should be scalarized elsewhere."); + assert(IntrinsicCost.isValid() && CallCost.isValid() && + "Cannot have invalid costs while widening"); for (unsigned Part = 0; Part < UF; ++Part) { SmallVector Args; @@ -4404,15 +4926,15 @@ void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPUser &ArgOperands, if (UseVectorIntrinsic) { // Use vector version of the intrinsic. Type *TysForDecl[] = {CI->getType()}; - if (VF > 1) - TysForDecl[0] = - FixedVectorType::get(CI->getType()->getScalarType(), VF); + if (VF.isVector()) { + assert(!VF.isScalable() && "VF is assumed to be non scalable."); + TysForDecl[0] = VectorType::get(CI->getType()->getScalarType(), VF); + } VectorF = Intrinsic::getDeclaration(M, ID, TysForDecl); assert(VectorF && "Can't retrieve vector intrinsic."); } else { // Use vector version of the function call. - const VFShape Shape = - VFShape::get(*CI, {VF, false} /*EC*/, false /*HasGlobalPred*/); + const VFShape Shape = VFShape::get(*CI, VF, false /*HasGlobalPred*/); #ifndef NDEBUG assert(VFDatabase(*CI).getVectorizedFunction(Shape) != nullptr && "Can't create vector function."); @@ -4426,12 +4948,12 @@ void InnerLoopVectorizer::widenCallInstruction(CallInst &I, VPUser &ArgOperands, if (isa(V)) V->copyFastMathFlags(CI); - VectorLoopValueMap.setVectorValue(&I, Part, V); + State.set(Def, &I, V, Part); addMetadata(V, &I); } } -void InnerLoopVectorizer::widenSelectInstruction(SelectInst &I, +void InnerLoopVectorizer::widenSelectInstruction(SelectInst &I, VPValue *VPDef, VPUser &Operands, bool InvariantCond, VPTransformState &State) { @@ -4450,16 +4972,16 @@ void InnerLoopVectorizer::widenSelectInstruction(SelectInst &I, Value *Op0 = State.get(Operands.getOperand(1), Part); Value *Op1 = State.get(Operands.getOperand(2), Part); Value *Sel = Builder.CreateSelect(Cond, Op0, Op1); - VectorLoopValueMap.setVectorValue(&I, Part, Sel); + State.set(VPDef, &I, Sel, Part); addMetadata(Sel, &I); } } -void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { +void LoopVectorizationCostModel::collectLoopScalars(ElementCount VF) { // We should not collect Scalars more than once per VF. Right now, this // function is called from collectUniformsAndScalars(), which already does // this check. Collecting Scalars for VF=1 does not make any sense. - assert(VF >= 2 && Scalars.find(VF) == Scalars.end() && + assert(VF.isVector() && Scalars.find(VF) == Scalars.end() && "This function should not be visited twice for the same VF"); SmallSetVector Worklist; @@ -4468,6 +4990,7 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { // accesses that will remain scalar. SmallSetVector ScalarPtrs; SmallPtrSet PossibleNonScalarPtrs; + auto *Latch = TheLoop->getLoopLatch(); // A helper that returns true if the use of Ptr by MemAccess will be scalar. // The pointer operands of loads and stores will be scalar as long as the @@ -4493,11 +5016,33 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { !TheLoop->isLoopInvariant(V); }; - // A helper that evaluates a memory access's use of a pointer. If the use - // will be a scalar use, and the pointer is only used by memory accesses, we - // place the pointer in ScalarPtrs. Otherwise, the pointer is placed in - // PossibleNonScalarPtrs. + auto isScalarPtrInduction = [&](Instruction *MemAccess, Value *Ptr) { + if (!isa(Ptr) || + !Legal->getInductionVars().count(cast(Ptr))) + return false; + auto &Induction = Legal->getInductionVars()[cast(Ptr)]; + if (Induction.getKind() != InductionDescriptor::IK_PtrInduction) + return false; + return isScalarUse(MemAccess, Ptr); + }; + + // A helper that evaluates a memory access's use of a pointer. If the + // pointer is actually the pointer induction of a loop, it is being + // inserted into Worklist. If the use will be a scalar use, and the + // pointer is only used by memory accesses, we place the pointer in + // ScalarPtrs. Otherwise, the pointer is placed in PossibleNonScalarPtrs. auto evaluatePtrUse = [&](Instruction *MemAccess, Value *Ptr) { + if (isScalarPtrInduction(MemAccess, Ptr)) { + Worklist.insert(cast(Ptr)); + Instruction *Update = cast( + cast(Ptr)->getIncomingValueForBlock(Latch)); + Worklist.insert(Update); + LLVM_DEBUG(dbgs() << "LV: Found new scalar instruction: " << *Ptr + << "\n"); + LLVM_DEBUG(dbgs() << "LV: Found new scalar instruction: " << *Update + << "\n"); + return; + } // We only care about bitcast and getelementptr instructions contained in // the loop. if (!isLoopVaryingBitCastOrGEP(Ptr)) @@ -4521,10 +5066,9 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { }; // We seed the scalars analysis with three classes of instructions: (1) - // instructions marked uniform-after-vectorization, (2) bitcast and - // getelementptr instructions used by memory accesses requiring a scalar use, - // and (3) pointer induction variables and their update instructions (we - // currently only scalarize these). + // instructions marked uniform-after-vectorization and (2) bitcast, + // getelementptr and (pointer) phi instructions used by memory accesses + // requiring a scalar use. // // (1) Add to the worklist all instructions that have been identified as // uniform-after-vectorization. @@ -4550,24 +5094,6 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { Worklist.insert(I); } - // (3) Add to the worklist all pointer induction variables and their update - // instructions. - // - // TODO: Once we are able to vectorize pointer induction variables we should - // no longer insert them into the worklist here. - auto *Latch = TheLoop->getLoopLatch(); - for (auto &Induction : Legal->getInductionVars()) { - auto *Ind = Induction.first; - auto *IndUpdate = cast(Ind->getIncomingValueForBlock(Latch)); - if (Induction.second.getKind() != InductionDescriptor::IK_PtrInduction) - continue; - Worklist.insert(Ind); - Worklist.insert(IndUpdate); - LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *Ind << "\n"); - LLVM_DEBUG(dbgs() << "LV: Found scalar instruction: " << *IndUpdate - << "\n"); - } - // Insert the forced scalars. // FIXME: Currently widenPHIInstruction() often creates a dead vector // induction variable when the PHI user is scalarized. @@ -4603,14 +5129,6 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { auto *Ind = Induction.first; auto *IndUpdate = cast(Ind->getIncomingValueForBlock(Latch)); - // We already considered pointer induction variables, so there's no reason - // to look at their users again. - // - // TODO: Once we are able to vectorize pointer induction variables we - // should no longer skip over them here. - if (Induction.second.getKind() == InductionDescriptor::IK_PtrInduction) - continue; - // If tail-folding is applied, the primary induction variable will be used // to feed a vector compare. if (Ind == Legal->getPrimaryInduction() && foldTailByMasking()) @@ -4646,7 +5164,8 @@ void LoopVectorizationCostModel::collectLoopScalars(unsigned VF) { Scalars[VF].insert(Worklist.begin(), Worklist.end()); } -bool LoopVectorizationCostModel::isScalarWithPredication(Instruction *I, unsigned VF) { +bool LoopVectorizationCostModel::isScalarWithPredication(Instruction *I, + ElementCount VF) { if (!blockNeedsPredication(I->getParent())) return false; switch(I->getOpcode()) { @@ -4660,7 +5179,7 @@ bool LoopVectorizationCostModel::isScalarWithPredication(Instruction *I, unsigne auto *Ty = getMemInstValueType(I); // We have already decided how to vectorize this instruction, get that // result. - if (VF > 1) { + if (VF.isVector()) { InstWidening WideningDecision = getWideningDecision(I, VF); assert(WideningDecision != CM_Unknown && "Widening decision should be ready at this moment"); @@ -4681,8 +5200,8 @@ bool LoopVectorizationCostModel::isScalarWithPredication(Instruction *I, unsigne return false; } -bool LoopVectorizationCostModel::interleavedAccessCanBeWidened(Instruction *I, - unsigned VF) { +bool LoopVectorizationCostModel::interleavedAccessCanBeWidened( + Instruction *I, ElementCount VF) { assert(isAccessInterleaved(I) && "Expecting interleaved access."); assert(getWideningDecision(I, VF) == CM_Unknown && "Decision should not be set yet."); @@ -4718,8 +5237,8 @@ bool LoopVectorizationCostModel::interleavedAccessCanBeWidened(Instruction *I, : TTI.isLegalMaskedStore(Ty, Alignment); } -bool LoopVectorizationCostModel::memoryInstructionCanBeWidened(Instruction *I, - unsigned VF) { +bool LoopVectorizationCostModel::memoryInstructionCanBeWidened( + Instruction *I, ElementCount VF) { // Get and ensure we have a valid memory instruction. LoadInst *LI = dyn_cast(I); StoreInst *SI = dyn_cast(I); @@ -4746,13 +5265,13 @@ bool LoopVectorizationCostModel::memoryInstructionCanBeWidened(Instruction *I, return true; } -void LoopVectorizationCostModel::collectLoopUniforms(unsigned VF) { +void LoopVectorizationCostModel::collectLoopUniforms(ElementCount VF) { // We should not collect Uniforms more than once per VF. Right now, // this function is called from collectUniformsAndScalars(), which // already does this check. Collecting Uniforms for VF=1 does not make any // sense. - assert(VF >= 2 && Uniforms.find(VF) == Uniforms.end() && + assert(VF.isVector() && Uniforms.find(VF) == Uniforms.end() && "This function should not be visited twice for the same VF"); // Visit the list of Uniforms. If we'll not find any uniform value, we'll @@ -4778,6 +5297,11 @@ void LoopVectorizationCostModel::collectLoopUniforms(unsigned VF) { // replicating region where only a single instance out of VF should be formed. // TODO: optimize such seldom cases if found important, see PR40816. auto addToWorklistIfAllowed = [&](Instruction *I) -> void { + if (isOutOfScope(I)) { + LLVM_DEBUG(dbgs() << "LV: Found not uniform due to scope: " + << *I << "\n"); + return; + } if (isScalarWithPredication(I, VF)) { LLVM_DEBUG(dbgs() << "LV: Found not uniform being ScalarWithPredication: " << *I << "\n"); @@ -4794,65 +5318,71 @@ void LoopVectorizationCostModel::collectLoopUniforms(unsigned VF) { if (Cmp && TheLoop->contains(Cmp) && Cmp->hasOneUse()) addToWorklistIfAllowed(Cmp); - // Holds consecutive and consecutive-like pointers. Consecutive-like pointers - // are pointers that are treated like consecutive pointers during - // vectorization. The pointer operands of interleaved accesses are an - // example. - SmallSetVector ConsecutiveLikePtrs; - - // Holds pointer operands of instructions that are possibly non-uniform. - SmallPtrSet PossibleNonUniformPtrs; - - auto isUniformDecision = [&](Instruction *I, unsigned VF) { + auto isUniformDecision = [&](Instruction *I, ElementCount VF) { InstWidening WideningDecision = getWideningDecision(I, VF); assert(WideningDecision != CM_Unknown && "Widening decision should be ready at this moment"); + // A uniform memory op is itself uniform. We exclude uniform stores + // here as they demand the last lane, not the first one. + if (isa(I) && Legal->isUniformMemOp(*I)) { + assert(WideningDecision == CM_Scalarize); + return true; + } + return (WideningDecision == CM_Widen || WideningDecision == CM_Widen_Reverse || WideningDecision == CM_Interleave); }; - // Iterate over the instructions in the loop, and collect all - // consecutive-like pointer operands in ConsecutiveLikePtrs. If it's possible - // that a consecutive-like pointer operand will be scalarized, we collect it - // in PossibleNonUniformPtrs instead. We use two sets here because a single - // getelementptr instruction can be used by both vectorized and scalarized - // memory instructions. For example, if a loop loads and stores from the same - // location, but the store is conditional, the store will be scalarized, and - // the getelementptr won't remain uniform. + + + // Returns true if Ptr is the pointer operand of a memory access instruction + // I, and I is known to not require scalarization. + auto isVectorizedMemAccessUse = [&](Instruction *I, Value *Ptr) -> bool { + return getLoadStorePointerOperand(I) == Ptr && isUniformDecision(I, VF); + }; + + // Holds a list of values which are known to have at least one uniform use. + // Note that there may be other uses which aren't uniform. A "uniform use" + // here is something which only demands lane 0 of the unrolled iterations; + // it does not imply that all lanes produce the same value (e.g. this is not + // the usual meaning of uniform) + SmallPtrSet HasUniformUse; + + // Scan the loop for instructions which are either a) known to have only + // lane 0 demanded or b) are uses which demand only lane 0 of their operand. for (auto *BB : TheLoop->blocks()) for (auto &I : *BB) { // If there's no pointer operand, there's nothing to do. - auto *Ptr = dyn_cast_or_null(getLoadStorePointerOperand(&I)); + auto *Ptr = getLoadStorePointerOperand(&I); if (!Ptr) continue; - // True if all users of Ptr are memory accesses that have Ptr as their - // pointer operand. - auto UsersAreMemAccesses = - llvm::all_of(Ptr->users(), [&](User *U) -> bool { - return getLoadStorePointerOperand(U) == Ptr; - }); - - // Ensure the memory instruction will not be scalarized or used by - // gather/scatter, making its pointer operand non-uniform. If the pointer - // operand is used by any instruction other than a memory access, we - // conservatively assume the pointer operand may be non-uniform. - if (!UsersAreMemAccesses || !isUniformDecision(&I, VF)) - PossibleNonUniformPtrs.insert(Ptr); - - // If the memory instruction will be vectorized and its pointer operand - // is consecutive-like, or interleaving - the pointer operand should - // remain uniform. - else - ConsecutiveLikePtrs.insert(Ptr); + // A uniform memory op is itself uniform. We exclude uniform stores + // here as they demand the last lane, not the first one. + if (isa(I) && Legal->isUniformMemOp(I)) + addToWorklistIfAllowed(&I); + + if (isUniformDecision(&I, VF)) { + assert(isVectorizedMemAccessUse(&I, Ptr) && "consistency check"); + HasUniformUse.insert(Ptr); + } } - // Add to the Worklist all consecutive and consecutive-like pointers that - // aren't also identified as possibly non-uniform. - for (auto *V : ConsecutiveLikePtrs) - if (!PossibleNonUniformPtrs.count(V)) - addToWorklistIfAllowed(V); + // Add to the worklist any operands which have *only* uniform (e.g. lane 0 + // demanding) users. Since loops are assumed to be in LCSSA form, this + // disallows uses outside the loop as well. + for (auto *V : HasUniformUse) { + if (isOutOfScope(V)) + continue; + auto *I = cast(V); + auto UsersAreMemAccesses = + llvm::all_of(I->users(), [&](User *U) -> bool { + return isVectorizedMemAccessUse(cast(U), V); + }); + if (UsersAreMemAccesses) + addToWorklistIfAllowed(I); + } // Expand Worklist in topological order: whenever a new instruction // is added , its users should be already inside Worklist. It ensures @@ -4875,20 +5405,12 @@ void LoopVectorizationCostModel::collectLoopUniforms(unsigned VF) { auto *OI = cast(OV); if (llvm::all_of(OI->users(), [&](User *U) -> bool { auto *J = cast(U); - return Worklist.count(J) || - (OI == getLoadStorePointerOperand(J) && - isUniformDecision(J, VF)); + return Worklist.count(J) || isVectorizedMemAccessUse(J, OI); })) addToWorklistIfAllowed(OI); } } - // Returns true if Ptr is the pointer operand of a memory access instruction - // I, and I is known to not require scalarization. - auto isVectorizedMemAccessUse = [&](Instruction *I, Value *Ptr) -> bool { - return getLoadStorePointerOperand(I) == Ptr && isUniformDecision(I, VF); - }; - // For an instruction to be added into Worklist above, all its users inside // the loop should also be in Worklist. However, this condition cannot be // true for phi nodes that form a cyclic dependence. We must process phi @@ -4961,8 +5483,8 @@ bool LoopVectorizationCostModel::runtimeChecksRequired() { return false; } -Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, - unsigned UserIC) { +Optional +LoopVectorizationCostModel::computeMaxVF(ElementCount UserVF, unsigned UserIC) { if (Legal->getRuntimePointerChecking()->Need && TTI.hasBranchDivergence()) { // TODO: It may by useful to do since it's still likely to be dynamically // uniform if the target can skip. @@ -4982,9 +5504,13 @@ Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, return None; } + ElementCount MaxVF = computeFeasibleMaxVF(TC, UserVF); + switch (ScalarEpilogueStatus) { case CM_ScalarEpilogueAllowed: - return UserVF ? UserVF : computeFeasibleMaxVF(TC); + return MaxVF; + case CM_ScalarEpilogueNotAllowedUsePredicate: + LLVM_FALLTHROUGH; case CM_ScalarEpilogueNotNeededUsePredicate: LLVM_DEBUG( dbgs() << "LV: vector predicate hint/switch found.\n" @@ -5005,9 +5531,26 @@ Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, // for size. if (runtimeChecksRequired()) return None; + break; } + // The only loops we can vectorize without a scalar epilogue, are loops with + // a bottom-test and a single exiting block. We'd have to handle the fact + // that not every instruction executes on the last iteration. This will + // require a lane mask which varies through the vector loop body. (TODO) + if (TheLoop->getExitingBlock() != TheLoop->getLoopLatch()) { + // If there was a tail-folding hint/switch, but we can't fold the tail by + // masking, fallback to a vectorization with a scalar epilogue. + if (ScalarEpilogueStatus == CM_ScalarEpilogueNotNeededUsePredicate) { + LLVM_DEBUG(dbgs() << "LV: Cannot fold tail by masking: vectorize with a " + "scalar epilogue instead.\n"); + ScalarEpilogueStatus = CM_ScalarEpilogueAllowed; + return MaxVF; + } + return None; + } + // Now try the tail folding // Invalidate interleave groups that require an epilogue if we can't mask @@ -5020,10 +5563,21 @@ Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, InterleaveInfo.invalidateGroupsRequiringScalarEpilogue(); } - unsigned MaxVF = UserVF ? UserVF : computeFeasibleMaxVF(TC); - assert((UserVF || isPowerOf2_32(MaxVF)) && "MaxVF must be a power of 2"); - unsigned MaxVFtimesIC = UserIC ? MaxVF * UserIC : MaxVF; - if (TC > 0 && TC % MaxVFtimesIC == 0) { + assert(!MaxVF.isScalable() && + "Scalable vectors do not yet support tail folding"); + assert((UserVF.isNonZero() || isPowerOf2_32(MaxVF.getFixedValue())) && + "MaxVF must be a power of 2"); + unsigned MaxVFtimesIC = + UserIC ? MaxVF.getFixedValue() * UserIC : MaxVF.getFixedValue(); + // Avoid tail folding if the trip count is known to be a multiple of any VF we + // chose. + ScalarEvolution *SE = PSE.getSE(); + const SCEV *BackedgeTakenCount = PSE.getBackedgeTakenCount(); + const SCEV *ExitCount = SE->getAddExpr( + BackedgeTakenCount, SE->getOne(BackedgeTakenCount->getType())); + const SCEV *Rem = SE->getURemExpr( + ExitCount, SE->getConstant(BackedgeTakenCount->getType(), MaxVFtimesIC)); + if (Rem->isZero()) { // Accept MaxVF if we do not have a tail. LLVM_DEBUG(dbgs() << "LV: No tail will remain for any chosen VF.\n"); return MaxVF; @@ -5038,6 +5592,20 @@ Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, return MaxVF; } + // If there was a tail-folding hint/switch, but we can't fold the tail by + // masking, fallback to a vectorization with a scalar epilogue. + if (ScalarEpilogueStatus == CM_ScalarEpilogueNotNeededUsePredicate) { + LLVM_DEBUG(dbgs() << "LV: Cannot fold tail by masking: vectorize with a " + "scalar epilogue instead.\n"); + ScalarEpilogueStatus = CM_ScalarEpilogueAllowed; + return MaxVF; + } + + if (ScalarEpilogueStatus == CM_ScalarEpilogueNotAllowedUsePredicate) { + LLVM_DEBUG(dbgs() << "LV: Can't fold tail by masking: don't vectorize\n"); + return None; + } + if (TC == 0) { reportVectorizationFailure( "Unable to calculate the loop count due to complex control flow", @@ -5055,8 +5623,33 @@ Optional LoopVectorizationCostModel::computeMaxVF(unsigned UserVF, return None; } -unsigned -LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { +ElementCount +LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount, + ElementCount UserVF) { + bool IgnoreScalableUserVF = UserVF.isScalable() && + !TTI.supportsScalableVectors() && + !ForceTargetSupportsScalableVectors; + if (IgnoreScalableUserVF) { + LLVM_DEBUG( + dbgs() << "LV: Ignoring VF=" << UserVF + << " because target does not support scalable vectors.\n"); + ORE->emit([&]() { + return OptimizationRemarkAnalysis(DEBUG_TYPE, "IgnoreScalableUserVF", + TheLoop->getStartLoc(), + TheLoop->getHeader()) + << "Ignoring VF=" << ore::NV("UserVF", UserVF) + << " because target does not support scalable vectors."; + }); + } + + // Beyond this point two scenarios are handled. If UserVF isn't specified + // then a suitable VF is chosen. If UserVF is specified and there are + // dependencies, check if it's legal. However, if a UserVF is specified and + // there are no dependencies, then there's nothing to do. + if (UserVF.isNonZero() && !IgnoreScalableUserVF && + Legal->isSafeForAnyVectorWidth()) + return UserVF; + MinBWs = computeMinimumValueSizes(TheLoop->getBlocks(), *DB, &TTI); unsigned SmallestType, WidestType; std::tie(SmallestType, WidestType) = getSmallestAndWidestTypes(); @@ -5066,9 +5659,62 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { // It is computed by MaxVF * sizeOf(type) * 8, where type is taken from // the memory accesses that is most restrictive (involved in the smallest // dependence distance). - unsigned MaxSafeRegisterWidth = Legal->getMaxSafeRegisterWidth(); + unsigned MaxSafeVectorWidthInBits = Legal->getMaxSafeVectorWidthInBits(); + + // If the user vectorization factor is legally unsafe, clamp it to a safe + // value. Otherwise, return as is. + if (UserVF.isNonZero() && !IgnoreScalableUserVF) { + unsigned MaxSafeElements = + PowerOf2Floor(MaxSafeVectorWidthInBits / WidestType); + ElementCount MaxSafeVF = ElementCount::getFixed(MaxSafeElements); + + if (UserVF.isScalable()) { + Optional MaxVScale = TTI.getMaxVScale(); + + // Scale VF by vscale before checking if it's safe. + MaxSafeVF = ElementCount::getScalable( + MaxVScale ? (MaxSafeElements / MaxVScale.getValue()) : 0); + + if (MaxSafeVF.isZero()) { + // The dependence distance is too small to use scalable vectors, + // fallback on fixed. + LLVM_DEBUG( + dbgs() + << "LV: Max legal vector width too small, scalable vectorization " + "unfeasible. Using fixed-width vectorization instead.\n"); + ORE->emit([&]() { + return OptimizationRemarkAnalysis(DEBUG_TYPE, "ScalableVFUnfeasible", + TheLoop->getStartLoc(), + TheLoop->getHeader()) + << "Max legal vector width too small, scalable vectorization " + << "unfeasible. Using fixed-width vectorization instead."; + }); + return computeFeasibleMaxVF( + ConstTripCount, ElementCount::getFixed(UserVF.getKnownMinValue())); + } + } - WidestRegister = std::min(WidestRegister, MaxSafeRegisterWidth); + LLVM_DEBUG(dbgs() << "LV: The max safe VF is: " << MaxSafeVF << ".\n"); + + if (ElementCount::isKnownLE(UserVF, MaxSafeVF)) + return UserVF; + + LLVM_DEBUG(dbgs() << "LV: User VF=" << UserVF + << " is unsafe, clamping to max safe VF=" << MaxSafeVF + << ".\n"); + ORE->emit([&]() { + return OptimizationRemarkAnalysis(DEBUG_TYPE, "VectorizationFactor", + TheLoop->getStartLoc(), + TheLoop->getHeader()) + << "User-specified vectorization factor " + << ore::NV("UserVectorizationFactor", UserVF) + << " is unsafe, clamping to maximum safe vectorization factor " + << ore::NV("VectorizationFactor", MaxSafeVF); + }); + return MaxSafeVF; + } + + WidestRegister = std::min(WidestRegister, MaxSafeVectorWidthInBits); // Ensure MaxVF is a power of 2; the dependence distance bound may not be. // Note that both WidestRegister and WidestType may not be a powers of 2. @@ -5079,12 +5725,13 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { LLVM_DEBUG(dbgs() << "LV: The Widest register safe to use is: " << WidestRegister << " bits.\n"); - assert(MaxVectorSize <= 256 && "Did not expect to pack so many elements" - " into one vector!"); + assert(MaxVectorSize <= WidestRegister && + "Did not expect to pack so many elements" + " into one vector!"); if (MaxVectorSize == 0) { LLVM_DEBUG(dbgs() << "LV: The target has no vector registers.\n"); MaxVectorSize = 1; - return MaxVectorSize; + return ElementCount::getFixed(MaxVectorSize); } else if (ConstTripCount && ConstTripCount < MaxVectorSize && isPowerOf2_32(ConstTripCount)) { // We need to clamp the VF to be the ConstTripCount. There is no point in @@ -5092,7 +5739,7 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { LLVM_DEBUG(dbgs() << "LV: Clamping the MaxVF to the constant trip count: " << ConstTripCount << "\n"); MaxVectorSize = ConstTripCount; - return MaxVectorSize; + return ElementCount::getFixed(MaxVectorSize); } unsigned MaxVF = MaxVectorSize; @@ -5100,10 +5747,10 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { (MaximizeBandwidth && isScalarEpilogueAllowed())) { // Collect all viable vectorization factors larger than the default MaxVF // (i.e. MaxVectorSize). - SmallVector VFs; + SmallVector VFs; unsigned NewMaxVectorSize = WidestRegister / SmallestType; for (unsigned VS = MaxVectorSize * 2; VS <= NewMaxVectorSize; VS *= 2) - VFs.push_back(VS); + VFs.push_back(ElementCount::getFixed(VS)); // For each VF calculate its register usage. auto RUs = calculateRegisterUsage(VFs); @@ -5118,7 +5765,7 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { Selected = false; } if (Selected) { - MaxVF = VFs[i]; + MaxVF = VFs[i].getKnownMinValue(); break; } } @@ -5130,30 +5777,39 @@ LoopVectorizationCostModel::computeFeasibleMaxVF(unsigned ConstTripCount) { } } } - return MaxVF; + return ElementCount::getFixed(MaxVF); } VectorizationFactor -LoopVectorizationCostModel::selectVectorizationFactor(unsigned MaxVF) { - float Cost = expectedCost(1).first; - const float ScalarCost = Cost; +LoopVectorizationCostModel::selectVectorizationFactor(ElementCount MaxVF) { + // FIXME: This can be fixed for scalable vectors later, because at this stage + // the LoopVectorizer will only consider vectorizing a loop with scalable + // vectors when the loop has a hint to enable vectorization for a given VF. + assert(!MaxVF.isScalable() && "scalable vectors not yet supported"); + + InstructionCost ExpectedCost = expectedCost(ElementCount::getFixed(1)).first; + LLVM_DEBUG(dbgs() << "LV: Scalar loop costs: " << ExpectedCost << ".\n"); + assert(ExpectedCost.isValid() && "Unexpected invalid cost for scalar loop"); + unsigned Width = 1; - LLVM_DEBUG(dbgs() << "LV: Scalar loop costs: " << (int)ScalarCost << ".\n"); + const float ScalarCost = *ExpectedCost.getValue(); + float Cost = ScalarCost; bool ForceVectorization = Hints->getForce() == LoopVectorizeHints::FK_Enabled; - if (ForceVectorization && MaxVF > 1) { + if (ForceVectorization && MaxVF.isVector()) { // Ignore scalar width, because the user explicitly wants vectorization. // Initialize cost to max so that VF = 2 is, at least, chosen during cost // evaluation. Cost = std::numeric_limits::max(); } - for (unsigned i = 2; i <= MaxVF; i *= 2) { + for (unsigned i = 2; i <= MaxVF.getFixedValue(); i *= 2) { // Notice that the vector loop needs to be executed less times, so // we need to divide the cost of the vector loops by the width of // the vector elements. - VectorizationCostTy C = expectedCost(i); - float VectorCost = C.first / (float)i; + VectorizationCostTy C = expectedCost(ElementCount::getFixed(i)); + assert(C.first.isValid() && "Unexpected invalid cost for vector loop"); + float VectorCost = *C.first.getValue() / (float)i; LLVM_DEBUG(dbgs() << "LV: Vector loop of width " << i << " costs: " << (int)VectorCost << ".\n"); if (!C.second && !ForceVectorization) { @@ -5162,6 +5818,13 @@ LoopVectorizationCostModel::selectVectorizationFactor(unsigned MaxVF) { << " because it will not generate any vector instructions.\n"); continue; } + + // If profitable add it to ProfitableVF list. + if (VectorCost < ScalarCost) { + ProfitableVFs.push_back(VectorizationFactor( + {ElementCount::getFixed(i), (unsigned)VectorCost})); + } + if (VectorCost < Cost) { Cost = VectorCost; Width = i; @@ -5180,10 +5843,131 @@ LoopVectorizationCostModel::selectVectorizationFactor(unsigned MaxVF) { << "LV: Vectorization seems to be not beneficial, " << "but was forced by a user.\n"); LLVM_DEBUG(dbgs() << "LV: Selecting VF: " << Width << ".\n"); - VectorizationFactor Factor = {Width, (unsigned)(Width * Cost)}; + VectorizationFactor Factor = {ElementCount::getFixed(Width), + (unsigned)(Width * Cost)}; return Factor; } +bool LoopVectorizationCostModel::isCandidateForEpilogueVectorization( + const Loop &L, ElementCount VF) const { + // Cross iteration phis such as reductions need special handling and are + // currently unsupported. + if (any_of(L.getHeader()->phis(), [&](PHINode &Phi) { + return Legal->isFirstOrderRecurrence(&Phi) || + Legal->isReductionVariable(&Phi); + })) + return false; + + // Phis with uses outside of the loop require special handling and are + // currently unsupported. + for (auto &Entry : Legal->getInductionVars()) { + // Look for uses of the value of the induction at the last iteration. + Value *PostInc = Entry.first->getIncomingValueForBlock(L.getLoopLatch()); + for (User *U : PostInc->users()) + if (!L.contains(cast(U))) + return false; + // Look for uses of penultimate value of the induction. + for (User *U : Entry.first->users()) + if (!L.contains(cast(U))) + return false; + } + + // Induction variables that are widened require special handling that is + // currently not supported. + if (any_of(Legal->getInductionVars(), [&](auto &Entry) { + return !(this->isScalarAfterVectorization(Entry.first, VF) || + this->isProfitableToScalarize(Entry.first, VF)); + })) + return false; + + return true; +} + +bool LoopVectorizationCostModel::isEpilogueVectorizationProfitable( + const ElementCount VF) const { + // FIXME: We need a much better cost-model to take different parameters such + // as register pressure, code size increase and cost of extra branches into + // account. For now we apply a very crude heuristic and only consider loops + // with vectorization factors larger than a certain value. + // We also consider epilogue vectorization unprofitable for targets that don't + // consider interleaving beneficial (eg. MVE). + if (TTI.getMaxInterleaveFactor(VF.getKnownMinValue()) <= 1) + return false; + if (VF.getFixedValue() >= EpilogueVectorizationMinVF) + return true; + return false; +} + +VectorizationFactor +LoopVectorizationCostModel::selectEpilogueVectorizationFactor( + const ElementCount MainLoopVF, const LoopVectorizationPlanner &LVP) { + VectorizationFactor Result = VectorizationFactor::Disabled(); + if (!EnableEpilogueVectorization) { + LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization is disabled.\n";); + return Result; + } + + if (!isScalarEpilogueAllowed()) { + LLVM_DEBUG( + dbgs() << "LEV: Unable to vectorize epilogue because no epilogue is " + "allowed.\n";); + return Result; + } + + // FIXME: This can be fixed for scalable vectors later, because at this stage + // the LoopVectorizer will only consider vectorizing a loop with scalable + // vectors when the loop has a hint to enable vectorization for a given VF. + if (MainLoopVF.isScalable()) { + LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization for scalable vectors not " + "yet supported.\n"); + return Result; + } + + // Not really a cost consideration, but check for unsupported cases here to + // simplify the logic. + if (!isCandidateForEpilogueVectorization(*TheLoop, MainLoopVF)) { + LLVM_DEBUG( + dbgs() << "LEV: Unable to vectorize epilogue because the loop is " + "not a supported candidate.\n";); + return Result; + } + + if (EpilogueVectorizationForceVF > 1) { + LLVM_DEBUG(dbgs() << "LEV: Epilogue vectorization factor is forced.\n";); + if (LVP.hasPlanWithVFs( + {MainLoopVF, ElementCount::getFixed(EpilogueVectorizationForceVF)})) + return {ElementCount::getFixed(EpilogueVectorizationForceVF), 0}; + else { + LLVM_DEBUG( + dbgs() + << "LEV: Epilogue vectorization forced factor is not viable.\n";); + return Result; + } + } + + if (TheLoop->getHeader()->getParent()->hasOptSize() || + TheLoop->getHeader()->getParent()->hasMinSize()) { + LLVM_DEBUG( + dbgs() + << "LEV: Epilogue vectorization skipped due to opt for size.\n";); + return Result; + } + + if (!isEpilogueVectorizationProfitable(MainLoopVF)) + return Result; + + for (auto &NextVF : ProfitableVFs) + if (ElementCount::isKnownLT(NextVF.Width, MainLoopVF) && + (Result.Width.getFixedValue() == 1 || NextVF.Cost < Result.Cost) && + LVP.hasPlanWithVFs({MainLoopVF, NextVF.Width})) + Result = NextVF; + + if (Result != VectorizationFactor::Disabled()) + LLVM_DEBUG(dbgs() << "LEV: Vectorizing epilogue loop with VF = " + << Result.Width.getFixedValue() << "\n";); + return Result; +} + std::pair LoopVectorizationCostModel::getSmallestAndWidestTypes() { unsigned MinWidth = -1U; @@ -5210,6 +5994,11 @@ LoopVectorizationCostModel::getSmallestAndWidestTypes() { if (!Legal->isReductionVariable(PN)) continue; RecurrenceDescriptor RdxDesc = Legal->getReductionVars()[PN]; + if (PreferInLoopReductions || + TTI.preferInLoopReduction(RdxDesc.getOpcode(), + RdxDesc.getRecurrenceType(), + TargetTransformInfo::ReductionFlags())) + continue; T = RdxDesc.getRecurrenceType(); } @@ -5240,7 +6029,7 @@ LoopVectorizationCostModel::getSmallestAndWidestTypes() { return {MinWidth, MaxWidth}; } -unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, +unsigned LoopVectorizationCostModel::selectInterleaveCount(ElementCount VF, unsigned LoopCost) { // -- The interleave heuristics -- // We interleave the loop in order to expose ILP and reduce the loop overhead. @@ -5263,10 +6052,15 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, if (Legal->getMaxSafeDepDistBytes() != -1U) return 1; - // Do not interleave loops with a relatively small known or estimated trip - // count. auto BestKnownTC = getSmallBestKnownTC(*PSE.getSE(), TheLoop); - if (BestKnownTC && *BestKnownTC < TinyTripCountInterleaveThreshold) + const bool HasReductions = !Legal->getReductionVars().empty(); + // Do not interleave loops with a relatively small known or estimated trip + // count. But we will interleave when InterleaveSmallLoopScalarReduction is + // enabled, and the code has scalar reductions(HasReductions && VF = 1), + // because with the above conditions interleaving can expose ILP and break + // cross iteration dependences for reductions. + if (BestKnownTC && (*BestKnownTC < TinyTripCountInterleaveThreshold) && + !(InterleaveSmallLoopScalarReduction && HasReductions && VF.isScalar())) return 1; RegisterUsage R = calculateRegisterUsage({VF})[0]; @@ -5294,7 +6088,7 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, LLVM_DEBUG(dbgs() << "LV: The target has " << TargetNumRegisters << " registers of " << TTI.getRegisterClassName(pair.first) << " register class\n"); - if (VF == 1) { + if (VF.isScalar()) { if (ForceTargetNumScalarRegs.getNumOccurrences() > 0) TargetNumRegisters = ForceTargetNumScalarRegs; } else { @@ -5318,10 +6112,11 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, } // Clamp the interleave ranges to reasonable counts. - unsigned MaxInterleaveCount = TTI.getMaxInterleaveFactor(VF); + unsigned MaxInterleaveCount = + TTI.getMaxInterleaveFactor(VF.getKnownMinValue()); // Check if the user has overridden the max. - if (VF == 1) { + if (VF.isScalar()) { if (ForceTargetMaxScalarInterleaveFactor.getNumOccurrences() > 0) MaxInterleaveCount = ForceTargetMaxScalarInterleaveFactor; } else { @@ -5330,28 +6125,47 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, } // If trip count is known or estimated compile time constant, limit the - // interleave count to be less than the trip count divided by VF. + // interleave count to be less than the trip count divided by VF, provided it + // is at least 1. + // + // For scalable vectors we can't know if interleaving is beneficial. It may + // not be beneficial for small loops if none of the lanes in the second vector + // iterations is enabled. However, for larger loops, there is likely to be a + // similar benefit as for fixed-width vectors. For now, we choose to leave + // the InterleaveCount as if vscale is '1', although if some information about + // the vector is known (e.g. min vector size), we can make a better decision. if (BestKnownTC) { - MaxInterleaveCount = std::min(*BestKnownTC / VF, MaxInterleaveCount); + MaxInterleaveCount = + std::min(*BestKnownTC / VF.getKnownMinValue(), MaxInterleaveCount); + // Make sure MaxInterleaveCount is greater than 0. + MaxInterleaveCount = std::max(1u, MaxInterleaveCount); } - // If we did not calculate the cost for VF (because the user selected the VF) - // then we calculate the cost of VF here. - if (LoopCost == 0) - LoopCost = expectedCost(VF).first; - - assert(LoopCost && "Non-zero loop cost expected"); + assert(MaxInterleaveCount > 0 && + "Maximum interleave count must be greater than 0"); // Clamp the calculated IC to be between the 1 and the max interleave count // that the target and trip count allows. if (IC > MaxInterleaveCount) IC = MaxInterleaveCount; - else if (IC < 1) - IC = 1; + else + // Make sure IC is greater than 0. + IC = std::max(1u, IC); + + assert(IC > 0 && "Interleave count must be greater than 0."); + + // If we did not calculate the cost for VF (because the user selected the VF) + // then we calculate the cost of VF here. + if (LoopCost == 0) { + assert(expectedCost(VF).first.isValid() && "Expected a valid cost"); + LoopCost = *expectedCost(VF).first.getValue(); + } + + assert(LoopCost && "Non-zero loop cost expected"); // Interleave if we vectorized this loop and there is a reduction that could // benefit from interleaving. - if (VF > 1 && !Legal->getReductionVars().empty()) { + if (VF.isVector() && HasReductions) { LLVM_DEBUG(dbgs() << "LV: Interleaving because of reductions.\n"); return IC; } @@ -5359,11 +6173,15 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, // Note that if we've already vectorized the loop we will have done the // runtime check and so interleaving won't require further checks. bool InterleavingRequiresRuntimePointerCheck = - (VF == 1 && Legal->getRuntimePointerChecking()->Need); + (VF.isScalar() && Legal->getRuntimePointerChecking()->Need); // We want to interleave small loops in order to reduce the loop overhead and // potentially expose ILP opportunities. - LLVM_DEBUG(dbgs() << "LV: Loop cost is " << LoopCost << '\n'); + LLVM_DEBUG(dbgs() << "LV: Loop cost is " << LoopCost << '\n' + << "LV: IC is " << IC << '\n' + << "LV: VF is " << VF << '\n'); + const bool AggressivelyInterleaveReductions = + TTI.enableAggressiveInterleaving(HasReductions); if (!InterleavingRequiresRuntimePointerCheck && LoopCost < SmallLoopCost) { // We assume that the cost overhead is 1 and we use the cost model // to estimate the cost of the loop and interleave until the cost of the @@ -5382,7 +6200,7 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, // by this point), we can increase the critical path length if the loop // we're interleaving is inside another loop. Limit, by default to 2, so the // critical path only gets increased by one reduction operation. - if (!Legal->getReductionVars().empty() && TheLoop->getLoopDepth() > 1) { + if (HasReductions && TheLoop->getLoopDepth() > 1) { unsigned F = static_cast(MaxNestedScalarReductionIC); SmallIC = std::min(SmallIC, F); StoresIC = std::min(StoresIC, F); @@ -5396,14 +6214,23 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, return std::max(StoresIC, LoadsIC); } - LLVM_DEBUG(dbgs() << "LV: Interleaving to reduce branch cost.\n"); - return SmallIC; + // If there are scalar reductions and TTI has enabled aggressive + // interleaving for reductions, we will interleave to expose ILP. + if (InterleaveSmallLoopScalarReduction && VF.isScalar() && + AggressivelyInterleaveReductions) { + LLVM_DEBUG(dbgs() << "LV: Interleaving to expose ILP.\n"); + // Interleave no less than SmallIC but not as aggressive as the normal IC + // to satisfy the rare situation when resources are too limited. + return std::max(IC / 2, SmallIC); + } else { + LLVM_DEBUG(dbgs() << "LV: Interleaving to reduce branch cost.\n"); + return SmallIC; + } } // Interleave if this is a large loop (small loops are already dealt with by // this point) that could benefit from interleaving. - bool HasReductions = !Legal->getReductionVars().empty(); - if (TTI.enableAggressiveInterleaving(HasReductions)) { + if (AggressivelyInterleaveReductions) { LLVM_DEBUG(dbgs() << "LV: Interleaving to expose ILP.\n"); return IC; } @@ -5413,7 +6240,7 @@ unsigned LoopVectorizationCostModel::selectInterleaveCount(unsigned VF, } SmallVector -LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { +LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { // This function calculates the register usage by measuring the highest number // of values that are alive at a single location. Obviously, this is a very // rough estimation. We scan the loop in a topological order in order and @@ -5485,26 +6312,17 @@ LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { TransposeEnds[Interval.second].push_back(Interval.first); SmallPtrSet OpenIntervals; - - // Get the size of the widest register. - unsigned MaxSafeDepDist = -1U; - if (Legal->getMaxSafeDepDistBytes() != -1U) - MaxSafeDepDist = Legal->getMaxSafeDepDistBytes() * 8; - unsigned WidestRegister = - std::min(TTI.getRegisterBitWidth(true), MaxSafeDepDist); - const DataLayout &DL = TheFunction->getParent()->getDataLayout(); - SmallVector RUs(VFs.size()); SmallVector, 8> MaxUsages(VFs.size()); LLVM_DEBUG(dbgs() << "LV(REG): Calculating max register usage:\n"); // A lambda that gets the register usage for the given type and VF. - auto GetRegUsage = [&DL, WidestRegister](Type *Ty, unsigned VF) { - if (Ty->isTokenTy()) + const auto &TTICapture = TTI; + auto GetRegUsage = [&TTICapture](Type *Ty, ElementCount VF) { + if (Ty->isTokenTy() || !VectorType::isValidElementType(Ty)) return 0U; - unsigned TypeSize = DL.getTypeSizeInBits(Ty->getScalarType()); - return std::max(1, VF * TypeSize / WidestRegister); + return TTICapture.getRegUsageForType(VectorType::get(Ty, VF)); }; for (unsigned int i = 0, s = IdxToInstr.size(); i < s; ++i) { @@ -5528,7 +6346,7 @@ LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { // Count the number of live intervals. SmallMapVector RegUsage; - if (VFs[j] == 1) { + if (VFs[j].isScalar()) { for (auto Inst : OpenIntervals) { unsigned ClassID = TTI.getRegisterClassForType(false, Inst->getType()); if (RegUsage.find(ClassID) == RegUsage.end()) @@ -5557,7 +6375,7 @@ LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { } } } - + for (auto& pair : RegUsage) { if (MaxUsages[j].find(pair.first) != MaxUsages[j].end()) MaxUsages[j][pair.first] = std::max(MaxUsages[j][pair.first], pair.second); @@ -5575,10 +6393,12 @@ LoopVectorizationCostModel::calculateRegisterUsage(ArrayRef VFs) { for (unsigned i = 0, e = VFs.size(); i < e; ++i) { SmallMapVector Invariant; - + for (auto Inst : LoopInvariants) { - unsigned Usage = VFs[i] == 1 ? 1 : GetRegUsage(Inst->getType(), VFs[i]); - unsigned ClassID = TTI.getRegisterClassForType(VFs[i] > 1, Inst->getType()); + unsigned Usage = + VFs[i].isScalar() ? 1 : GetRegUsage(Inst->getType(), VFs[i]); + unsigned ClassID = + TTI.getRegisterClassForType(VFs[i].isVector(), Inst->getType()); if (Invariant.find(ClassID) == Invariant.end()) Invariant[ClassID] = Usage; else @@ -5626,12 +6446,13 @@ bool LoopVectorizationCostModel::useEmulatedMaskMemRefHack(Instruction *I){ NumPredStores > NumberOfStoresToPredicate); } -void LoopVectorizationCostModel::collectInstsToScalarize(unsigned VF) { +void LoopVectorizationCostModel::collectInstsToScalarize(ElementCount VF) { // If we aren't vectorizing the loop, or if we've already collected the // instructions to scalarize, there's nothing to do. Collection may already // have occurred if we have a user-selected VF and are now computing the // expected cost for interleaving. - if (VF < 2 || InstsToScalarize.find(VF) != InstsToScalarize.end()) + if (VF.isScalar() || VF.isZero() || + InstsToScalarize.find(VF) != InstsToScalarize.end()) return; // Initialize a mapping for VF in InstsToScalalarize. If we find that it's @@ -5660,14 +6481,13 @@ void LoopVectorizationCostModel::collectInstsToScalarize(unsigned VF) { } int LoopVectorizationCostModel::computePredInstDiscount( - Instruction *PredInst, DenseMap &ScalarCosts, - unsigned VF) { + Instruction *PredInst, ScalarCostsTy &ScalarCosts, ElementCount VF) { assert(!isUniformAfterVectorization(PredInst, VF) && "Instruction marked uniform-after-vectorization will be predicated"); // Initialize the discount to zero, meaning that the scalar version and the // vector version cost the same. - int Discount = 0; + InstructionCost Discount = 0; // Holds instructions to analyze. The instructions we visit are mapped in // ScalarCosts. Those instructions are the ones that would be scalarized if @@ -5722,22 +6542,27 @@ int LoopVectorizationCostModel::computePredInstDiscount( // Compute the cost of the vector instruction. Note that this cost already // includes the scalarization overhead of the predicated instruction. - unsigned VectorCost = getInstructionCost(I, VF).first; + InstructionCost VectorCost = getInstructionCost(I, VF).first; // Compute the cost of the scalarized instruction. This cost is the cost of // the instruction as if it wasn't if-converted and instead remained in the // predicated block. We will scale this cost by block probability after // computing the scalarization overhead. - unsigned ScalarCost = VF * getInstructionCost(I, 1).first; + assert(!VF.isScalable() && "scalable vectors not yet supported."); + InstructionCost ScalarCost = + VF.getKnownMinValue() * + getInstructionCost(I, ElementCount::getFixed(1)).first; // Compute the scalarization overhead of needed insertelement instructions // and phi nodes. if (isScalarWithPredication(I) && !I->getType()->isVoidTy()) { ScalarCost += TTI.getScalarizationOverhead( cast(ToVectorTy(I->getType(), VF)), - APInt::getAllOnesValue(VF), true, false); - ScalarCost += VF * TTI.getCFInstrCost(Instruction::PHI, - TTI::TCK_RecipThroughput); + APInt::getAllOnesValue(VF.getKnownMinValue()), true, false); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + ScalarCost += + VF.getKnownMinValue() * + TTI.getCFInstrCost(Instruction::PHI, TTI::TCK_RecipThroughput); } // Compute the scalarization overhead of needed extractelement @@ -5750,10 +6575,12 @@ int LoopVectorizationCostModel::computePredInstDiscount( "Instruction has non-scalar type"); if (canBeScalarized(J)) Worklist.push_back(J); - else if (needsExtract(J, VF)) + else if (needsExtract(J, VF)) { + assert(!VF.isScalable() && "scalable vectors not yet supported."); ScalarCost += TTI.getScalarizationOverhead( cast(ToVectorTy(J->getType(), VF)), - APInt::getAllOnesValue(VF), false, true); + APInt::getAllOnesValue(VF.getKnownMinValue()), false, true); + } } // Scale the total scalar cost by block probability. @@ -5765,11 +6592,11 @@ int LoopVectorizationCostModel::computePredInstDiscount( ScalarCosts[I] = ScalarCost; } - return Discount; + return *Discount.getValue(); } LoopVectorizationCostModel::VectorizationCostTy -LoopVectorizationCostModel::expectedCost(unsigned VF) { +LoopVectorizationCostModel::expectedCost(ElementCount VF) { VectorizationCostTy Cost; // For each block. @@ -5779,14 +6606,15 @@ LoopVectorizationCostModel::expectedCost(unsigned VF) { // For each instruction in the old loop. for (Instruction &I : BB->instructionsWithoutDebug()) { // Skip ignored values. - if (ValuesToIgnore.count(&I) || (VF > 1 && VecValuesToIgnore.count(&I))) + if (ValuesToIgnore.count(&I) || + (VF.isVector() && VecValuesToIgnore.count(&I))) continue; VectorizationCostTy C = getInstructionCost(&I, VF); // Check if we should override the cost. if (ForceTargetInstructionCost.getNumOccurrences() > 0) - C.first = ForceTargetInstructionCost; + C.first = InstructionCost(ForceTargetInstructionCost); BlockCost.first += C.first; BlockCost.second |= C.second; @@ -5799,9 +6627,10 @@ LoopVectorizationCostModel::expectedCost(unsigned VF) { // if-converted. This means that the block's instructions (aside from // stores and instructions that may divide by zero) will now be // unconditionally executed. For the scalar case, we may not always execute - // the predicated block. Thus, scale the block's cost by the probability of - // executing it. - if (VF == 1 && blockNeedsPredication(BB)) + // the predicated block, if it is an if-else block. Thus, scale the block's + // cost by the probability of executing it. blockNeedsPredication from + // Legal is used so as to not include all blocks in tail folded loops. + if (VF.isScalar() && Legal->blockNeedsPredication(BB)) BlockCost.first /= getReciprocalPredBlockProb(); Cost.first += BlockCost.first; @@ -5846,9 +6675,12 @@ static bool isStrideMul(Instruction *I, LoopVectorizationLegality *Legal) { Legal->hasStride(I->getOperand(1)); } -unsigned LoopVectorizationCostModel::getMemInstScalarizationCost(Instruction *I, - unsigned VF) { - assert(VF > 1 && "Scalarization cost of instruction implies vectorization."); +InstructionCost +LoopVectorizationCostModel::getMemInstScalarizationCost(Instruction *I, + ElementCount VF) { + assert(VF.isVector() && + "Scalarization cost of instruction implies vectorization."); + assert(!VF.isScalable() && "scalable vectors not yet supported."); Type *ValTy = getMemInstValueType(I); auto SE = PSE.getSE(); @@ -5861,14 +6693,15 @@ unsigned LoopVectorizationCostModel::getMemInstScalarizationCost(Instruction *I, const SCEV *PtrSCEV = getAddressAccessSCEV(Ptr, Legal, PSE, TheLoop); // Get the cost of the scalar memory instruction and address computation. - unsigned Cost = VF * TTI.getAddressComputationCost(PtrTy, SE, PtrSCEV); + InstructionCost Cost = + VF.getKnownMinValue() * TTI.getAddressComputationCost(PtrTy, SE, PtrSCEV); // Don't pass *I here, since it is scalar but will actually be part of a // vectorized loop where the user of it is a vectorized instruction. const Align Alignment = getLoadStoreAlignment(I); - Cost += VF * TTI.getMemoryOpCost(I->getOpcode(), ValTy->getScalarType(), - Alignment, AS, - TTI::TCK_RecipThroughput); + Cost += VF.getKnownMinValue() * + TTI.getMemoryOpCost(I->getOpcode(), ValTy->getScalarType(), Alignment, + AS, TTI::TCK_RecipThroughput); // Get the overhead of the extractelement and insertelement instructions // we might create due to scalarization. @@ -5889,8 +6722,9 @@ unsigned LoopVectorizationCostModel::getMemInstScalarizationCost(Instruction *I, return Cost; } -unsigned LoopVectorizationCostModel::getConsecutiveMemOpCost(Instruction *I, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getConsecutiveMemOpCost(Instruction *I, + ElementCount VF) { Type *ValTy = getMemInstValueType(I); auto *VectorTy = cast(ToVectorTy(ValTy, VF)); Value *Ptr = getLoadStorePointerOperand(I); @@ -5901,7 +6735,7 @@ unsigned LoopVectorizationCostModel::getConsecutiveMemOpCost(Instruction *I, assert((ConsecutiveStride == 1 || ConsecutiveStride == -1) && "Stride should be 1 or -1 for consecutive memory access"); const Align Alignment = getLoadStoreAlignment(I); - unsigned Cost = 0; + InstructionCost Cost = 0; if (Legal->isMaskRequired(I)) Cost += TTI.getMaskedMemoryOpCost(I->getOpcode(), VectorTy, Alignment, AS, CostKind); @@ -5915,8 +6749,11 @@ unsigned LoopVectorizationCostModel::getConsecutiveMemOpCost(Instruction *I, return Cost; } -unsigned LoopVectorizationCostModel::getUniformMemOpCost(Instruction *I, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getUniformMemOpCost(Instruction *I, + ElementCount VF) { + assert(Legal->isUniformMemOp(*I)); + Type *ValTy = getMemInstValueType(I); auto *VectorTy = cast(ToVectorTy(ValTy, VF)); const Align Alignment = getLoadStoreAlignment(I); @@ -5937,11 +6774,12 @@ unsigned LoopVectorizationCostModel::getUniformMemOpCost(Instruction *I, (isLoopInvariantStoreValue ? 0 : TTI.getVectorInstrCost(Instruction::ExtractElement, VectorTy, - VF - 1)); + VF.getKnownMinValue() - 1)); } -unsigned LoopVectorizationCostModel::getGatherScatterCost(Instruction *I, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getGatherScatterCost(Instruction *I, + ElementCount VF) { Type *ValTy = getMemInstValueType(I); auto *VectorTy = cast(ToVectorTy(ValTy, VF)); const Align Alignment = getLoadStoreAlignment(I); @@ -5953,8 +6791,9 @@ unsigned LoopVectorizationCostModel::getGatherScatterCost(Instruction *I, TargetTransformInfo::TCK_RecipThroughput, I); } -unsigned LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I, + ElementCount VF) { Type *ValTy = getMemInstValueType(I); auto *VectorTy = cast(ToVectorTy(ValTy, VF)); unsigned AS = getLoadStoreAddressSpace(I); @@ -5963,7 +6802,8 @@ unsigned LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I, assert(Group && "Fail to get an interleaved access group."); unsigned InterleaveFactor = Group->getFactor(); - auto *WideVecTy = FixedVectorType::get(ValTy, VF * InterleaveFactor); + assert(!VF.isScalable() && "scalable vectors not yet supported."); + auto *WideVecTy = VectorType::get(ValTy, VF * InterleaveFactor); // Holds the indices of existing members in an interleaved load group. // An interleaved store group doesn't need this as it doesn't allow gaps. @@ -5977,7 +6817,7 @@ unsigned LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I, // Calculate the cost of the whole interleaved group. bool UseMaskForGaps = Group->requiresScalarEpilogue() && !isScalarEpilogueAllowed(); - unsigned Cost = TTI.getInterleavedMemoryOpCost( + InstructionCost Cost = TTI.getInterleavedMemoryOpCost( I->getOpcode(), WideVecTy, Group->getFactor(), Indices, Group->getAlign(), AS, TTI::TCK_RecipThroughput, Legal->isMaskRequired(I), UseMaskForGaps); @@ -5991,11 +6831,122 @@ unsigned LoopVectorizationCostModel::getInterleaveGroupCost(Instruction *I, return Cost; } -unsigned LoopVectorizationCostModel::getMemoryInstructionCost(Instruction *I, - unsigned VF) { +InstructionCost LoopVectorizationCostModel::getReductionPatternCost( + Instruction *I, ElementCount VF, Type *Ty, TTI::TargetCostKind CostKind) { + // Early exit for no inloop reductions + if (InLoopReductionChains.empty() || VF.isScalar() || !isa(Ty)) + return InstructionCost::getInvalid(); + auto *VectorTy = cast(Ty); + + // We are looking for a pattern of, and finding the minimal acceptable cost: + // reduce(mul(ext(A), ext(B))) or + // reduce(mul(A, B)) or + // reduce(ext(A)) or + // reduce(A). + // The basic idea is that we walk down the tree to do that, finding the root + // reduction instruction in InLoopReductionImmediateChains. From there we find + // the pattern of mul/ext and test the cost of the entire pattern vs the cost + // of the components. If the reduction cost is lower then we return it for the + // reduction instruction and 0 for the other instructions in the pattern. If + // it is not we return an invalid cost specifying the orignal cost method + // should be used. + Instruction *RetI = I; + if ((RetI->getOpcode() == Instruction::SExt || + RetI->getOpcode() == Instruction::ZExt)) { + if (!RetI->hasOneUser()) + return InstructionCost::getInvalid(); + RetI = RetI->user_back(); + } + if (RetI->getOpcode() == Instruction::Mul && + RetI->user_back()->getOpcode() == Instruction::Add) { + if (!RetI->hasOneUser()) + return InstructionCost::getInvalid(); + RetI = RetI->user_back(); + } + + // Test if the found instruction is a reduction, and if not return an invalid + // cost specifying the parent to use the original cost modelling. + if (!InLoopReductionImmediateChains.count(RetI)) + return InstructionCost::getInvalid(); + + // Find the reduction this chain is a part of and calculate the basic cost of + // the reduction on its own. + Instruction *LastChain = InLoopReductionImmediateChains[RetI]; + Instruction *ReductionPhi = LastChain; + while (!isa(ReductionPhi)) + ReductionPhi = InLoopReductionImmediateChains[ReductionPhi]; + + RecurrenceDescriptor RdxDesc = + Legal->getReductionVars()[cast(ReductionPhi)]; + unsigned BaseCost = TTI.getArithmeticReductionCost(RdxDesc.getOpcode(), + VectorTy, false, CostKind); + + // Get the operand that was not the reduction chain and match it to one of the + // patterns, returning the better cost if it is found. + Instruction *RedOp = RetI->getOperand(1) == LastChain + ? dyn_cast(RetI->getOperand(0)) + : dyn_cast(RetI->getOperand(1)); + + VectorTy = VectorType::get(I->getOperand(0)->getType(), VectorTy); + + if (RedOp && (isa(RedOp) || isa(RedOp)) && + !TheLoop->isLoopInvariant(RedOp)) { + bool IsUnsigned = isa(RedOp); + auto *ExtType = VectorType::get(RedOp->getOperand(0)->getType(), VectorTy); + InstructionCost RedCost = TTI.getExtendedAddReductionCost( + /*IsMLA=*/false, IsUnsigned, RdxDesc.getRecurrenceType(), ExtType, + CostKind); + + unsigned ExtCost = + TTI.getCastInstrCost(RedOp->getOpcode(), VectorTy, ExtType, + TTI::CastContextHint::None, CostKind, RedOp); + if (RedCost.isValid() && RedCost < BaseCost + ExtCost) + return I == RetI ? *RedCost.getValue() : 0; + } else if (RedOp && RedOp->getOpcode() == Instruction::Mul) { + Instruction *Mul = RedOp; + Instruction *Op0 = dyn_cast(Mul->getOperand(0)); + Instruction *Op1 = dyn_cast(Mul->getOperand(1)); + if (Op0 && Op1 && (isa(Op0) || isa(Op0)) && + Op0->getOpcode() == Op1->getOpcode() && + Op0->getOperand(0)->getType() == Op1->getOperand(0)->getType() && + !TheLoop->isLoopInvariant(Op0) && !TheLoop->isLoopInvariant(Op1)) { + bool IsUnsigned = isa(Op0); + auto *ExtType = VectorType::get(Op0->getOperand(0)->getType(), VectorTy); + // reduce(mul(ext, ext)) + unsigned ExtCost = + TTI.getCastInstrCost(Op0->getOpcode(), VectorTy, ExtType, + TTI::CastContextHint::None, CostKind, Op0); + unsigned MulCost = + TTI.getArithmeticInstrCost(Mul->getOpcode(), VectorTy, CostKind); + + InstructionCost RedCost = TTI.getExtendedAddReductionCost( + /*IsMLA=*/true, IsUnsigned, RdxDesc.getRecurrenceType(), ExtType, + CostKind); + + if (RedCost.isValid() && RedCost < ExtCost * 2 + MulCost + BaseCost) + return I == RetI ? *RedCost.getValue() : 0; + } else { + unsigned MulCost = + TTI.getArithmeticInstrCost(Mul->getOpcode(), VectorTy, CostKind); + + InstructionCost RedCost = TTI.getExtendedAddReductionCost( + /*IsMLA=*/true, true, RdxDesc.getRecurrenceType(), VectorTy, + CostKind); + + if (RedCost.isValid() && RedCost < MulCost + BaseCost) + return I == RetI ? *RedCost.getValue() : 0; + } + } + + return I == RetI ? BaseCost : InstructionCost::getInvalid(); +} + +InstructionCost +LoopVectorizationCostModel::getMemoryInstructionCost(Instruction *I, + ElementCount VF) { // Calculate scalar cost only. Vectorization cost should be ready at this // moment. - if (VF == 1) { + if (VF.isScalar()) { Type *ValTy = getMemInstValueType(I); const Align Alignment = getLoadStoreAlignment(I); unsigned AS = getLoadStoreAddressSpace(I); @@ -6008,43 +6959,52 @@ unsigned LoopVectorizationCostModel::getMemoryInstructionCost(Instruction *I, } LoopVectorizationCostModel::VectorizationCostTy -LoopVectorizationCostModel::getInstructionCost(Instruction *I, unsigned VF) { +LoopVectorizationCostModel::getInstructionCost(Instruction *I, + ElementCount VF) { // If we know that this instruction will remain uniform, check the cost of // the scalar version. if (isUniformAfterVectorization(I, VF)) - VF = 1; + VF = ElementCount::getFixed(1); - if (VF > 1 && isProfitableToScalarize(I, VF)) + if (VF.isVector() && isProfitableToScalarize(I, VF)) return VectorizationCostTy(InstsToScalarize[VF][I], false); // Forced scalars do not have any scalarization overhead. auto ForcedScalar = ForcedScalars.find(VF); - if (VF > 1 && ForcedScalar != ForcedScalars.end()) { + if (VF.isVector() && ForcedScalar != ForcedScalars.end()) { auto InstSet = ForcedScalar->second; if (InstSet.count(I)) - return VectorizationCostTy((getInstructionCost(I, 1).first * VF), false); + return VectorizationCostTy( + (getInstructionCost(I, ElementCount::getFixed(1)).first * + VF.getKnownMinValue()), + false); } Type *VectorTy; - unsigned C = getInstructionCost(I, VF, VectorTy); + InstructionCost C = getInstructionCost(I, VF, VectorTy); bool TypeNotScalarized = - VF > 1 && VectorTy->isVectorTy() && TTI.getNumberOfParts(VectorTy) < VF; + VF.isVector() && VectorTy->isVectorTy() && + TTI.getNumberOfParts(VectorTy) < VF.getKnownMinValue(); return VectorizationCostTy(C, TypeNotScalarized); } -unsigned LoopVectorizationCostModel::getScalarizationOverhead(Instruction *I, - unsigned VF) { +InstructionCost +LoopVectorizationCostModel::getScalarizationOverhead(Instruction *I, + ElementCount VF) { - if (VF == 1) + assert(!VF.isScalable() && + "cannot compute scalarization overhead for scalable vectorization"); + if (VF.isScalar()) return 0; - unsigned Cost = 0; + InstructionCost Cost = 0; Type *RetTy = ToVectorTy(I->getType(), VF); if (!RetTy->isVoidTy() && (!isa(I) || !TTI.supportsEfficientVectorElementLoadStore())) Cost += TTI.getScalarizationOverhead( - cast(RetTy), APInt::getAllOnesValue(VF), true, false); + cast(RetTy), APInt::getAllOnesValue(VF.getKnownMinValue()), + true, false); // Some targets keep addresses scalar. if (isa(I) && !TTI.prefersVectorizedAddressing()) @@ -6061,11 +7021,11 @@ unsigned LoopVectorizationCostModel::getScalarizationOverhead(Instruction *I, // Skip operands that do not require extraction/scalarization and do not incur // any overhead. return Cost + TTI.getOperandsScalarizationOverhead( - filterExtractingOperands(Ops, VF), VF); + filterExtractingOperands(Ops, VF), VF.getKnownMinValue()); } -void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { - if (VF == 1) +void LoopVectorizationCostModel::setCostBasedWideningDecision(ElementCount VF) { + if (VF.isScalar()) return; NumPredStores = 0; for (BasicBlock *BB : TheLoop->blocks()) { @@ -6082,23 +7042,19 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { if (isa(&I) && isScalarWithPredication(&I)) NumPredStores++; - if (Legal->isUniform(Ptr) && - // Conditional loads and stores should be scalarized and predicated. - // isScalarWithPredication cannot be used here since masked - // gather/scatters are not considered scalar with predication. - !Legal->blockNeedsPredication(I.getParent())) { + if (Legal->isUniformMemOp(I)) { // TODO: Avoid replicating loads and stores instead of // relying on instcombine to remove them. // Load: Scalar load + broadcast // Store: Scalar store + isLoopInvariantStoreValue ? 0 : extract - unsigned Cost = getUniformMemOpCost(&I, VF); + InstructionCost Cost = getUniformMemOpCost(&I, VF); setWideningDecision(&I, VF, CM_Scalarize, Cost); continue; } // We assume that widening is the best solution when possible. if (memoryInstructionCanBeWidened(&I, VF)) { - unsigned Cost = getConsecutiveMemOpCost(&I, VF); + InstructionCost Cost = getConsecutiveMemOpCost(&I, VF); int ConsecutiveStride = Legal->isConsecutivePtr(getLoadStorePointerOperand(&I)); assert((ConsecutiveStride == 1 || ConsecutiveStride == -1) && @@ -6110,7 +7066,7 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { } // Choose between Interleaving, Gather/Scatter or Scalarization. - unsigned InterleaveCost = std::numeric_limits::max(); + InstructionCost InterleaveCost = std::numeric_limits::max(); unsigned NumAccesses = 1; if (isAccessInterleaved(&I)) { auto Group = getInterleavedAccessGroup(&I); @@ -6125,17 +7081,17 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { InterleaveCost = getInterleaveGroupCost(&I, VF); } - unsigned GatherScatterCost = + InstructionCost GatherScatterCost = isLegalGatherOrScatter(&I) ? getGatherScatterCost(&I, VF) * NumAccesses - : std::numeric_limits::max(); + : std::numeric_limits::max(); - unsigned ScalarizationCost = + InstructionCost ScalarizationCost = getMemInstScalarizationCost(&I, VF) * NumAccesses; // Choose better solution for the current VF, // write down this decision and use it during vectorization. - unsigned Cost; + InstructionCost Cost; InstWidening Decision; if (InterleaveCost <= GatherScatterCost && InterleaveCost < ScalarizationCost) { @@ -6179,8 +7135,7 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { // Add all instructions used to generate the addresses. SmallVector Worklist; - for (auto *I : AddrDefs) - Worklist.push_back(I); + append_range(Worklist, AddrDefs); while (!Worklist.empty()) { Instruction *I = Worklist.pop_back_val(); for (auto &Op : I->operands()) @@ -6199,14 +7154,18 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { InstWidening Decision = getWideningDecision(I, VF); if (Decision == CM_Widen || Decision == CM_Widen_Reverse) // Scalarize a widened load of address. - setWideningDecision(I, VF, CM_Scalarize, - (VF * getMemoryInstructionCost(I, 1))); + setWideningDecision( + I, VF, CM_Scalarize, + (VF.getKnownMinValue() * + getMemoryInstructionCost(I, ElementCount::getFixed(1)))); else if (auto Group = getInterleavedAccessGroup(I)) { // Scalarize an interleave group of address loads. for (unsigned I = 0; I < Group->getFactor(); ++I) { if (Instruction *Member = Group->getMember(I)) - setWideningDecision(Member, VF, CM_Scalarize, - (VF * getMemoryInstructionCost(Member, 1))); + setWideningDecision( + Member, VF, CM_Scalarize, + (VF.getKnownMinValue() * + getMemoryInstructionCost(Member, ElementCount::getFixed(1)))); } } } else @@ -6216,9 +7175,9 @@ void LoopVectorizationCostModel::setCostBasedWideningDecision(unsigned VF) { } } -unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, - unsigned VF, - Type *&VectorTy) { +InstructionCost +LoopVectorizationCostModel::getInstructionCost(Instruction *I, ElementCount VF, + Type *&VectorTy) { Type *RetTy = I->getType(); if (canTruncateToMinimalBitwidth(I, VF)) RetTy = IntegerType::get(RetTy->getContext(), MinBWs[I]); @@ -6240,19 +7199,22 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, // blocks requires also an extract of its vector compare i1 element. bool ScalarPredicatedBB = false; BranchInst *BI = cast(I); - if (VF > 1 && BI->isConditional() && + if (VF.isVector() && BI->isConditional() && (PredicatedBBsAfterVectorization.count(BI->getSuccessor(0)) || PredicatedBBsAfterVectorization.count(BI->getSuccessor(1)))) ScalarPredicatedBB = true; if (ScalarPredicatedBB) { // Return cost for branches around scalarized and predicated blocks. + assert(!VF.isScalable() && "scalable vectors not yet supported."); auto *Vec_i1Ty = - FixedVectorType::get(IntegerType::getInt1Ty(RetTy->getContext()), VF); - return (TTI.getScalarizationOverhead(Vec_i1Ty, APInt::getAllOnesValue(VF), - false, true) + - (TTI.getCFInstrCost(Instruction::Br, CostKind) * VF)); - } else if (I->getParent() == TheLoop->getLoopLatch() || VF == 1) + VectorType::get(IntegerType::getInt1Ty(RetTy->getContext()), VF); + return (TTI.getScalarizationOverhead( + Vec_i1Ty, APInt::getAllOnesValue(VF.getKnownMinValue()), + false, true) + + (TTI.getCFInstrCost(Instruction::Br, CostKind) * + VF.getKnownMinValue())); + } else if (I->getParent() == TheLoop->getLoopLatch() || VF.isScalar()) // The back-edge branch will remain, as will all scalar branches. return TTI.getCFInstrCost(Instruction::Br, CostKind); else @@ -6267,20 +7229,20 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, // First-order recurrences are replaced by vector shuffles inside the loop. // NOTE: Don't use ToVectorTy as SK_ExtractSubvector expects a vector type. - if (VF > 1 && Legal->isFirstOrderRecurrence(Phi)) - return TTI.getShuffleCost(TargetTransformInfo::SK_ExtractSubvector, - cast(VectorTy), VF - 1, - FixedVectorType::get(RetTy, 1)); + if (VF.isVector() && Legal->isFirstOrderRecurrence(Phi)) + return TTI.getShuffleCost( + TargetTransformInfo::SK_ExtractSubvector, cast(VectorTy), + VF.getKnownMinValue() - 1, FixedVectorType::get(RetTy, 1)); // Phi nodes in non-header blocks (not inductions, reductions, etc.) are // converted into select instructions. We require N - 1 selects per phi // node, where N is the number of incoming values. - if (VF > 1 && Phi->getParent() != TheLoop->getHeader()) + if (VF.isVector() && Phi->getParent() != TheLoop->getHeader()) return (Phi->getNumIncomingValues() - 1) * TTI.getCmpSelInstrCost( Instruction::Select, ToVectorTy(Phi->getType(), VF), ToVectorTy(Type::getInt1Ty(Phi->getContext()), VF), - CostKind); + CmpInst::BAD_ICMP_PREDICATE, CostKind); return TTI.getCFInstrCost(Instruction::PHI, CostKind); } @@ -6292,17 +7254,19 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, // vector lane. Get the scalarization cost and scale this amount by the // probability of executing the predicated block. If the instruction is not // predicated, we fall through to the next case. - if (VF > 1 && isScalarWithPredication(I)) { - unsigned Cost = 0; + if (VF.isVector() && isScalarWithPredication(I)) { + InstructionCost Cost = 0; // These instructions have a non-void type, so account for the phi nodes // that we will create. This cost is likely to be zero. The phi node // cost, if any, should be scaled by the block probability because it // models a copy at the end of each predicated block. - Cost += VF * TTI.getCFInstrCost(Instruction::PHI, CostKind); + Cost += VF.getKnownMinValue() * + TTI.getCFInstrCost(Instruction::PHI, CostKind); // The cost of the non-predicated instruction. - Cost += VF * TTI.getArithmeticInstrCost(I->getOpcode(), RetTy, CostKind); + Cost += VF.getKnownMinValue() * + TTI.getArithmeticInstrCost(I->getOpcode(), RetTy, CostKind); // The cost of insertelement and extractelement instructions needed for // scalarization. @@ -6331,6 +7295,13 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, // Since we will replace the stride by 1 the multiplication should go away. if (I->getOpcode() == Instruction::Mul && isStrideMul(I, Legal)) return 0; + + // Detect reduction patterns + InstructionCost RedCost; + if ((RedCost = getReductionPatternCost(I, VF, VectorTy, CostKind)) + .isValid()) + return RedCost; + // Certain instructions can be cheaper to vectorize if they have a constant // second vector operand. One example of this are shifts on x86. Value *Op2 = I->getOperand(1); @@ -6341,14 +7312,15 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, Op2VK = TargetTransformInfo::OK_UniformValue; SmallVector Operands(I->operand_values()); - unsigned N = isScalarAfterVectorization(I, VF) ? VF : 1; + unsigned N = isScalarAfterVectorization(I, VF) ? VF.getKnownMinValue() : 1; return N * TTI.getArithmeticInstrCost( I->getOpcode(), VectorTy, CostKind, TargetTransformInfo::OK_AnyValue, Op2VK, TargetTransformInfo::OP_None, Op2VP, Operands, I); } case Instruction::FNeg: { - unsigned N = isScalarAfterVectorization(I, VF) ? VF : 1; + assert(!VF.isScalable() && "VF is assumed to be non scalable."); + unsigned N = isScalarAfterVectorization(I, VF) ? VF.getKnownMinValue() : 1; return N * TTI.getArithmeticInstrCost( I->getOpcode(), VectorTy, CostKind, TargetTransformInfo::OK_AnyValue, @@ -6362,10 +7334,9 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, bool ScalarCond = (SE->isLoopInvariant(CondSCEV, TheLoop)); Type *CondTy = SI->getCondition()->getType(); if (!ScalarCond) - CondTy = FixedVectorType::get(CondTy, VF); - + CondTy = VectorType::get(CondTy, VF); return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, CondTy, - CostKind, I); + CmpInst::BAD_ICMP_PREDICATE, CostKind, I); } case Instruction::ICmp: case Instruction::FCmp: { @@ -6374,18 +7345,18 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, if (canTruncateToMinimalBitwidth(Op0AsInstruction, VF)) ValTy = IntegerType::get(ValTy->getContext(), MinBWs[Op0AsInstruction]); VectorTy = ToVectorTy(ValTy, VF); - return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, nullptr, CostKind, - I); + return TTI.getCmpSelInstrCost(I->getOpcode(), VectorTy, nullptr, + CmpInst::BAD_ICMP_PREDICATE, CostKind, I); } case Instruction::Store: case Instruction::Load: { - unsigned Width = VF; - if (Width > 1) { + ElementCount Width = VF; + if (Width.isVector()) { InstWidening Decision = getWideningDecision(I, Width); assert(Decision != CM_Unknown && "CM decision should be taken at this point"); if (Decision == CM_Scalarize) - Width = 1; + Width = ElementCount::getFixed(1); } VectorTy = ToVectorTy(getMemInstValueType(I), Width); return getMemoryInstructionCost(I, VF); @@ -6402,15 +7373,62 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, case Instruction::Trunc: case Instruction::FPTrunc: case Instruction::BitCast: { + // Computes the CastContextHint from a Load/Store instruction. + auto ComputeCCH = [&](Instruction *I) -> TTI::CastContextHint { + assert((isa(I) || isa(I)) && + "Expected a load or a store!"); + + if (VF.isScalar() || !TheLoop->contains(I)) + return TTI::CastContextHint::Normal; + + switch (getWideningDecision(I, VF)) { + case LoopVectorizationCostModel::CM_GatherScatter: + return TTI::CastContextHint::GatherScatter; + case LoopVectorizationCostModel::CM_Interleave: + return TTI::CastContextHint::Interleave; + case LoopVectorizationCostModel::CM_Scalarize: + case LoopVectorizationCostModel::CM_Widen: + return Legal->isMaskRequired(I) ? TTI::CastContextHint::Masked + : TTI::CastContextHint::Normal; + case LoopVectorizationCostModel::CM_Widen_Reverse: + return TTI::CastContextHint::Reversed; + case LoopVectorizationCostModel::CM_Unknown: + llvm_unreachable("Instr did not go through cost modelling?"); + } + + llvm_unreachable("Unhandled case!"); + }; + + unsigned Opcode = I->getOpcode(); + TTI::CastContextHint CCH = TTI::CastContextHint::None; + // For Trunc, the context is the only user, which must be a StoreInst. + if (Opcode == Instruction::Trunc || Opcode == Instruction::FPTrunc) { + if (I->hasOneUse()) + if (StoreInst *Store = dyn_cast(*I->user_begin())) + CCH = ComputeCCH(Store); + } + // For Z/Sext, the context is the operand, which must be a LoadInst. + else if (Opcode == Instruction::ZExt || Opcode == Instruction::SExt || + Opcode == Instruction::FPExt) { + if (LoadInst *Load = dyn_cast(I->getOperand(0))) + CCH = ComputeCCH(Load); + } + // We optimize the truncation of induction variables having constant // integer steps. The cost of these truncations is the same as the scalar // operation. if (isOptimizableIVTruncate(I, VF)) { auto *Trunc = cast(I); return TTI.getCastInstrCost(Instruction::Trunc, Trunc->getDestTy(), - Trunc->getSrcTy(), CostKind, Trunc); + Trunc->getSrcTy(), CCH, CostKind, Trunc); } + // Detect reduction patterns + InstructionCost RedCost; + if ((RedCost = getReductionPatternCost(I, VF, VectorTy, CostKind)) + .isValid()) + return RedCost; + Type *SrcScalarTy = I->getOperand(0)->getType(); Type *SrcVecTy = VectorTy->isVectorTy() ? ToVectorTy(SrcScalarTy, VF) : SrcScalarTy; @@ -6421,35 +7439,39 @@ unsigned LoopVectorizationCostModel::getInstructionCost(Instruction *I, // // Calculate the modified src and dest types. Type *MinVecTy = VectorTy; - if (I->getOpcode() == Instruction::Trunc) { + if (Opcode == Instruction::Trunc) { SrcVecTy = smallestIntegerVectorType(SrcVecTy, MinVecTy); VectorTy = largestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy); - } else if (I->getOpcode() == Instruction::ZExt || - I->getOpcode() == Instruction::SExt) { + } else if (Opcode == Instruction::ZExt || Opcode == Instruction::SExt) { SrcVecTy = largestIntegerVectorType(SrcVecTy, MinVecTy); VectorTy = smallestIntegerVectorType(ToVectorTy(I->getType(), VF), MinVecTy); } } - unsigned N = isScalarAfterVectorization(I, VF) ? VF : 1; - return N * TTI.getCastInstrCost(I->getOpcode(), VectorTy, SrcVecTy, - CostKind, I); + assert(!VF.isScalable() && "VF is assumed to be non scalable"); + unsigned N = isScalarAfterVectorization(I, VF) ? VF.getKnownMinValue() : 1; + return N * + TTI.getCastInstrCost(Opcode, VectorTy, SrcVecTy, CCH, CostKind, I); } case Instruction::Call: { bool NeedToScalarize; CallInst *CI = cast(I); - unsigned CallCost = getVectorCallCost(CI, VF, NeedToScalarize); - if (getVectorIntrinsicIDForCall(CI, TLI)) - return std::min(CallCost, getVectorIntrinsicCost(CI, VF)); + InstructionCost CallCost = getVectorCallCost(CI, VF, NeedToScalarize); + if (getVectorIntrinsicIDForCall(CI, TLI)) { + InstructionCost IntrinsicCost = getVectorIntrinsicCost(CI, VF); + return std::min(CallCost, IntrinsicCost); + } return CallCost; } + case Instruction::ExtractValue: + return TTI.getInstructionCost(I, TTI::TCK_RecipThroughput); default: // The cost of executing VF copies of the scalar instruction. This opcode // is unknown. Assume that it is the same as 'mul'. - return VF * TTI.getArithmeticInstrCost(Instruction::Mul, VectorTy, - CostKind) + + return VF.getKnownMinValue() * TTI.getArithmeticInstrCost( + Instruction::Mul, VectorTy, CostKind) + getScalarizationOverhead(I, VF); } // end of switch. } @@ -6502,7 +7524,7 @@ void LoopVectorizationCostModel::collectValuesToIgnore() { // detection. for (auto &Reduction : Legal->getReductionVars()) { RecurrenceDescriptor &RedDes = Reduction.second; - SmallPtrSetImpl &Casts = RedDes.getCastInsts(); + const SmallPtrSetImpl &Casts = RedDes.getCastInsts(); VecValuesToIgnore.insert(Casts.begin(), Casts.end()); } // Ignore type-casting instructions we identified during induction @@ -6514,6 +7536,43 @@ void LoopVectorizationCostModel::collectValuesToIgnore() { } } +void LoopVectorizationCostModel::collectInLoopReductions() { + for (auto &Reduction : Legal->getReductionVars()) { + PHINode *Phi = Reduction.first; + RecurrenceDescriptor &RdxDesc = Reduction.second; + + // We don't collect reductions that are type promoted (yet). + if (RdxDesc.getRecurrenceType() != Phi->getType()) + continue; + + // If the target would prefer this reduction to happen "in-loop", then we + // want to record it as such. + unsigned Opcode = RdxDesc.getOpcode(); + if (!PreferInLoopReductions && + !TTI.preferInLoopReduction(Opcode, Phi->getType(), + TargetTransformInfo::ReductionFlags())) + continue; + + // Check that we can correctly put the reductions into the loop, by + // finding the chain of operations that leads from the phi to the loop + // exit value. + SmallVector ReductionOperations = + RdxDesc.getReductionOpChain(Phi, TheLoop); + bool InLoop = !ReductionOperations.empty(); + if (InLoop) { + InLoopReductionChains[Phi] = ReductionOperations; + // Add the elements to InLoopReductionImmediateChains for cost modelling. + Instruction *LastChain = Phi; + for (auto *I : ReductionOperations) { + InLoopReductionImmediateChains[I] = LastChain; + LastChain = I; + } + } + LLVM_DEBUG(dbgs() << "LV: Using " << (InLoop ? "inloop" : "out of loop") + << " reduction for phi: " << *Phi << "\n"); + } +} + // TODO: we could return a pair of values that specify the max VF and // min VF, to be used in `buildVPlans(MinVF, MaxVF)` instead of // `buildVPlans(VF, VF)`. We cannot do it because VPLAN at the moment @@ -6527,37 +7586,40 @@ static unsigned determineVPlanVF(const unsigned WidestVectorRegBits, } VectorizationFactor -LoopVectorizationPlanner::planInVPlanNativePath(unsigned UserVF) { - unsigned VF = UserVF; +LoopVectorizationPlanner::planInVPlanNativePath(ElementCount UserVF) { + assert(!UserVF.isScalable() && "scalable vectors not yet supported"); + ElementCount VF = UserVF; // Outer loop handling: They may require CFG and instruction level // transformations before even evaluating whether vectorization is profitable. // Since we cannot modify the incoming IR, we need to build VPlan upfront in // the vectorization pipeline. - if (!OrigLoop->empty()) { + if (!OrigLoop->isInnermost()) { // If the user doesn't provide a vectorization factor, determine a // reasonable one. - if (!UserVF) { - VF = determineVPlanVF(TTI->getRegisterBitWidth(true /* Vector*/), CM); + if (UserVF.isZero()) { + VF = ElementCount::getFixed( + determineVPlanVF(TTI->getRegisterBitWidth(true /* Vector*/), CM)); LLVM_DEBUG(dbgs() << "LV: VPlan computed VF " << VF << ".\n"); // Make sure we have a VF > 1 for stress testing. - if (VPlanBuildStressTest && VF < 2) { + if (VPlanBuildStressTest && (VF.isScalar() || VF.isZero())) { LLVM_DEBUG(dbgs() << "LV: VPlan stress testing: " << "overriding computed VF.\n"); - VF = 4; + VF = ElementCount::getFixed(4); } } assert(EnableVPlanNativePath && "VPlan-native path is not enabled."); - assert(isPowerOf2_32(VF) && "VF needs to be a power of two"); - LLVM_DEBUG(dbgs() << "LV: Using " << (UserVF ? "user " : "") << "VF " << VF - << " to build VPlans.\n"); + assert(isPowerOf2_32(VF.getKnownMinValue()) && + "VF needs to be a power of two"); + LLVM_DEBUG(dbgs() << "LV: Using " << (!UserVF.isZero() ? "user " : "") + << "VF " << VF << " to build VPlans.\n"); buildVPlans(VF, VF); // For VPlan build stress testing, we bail out after VPlan construction. if (VPlanBuildStressTest) return VectorizationFactor::Disabled(); - return {VF, 0}; + return {VF, 0 /*Cost*/}; } LLVM_DEBUG( @@ -6566,10 +7628,10 @@ LoopVectorizationPlanner::planInVPlanNativePath(unsigned UserVF) { return VectorizationFactor::Disabled(); } -Optional LoopVectorizationPlanner::plan(unsigned UserVF, - unsigned UserIC) { - assert(OrigLoop->empty() && "Inner loop expected."); - Optional MaybeMaxVF = CM.computeMaxVF(UserVF, UserIC); +Optional +LoopVectorizationPlanner::plan(ElementCount UserVF, unsigned UserIC) { + assert(OrigLoop->isInnermost() && "Inner loop expected."); + Optional MaybeMaxVF = CM.computeMaxVF(UserVF, UserIC); if (!MaybeMaxVF) // Cases that should not to be vectorized nor interleaved. return None; @@ -6587,40 +7649,55 @@ Optional LoopVectorizationPlanner::plan(unsigned UserVF, CM.invalidateCostModelingDecisions(); } - if (UserVF) { - LLVM_DEBUG(dbgs() << "LV: Using user VF " << UserVF << ".\n"); - assert(isPowerOf2_32(UserVF) && "VF needs to be a power of two"); + ElementCount MaxVF = MaybeMaxVF.getValue(); + assert(MaxVF.isNonZero() && "MaxVF is zero."); + + bool UserVFIsLegal = ElementCount::isKnownLE(UserVF, MaxVF); + if (!UserVF.isZero() && + (UserVFIsLegal || (UserVF.isScalable() && MaxVF.isScalable()))) { + // FIXME: MaxVF is temporarily used inplace of UserVF for illegal scalable + // VFs here, this should be reverted to only use legal UserVFs once the + // loop below supports scalable VFs. + ElementCount VF = UserVFIsLegal ? UserVF : MaxVF; + LLVM_DEBUG(dbgs() << "LV: Using " << (UserVFIsLegal ? "user" : "max") + << " VF " << VF << ".\n"); + assert(isPowerOf2_32(VF.getKnownMinValue()) && + "VF needs to be a power of two"); // Collect the instructions (and their associated costs) that will be more // profitable to scalarize. - CM.selectUserVectorizationFactor(UserVF); - buildVPlansWithVPRecipes(UserVF, UserVF); + CM.selectUserVectorizationFactor(VF); + CM.collectInLoopReductions(); + buildVPlansWithVPRecipes(VF, VF); LLVM_DEBUG(printPlans(dbgs())); - return {{UserVF, 0}}; + return {{VF, 0}}; } - unsigned MaxVF = MaybeMaxVF.getValue(); - assert(MaxVF != 0 && "MaxVF is zero."); + assert(!MaxVF.isScalable() && + "Scalable vectors not yet supported beyond this point"); - for (unsigned VF = 1; VF <= MaxVF; VF *= 2) { + for (ElementCount VF = ElementCount::getFixed(1); + ElementCount::isKnownLE(VF, MaxVF); VF *= 2) { // Collect Uniform and Scalar instructions after vectorization with VF. CM.collectUniformsAndScalars(VF); // Collect the instructions (and their associated costs) that will be more // profitable to scalarize. - if (VF > 1) + if (VF.isVector()) CM.collectInstsToScalarize(VF); } - buildVPlansWithVPRecipes(1, MaxVF); + CM.collectInLoopReductions(); + + buildVPlansWithVPRecipes(ElementCount::getFixed(1), MaxVF); LLVM_DEBUG(printPlans(dbgs())); - if (MaxVF == 1) + if (MaxVF.isScalar()) return VectorizationFactor::Disabled(); // Select the optimal vectorization factor. return CM.selectVectorizationFactor(MaxVF); } -void LoopVectorizationPlanner::setBestPlan(unsigned VF, unsigned UF) { +void LoopVectorizationPlanner::setBestPlan(ElementCount VF, unsigned UF) { LLVM_DEBUG(dbgs() << "Setting best plan to VF=" << VF << ", UF=" << UF << '\n'); BestVF = VF; @@ -6639,13 +7716,23 @@ void LoopVectorizationPlanner::executePlan(InnerLoopVectorizer &ILV, // 1. Create a new empty loop. Unlink the old loop and connect the new one. VPCallbackILV CallbackILV(ILV); - VPTransformState State{BestVF, BestUF, LI, - DT, ILV.Builder, ILV.VectorLoopValueMap, - &ILV, CallbackILV}; + assert(BestVF.hasValue() && "Vectorization Factor is missing"); + + VPTransformState State{*BestVF, + BestUF, + OrigLoop, + LI, + DT, + ILV.Builder, + ILV.VectorLoopValueMap, + &ILV, + CallbackILV}; State.CFG.PrevBB = ILV.createVectorizedLoopSkeleton(); State.TripCount = ILV.getOrCreateTripCount(nullptr); State.CanonicalIV = ILV.Induction; + ILV.printDebugTracesAtStart(); + //===------------------------------------------------===// // // Notice: any optimization or new instruction that go @@ -6661,25 +7748,48 @@ void LoopVectorizationPlanner::executePlan(InnerLoopVectorizer &ILV, // 3. Fix the vectorized code: take care of header phi's, live-outs, // predication, updating analyses. ILV.fixVectorizedLoop(); + + ILV.printDebugTracesAtEnd(); } void LoopVectorizationPlanner::collectTriviallyDeadInstructions( SmallPtrSetImpl &DeadInstructions) { - BasicBlock *Latch = OrigLoop->getLoopLatch(); - // We create new control-flow for the vectorized loop, so the original - // condition will be dead after vectorization if it's only used by the - // branch. - auto *Cmp = dyn_cast(Latch->getTerminator()->getOperand(0)); - if (Cmp && Cmp->hasOneUse()) - DeadInstructions.insert(Cmp); + // We create new control-flow for the vectorized loop, so the original exit + // conditions will be dead after vectorization if it's only used by the + // terminator + SmallVector ExitingBlocks; + OrigLoop->getExitingBlocks(ExitingBlocks); + for (auto *BB : ExitingBlocks) { + auto *Cmp = dyn_cast(BB->getTerminator()->getOperand(0)); + if (!Cmp || !Cmp->hasOneUse()) + continue; + + // TODO: we should introduce a getUniqueExitingBlocks on Loop + if (!DeadInstructions.insert(Cmp).second) + continue; + + // The operands of the icmp is often a dead trunc, used by IndUpdate. + // TODO: can recurse through operands in general + for (Value *Op : Cmp->operands()) { + if (isa(Op) && Op->hasOneUse()) + DeadInstructions.insert(cast(Op)); + } + } // We create new "steps" for induction variable updates to which the original // induction variables map. An original update instruction will be dead if // all its users except the induction variable are dead. + auto *Latch = OrigLoop->getLoopLatch(); for (auto &Induction : Legal->getInductionVars()) { PHINode *Ind = Induction.first; auto *IndUpdate = cast(Ind->getIncomingValueForBlock(Latch)); + + // If the tail is to be folded by masking, the primary induction variable, + // if exists, isn't dead: it will be used for masking. Don't kill it. + if (CM.foldTailByMasking() && IndUpdate == Legal->getPrimaryInduction()) + continue; + if (llvm::all_of(IndUpdate->users(), [&](User *U) -> bool { return U == Ind || DeadInstructions.count(cast(U)); })) @@ -6754,12 +7864,284 @@ static void AddRuntimeUnrollDisableMetaData(Loop *L) { } } +//===--------------------------------------------------------------------===// +// EpilogueVectorizerMainLoop +//===--------------------------------------------------------------------===// + +/// This function is partially responsible for generating the control flow +/// depicted in https://llvm.org/docs/Vectorizers.html#epilogue-vectorization. +BasicBlock *EpilogueVectorizerMainLoop::createEpilogueVectorizedLoopSkeleton() { + MDNode *OrigLoopID = OrigLoop->getLoopID(); + Loop *Lp = createVectorLoopSkeleton(""); + + // Generate the code to check the minimum iteration count of the vector + // epilogue (see below). + EPI.EpilogueIterationCountCheck = + emitMinimumIterationCountCheck(Lp, LoopScalarPreHeader, true); + EPI.EpilogueIterationCountCheck->setName("iter.check"); + + // Generate the code to check any assumptions that we've made for SCEV + // expressions. + BasicBlock *SavedPreHeader = LoopVectorPreHeader; + emitSCEVChecks(Lp, LoopScalarPreHeader); + + // If a safety check was generated save it. + if (SavedPreHeader != LoopVectorPreHeader) + EPI.SCEVSafetyCheck = SavedPreHeader; + + // Generate the code that checks at runtime if arrays overlap. We put the + // checks into a separate block to make the more common case of few elements + // faster. + SavedPreHeader = LoopVectorPreHeader; + emitMemRuntimeChecks(Lp, LoopScalarPreHeader); + + // If a safety check was generated save/overwite it. + if (SavedPreHeader != LoopVectorPreHeader) + EPI.MemSafetyCheck = SavedPreHeader; + + // Generate the iteration count check for the main loop, *after* the check + // for the epilogue loop, so that the path-length is shorter for the case + // that goes directly through the vector epilogue. The longer-path length for + // the main loop is compensated for, by the gain from vectorizing the larger + // trip count. Note: the branch will get updated later on when we vectorize + // the epilogue. + EPI.MainLoopIterationCountCheck = + emitMinimumIterationCountCheck(Lp, LoopScalarPreHeader, false); + + // Generate the induction variable. + OldInduction = Legal->getPrimaryInduction(); + Type *IdxTy = Legal->getWidestInductionType(); + Value *StartIdx = ConstantInt::get(IdxTy, 0); + Constant *Step = ConstantInt::get(IdxTy, VF.getKnownMinValue() * UF); + Value *CountRoundDown = getOrCreateVectorTripCount(Lp); + EPI.VectorTripCount = CountRoundDown; + Induction = + createInductionVariable(Lp, StartIdx, CountRoundDown, Step, + getDebugLocFromInstOrOperands(OldInduction)); + + // Skip induction resume value creation here because they will be created in + // the second pass. If we created them here, they wouldn't be used anyway, + // because the vplan in the second pass still contains the inductions from the + // original loop. + + return completeLoopSkeleton(Lp, OrigLoopID); +} + +void EpilogueVectorizerMainLoop::printDebugTracesAtStart() { + LLVM_DEBUG({ + dbgs() << "Create Skeleton for epilogue vectorized loop (first pass)\n" + << "Main Loop VF:" << EPI.MainLoopVF.getKnownMinValue() + << ", Main Loop UF:" << EPI.MainLoopUF + << ", Epilogue Loop VF:" << EPI.EpilogueVF.getKnownMinValue() + << ", Epilogue Loop UF:" << EPI.EpilogueUF << "\n"; + }); +} + +void EpilogueVectorizerMainLoop::printDebugTracesAtEnd() { + DEBUG_WITH_TYPE(VerboseDebug, { + dbgs() << "intermediate fn:\n" << *Induction->getFunction() << "\n"; + }); +} + +BasicBlock *EpilogueVectorizerMainLoop::emitMinimumIterationCountCheck( + Loop *L, BasicBlock *Bypass, bool ForEpilogue) { + assert(L && "Expected valid Loop."); + assert(Bypass && "Expected valid bypass basic block."); + unsigned VFactor = + ForEpilogue ? EPI.EpilogueVF.getKnownMinValue() : VF.getKnownMinValue(); + unsigned UFactor = ForEpilogue ? EPI.EpilogueUF : UF; + Value *Count = getOrCreateTripCount(L); + // Reuse existing vector loop preheader for TC checks. + // Note that new preheader block is generated for vector loop. + BasicBlock *const TCCheckBlock = LoopVectorPreHeader; + IRBuilder<> Builder(TCCheckBlock->getTerminator()); + + // Generate code to check if the loop's trip count is less than VF * UF of the + // main vector loop. + auto P = + Cost->requiresScalarEpilogue() ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_ULT; + + Value *CheckMinIters = Builder.CreateICmp( + P, Count, ConstantInt::get(Count->getType(), VFactor * UFactor), + "min.iters.check"); + + if (!ForEpilogue) + TCCheckBlock->setName("vector.main.loop.iter.check"); + + // Create new preheader for vector loop. + LoopVectorPreHeader = SplitBlock(TCCheckBlock, TCCheckBlock->getTerminator(), + DT, LI, nullptr, "vector.ph"); + + if (ForEpilogue) { + assert(DT->properlyDominates(DT->getNode(TCCheckBlock), + DT->getNode(Bypass)->getIDom()) && + "TC check is expected to dominate Bypass"); + + // Update dominator for Bypass & LoopExit. + DT->changeImmediateDominator(Bypass, TCCheckBlock); + DT->changeImmediateDominator(LoopExitBlock, TCCheckBlock); + + LoopBypassBlocks.push_back(TCCheckBlock); + + // Save the trip count so we don't have to regenerate it in the + // vec.epilog.iter.check. This is safe to do because the trip count + // generated here dominates the vector epilog iter check. + EPI.TripCount = Count; + } + + ReplaceInstWithInst( + TCCheckBlock->getTerminator(), + BranchInst::Create(Bypass, LoopVectorPreHeader, CheckMinIters)); + + return TCCheckBlock; +} + +//===--------------------------------------------------------------------===// +// EpilogueVectorizerEpilogueLoop +//===--------------------------------------------------------------------===// + +/// This function is partially responsible for generating the control flow +/// depicted in https://llvm.org/docs/Vectorizers.html#epilogue-vectorization. +BasicBlock * +EpilogueVectorizerEpilogueLoop::createEpilogueVectorizedLoopSkeleton() { + MDNode *OrigLoopID = OrigLoop->getLoopID(); + Loop *Lp = createVectorLoopSkeleton("vec.epilog."); + + // Now, compare the remaining count and if there aren't enough iterations to + // execute the vectorized epilogue skip to the scalar part. + BasicBlock *VecEpilogueIterationCountCheck = LoopVectorPreHeader; + VecEpilogueIterationCountCheck->setName("vec.epilog.iter.check"); + LoopVectorPreHeader = + SplitBlock(LoopVectorPreHeader, LoopVectorPreHeader->getTerminator(), DT, + LI, nullptr, "vec.epilog.ph"); + emitMinimumVectorEpilogueIterCountCheck(Lp, LoopScalarPreHeader, + VecEpilogueIterationCountCheck); + + // Adjust the control flow taking the state info from the main loop + // vectorization into account. + assert(EPI.MainLoopIterationCountCheck && EPI.EpilogueIterationCountCheck && + "expected this to be saved from the previous pass."); + EPI.MainLoopIterationCountCheck->getTerminator()->replaceUsesOfWith( + VecEpilogueIterationCountCheck, LoopVectorPreHeader); + + DT->changeImmediateDominator(LoopVectorPreHeader, + EPI.MainLoopIterationCountCheck); + + EPI.EpilogueIterationCountCheck->getTerminator()->replaceUsesOfWith( + VecEpilogueIterationCountCheck, LoopScalarPreHeader); + + if (EPI.SCEVSafetyCheck) + EPI.SCEVSafetyCheck->getTerminator()->replaceUsesOfWith( + VecEpilogueIterationCountCheck, LoopScalarPreHeader); + if (EPI.MemSafetyCheck) + EPI.MemSafetyCheck->getTerminator()->replaceUsesOfWith( + VecEpilogueIterationCountCheck, LoopScalarPreHeader); + + DT->changeImmediateDominator( + VecEpilogueIterationCountCheck, + VecEpilogueIterationCountCheck->getSinglePredecessor()); + + DT->changeImmediateDominator(LoopScalarPreHeader, + EPI.EpilogueIterationCountCheck); + DT->changeImmediateDominator(LoopExitBlock, EPI.EpilogueIterationCountCheck); + + // Keep track of bypass blocks, as they feed start values to the induction + // phis in the scalar loop preheader. + if (EPI.SCEVSafetyCheck) + LoopBypassBlocks.push_back(EPI.SCEVSafetyCheck); + if (EPI.MemSafetyCheck) + LoopBypassBlocks.push_back(EPI.MemSafetyCheck); + LoopBypassBlocks.push_back(EPI.EpilogueIterationCountCheck); + + // Generate a resume induction for the vector epilogue and put it in the + // vector epilogue preheader + Type *IdxTy = Legal->getWidestInductionType(); + PHINode *EPResumeVal = PHINode::Create(IdxTy, 2, "vec.epilog.resume.val", + LoopVectorPreHeader->getFirstNonPHI()); + EPResumeVal->addIncoming(EPI.VectorTripCount, VecEpilogueIterationCountCheck); + EPResumeVal->addIncoming(ConstantInt::get(IdxTy, 0), + EPI.MainLoopIterationCountCheck); + + // Generate the induction variable. + OldInduction = Legal->getPrimaryInduction(); + Value *CountRoundDown = getOrCreateVectorTripCount(Lp); + Constant *Step = ConstantInt::get(IdxTy, VF.getKnownMinValue() * UF); + Value *StartIdx = EPResumeVal; + Induction = + createInductionVariable(Lp, StartIdx, CountRoundDown, Step, + getDebugLocFromInstOrOperands(OldInduction)); + + // Generate induction resume values. These variables save the new starting + // indexes for the scalar loop. They are used to test if there are any tail + // iterations left once the vector loop has completed. + // Note that when the vectorized epilogue is skipped due to iteration count + // check, then the resume value for the induction variable comes from + // the trip count of the main vector loop, hence passing the AdditionalBypass + // argument. + createInductionResumeValues(Lp, CountRoundDown, + {VecEpilogueIterationCountCheck, + EPI.VectorTripCount} /* AdditionalBypass */); + + AddRuntimeUnrollDisableMetaData(Lp); + return completeLoopSkeleton(Lp, OrigLoopID); +} + +BasicBlock * +EpilogueVectorizerEpilogueLoop::emitMinimumVectorEpilogueIterCountCheck( + Loop *L, BasicBlock *Bypass, BasicBlock *Insert) { + + assert(EPI.TripCount && + "Expected trip count to have been safed in the first pass."); + assert( + (!isa(EPI.TripCount) || + DT->dominates(cast(EPI.TripCount)->getParent(), Insert)) && + "saved trip count does not dominate insertion point."); + Value *TC = EPI.TripCount; + IRBuilder<> Builder(Insert->getTerminator()); + Value *Count = Builder.CreateSub(TC, EPI.VectorTripCount, "n.vec.remaining"); + + // Generate code to check if the loop's trip count is less than VF * UF of the + // vector epilogue loop. + auto P = + Cost->requiresScalarEpilogue() ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_ULT; + + Value *CheckMinIters = Builder.CreateICmp( + P, Count, + ConstantInt::get(Count->getType(), + EPI.EpilogueVF.getKnownMinValue() * EPI.EpilogueUF), + "min.epilog.iters.check"); + + ReplaceInstWithInst( + Insert->getTerminator(), + BranchInst::Create(Bypass, LoopVectorPreHeader, CheckMinIters)); + + LoopBypassBlocks.push_back(Insert); + return Insert; +} + +void EpilogueVectorizerEpilogueLoop::printDebugTracesAtStart() { + LLVM_DEBUG({ + dbgs() << "Create Skeleton for epilogue vectorized loop (second pass)\n" + << "Main Loop VF:" << EPI.MainLoopVF.getKnownMinValue() + << ", Main Loop UF:" << EPI.MainLoopUF + << ", Epilogue Loop VF:" << EPI.EpilogueVF.getKnownMinValue() + << ", Epilogue Loop UF:" << EPI.EpilogueUF << "\n"; + }); +} + +void EpilogueVectorizerEpilogueLoop::printDebugTracesAtEnd() { + DEBUG_WITH_TYPE(VerboseDebug, { + dbgs() << "final fn:\n" << *Induction->getFunction() << "\n"; + }); +} + bool LoopVectorizationPlanner::getDecisionAndClampRange( - const std::function &Predicate, VFRange &Range) { - assert(Range.End > Range.Start && "Trying to test an empty VF range."); + const std::function &Predicate, VFRange &Range) { + assert(!Range.isEmpty() && "Trying to test an empty VF range."); bool PredicateAtRangeStart = Predicate(Range.Start); - for (unsigned TmpVF = Range.Start * 2; TmpVF < Range.End; TmpVF *= 2) + for (ElementCount TmpVF = Range.Start * 2; + ElementCount::isKnownLT(TmpVF, Range.End); TmpVF *= 2) if (Predicate(TmpVF) != PredicateAtRangeStart) { Range.End = TmpVF; break; @@ -6773,9 +8155,11 @@ bool LoopVectorizationPlanner::getDecisionAndClampRange( /// of VF's starting at a given VF and extending it as much as possible. Each /// vectorization decision can potentially shorten this sub-range during /// buildVPlan(). -void LoopVectorizationPlanner::buildVPlans(unsigned MinVF, unsigned MaxVF) { - for (unsigned VF = MinVF; VF < MaxVF + 1;) { - VFRange SubRange = {VF, MaxVF + 1}; +void LoopVectorizationPlanner::buildVPlans(ElementCount MinVF, + ElementCount MaxVF) { + auto MaxVFPlusOne = MaxVF.getWithIncrement(1); + for (ElementCount VF = MinVF; ElementCount::isKnownLT(VF, MaxVFPlusOne);) { + VFRange SubRange = {VF, MaxVFPlusOne}; VPlans.push_back(buildVPlan(SubRange)); VF = SubRange.End; } @@ -6800,7 +8184,13 @@ VPValue *VPRecipeBuilder::createEdgeMask(BasicBlock *Src, BasicBlock *Dst, if (!BI->isConditional() || BI->getSuccessor(0) == BI->getSuccessor(1)) return EdgeMaskCache[Edge] = SrcMask; - VPValue *EdgeMask = Plan->getVPValue(BI->getCondition()); + // If source is an exiting block, we know the exit edge is dynamically dead + // in the vector loop, and thus we don't need to restrict the mask. Avoid + // adding uses of an otherwise potentially dead instruction. + if (OrigLoop->isLoopExiting(Src)) + return EdgeMaskCache[Edge] = SrcMask; + + VPValue *EdgeMask = Plan->getOrAddVPValue(BI->getCondition()); assert(EdgeMask && "No Edge Mask found for condition"); if (BI->getSuccessor(0) != Dst) @@ -6828,23 +8218,34 @@ VPValue *VPRecipeBuilder::createBlockInMask(BasicBlock *BB, VPlanPtr &Plan) { if (!CM.blockNeedsPredication(BB)) return BlockMaskCache[BB] = BlockMask; // Loop incoming mask is all-one. + // Create the block in mask as the first non-phi instruction in the block. + VPBuilder::InsertPointGuard Guard(Builder); + auto NewInsertionPoint = Builder.getInsertBlock()->getFirstNonPhi(); + Builder.setInsertPoint(Builder.getInsertBlock(), NewInsertionPoint); + // Introduce the early-exit compare IV <= BTC to form header block mask. // This is used instead of IV < TC because TC may wrap, unlike BTC. // Start by constructing the desired canonical IV. VPValue *IV = nullptr; if (Legal->getPrimaryInduction()) - IV = Plan->getVPValue(Legal->getPrimaryInduction()); + IV = Plan->getOrAddVPValue(Legal->getPrimaryInduction()); else { auto IVRecipe = new VPWidenCanonicalIVRecipe(); - Builder.getInsertBlock()->appendRecipe(IVRecipe); + Builder.getInsertBlock()->insert(IVRecipe, NewInsertionPoint); IV = IVRecipe->getVPValue(); } VPValue *BTC = Plan->getOrCreateBackedgeTakenCount(); bool TailFolded = !CM.isScalarEpilogueAllowed(); - if (TailFolded && CM.TTI.emitGetActiveLaneMask()) - BlockMask = Builder.createNaryOp(VPInstruction::ActiveLaneMask, {IV, BTC}); - else + + if (TailFolded && CM.TTI.emitGetActiveLaneMask()) { + // While ActiveLaneMask is a binary op that consumes the loop tripcount + // as a second argument, we only pass the IV here and extract the + // tripcount from the transform state where codegen of the VP instructions + // happen. + BlockMask = Builder.createNaryOp(VPInstruction::ActiveLaneMask, {IV}); + } else { BlockMask = Builder.createNaryOp(VPInstruction::ICmpULE, {IV, BTC}); + } return BlockMaskCache[BB] = BlockMask; } @@ -6865,14 +8266,13 @@ VPValue *VPRecipeBuilder::createBlockInMask(BasicBlock *BB, VPlanPtr &Plan) { return BlockMaskCache[BB] = BlockMask; } -VPWidenMemoryInstructionRecipe * -VPRecipeBuilder::tryToWidenMemory(Instruction *I, VFRange &Range, - VPlanPtr &Plan) { +VPRecipeBase *VPRecipeBuilder::tryToWidenMemory(Instruction *I, VFRange &Range, + VPlanPtr &Plan) { assert((isa(I) || isa(I)) && "Must be called with either a load or store"); - auto willWiden = [&](unsigned VF) -> bool { - if (VF == 1) + auto willWiden = [&](ElementCount VF) -> bool { + if (VF.isScalar()) return false; LoopVectorizationCostModel::InstWidening Decision = CM.getWideningDecision(I, VF); @@ -6903,20 +8303,22 @@ VPRecipeBuilder::tryToWidenMemory(Instruction *I, VFRange &Range, } VPWidenIntOrFpInductionRecipe * -VPRecipeBuilder::tryToOptimizeInductionPHI(PHINode *Phi) const { +VPRecipeBuilder::tryToOptimizeInductionPHI(PHINode *Phi, VPlan &Plan) const { // Check if this is an integer or fp induction. If so, build the recipe that // produces its scalar and vector values. InductionDescriptor II = Legal->getInductionVars().lookup(Phi); if (II.getKind() == InductionDescriptor::IK_IntInduction || - II.getKind() == InductionDescriptor::IK_FpInduction) - return new VPWidenIntOrFpInductionRecipe(Phi); + II.getKind() == InductionDescriptor::IK_FpInduction) { + VPValue *Start = Plan.getOrAddVPValue(II.getStartValue()); + return new VPWidenIntOrFpInductionRecipe(Phi, Start); + } return nullptr; } VPWidenIntOrFpInductionRecipe * -VPRecipeBuilder::tryToOptimizeInductionTruncate(TruncInst *I, - VFRange &Range) const { +VPRecipeBuilder::tryToOptimizeInductionTruncate(TruncInst *I, VFRange &Range, + VPlan &Plan) const { // Optimize the special case where the source is a constant integer // induction variable. Notice that we can only optimize the 'trunc' case // because (a) FP conversions lose precision, (b) sext/zext may wrap, and @@ -6925,15 +8327,21 @@ VPRecipeBuilder::tryToOptimizeInductionTruncate(TruncInst *I, // Determine whether \p K is a truncation based on an induction variable that // can be optimized. auto isOptimizableIVTruncate = - [&](Instruction *K) -> std::function { - return - [=](unsigned VF) -> bool { return CM.isOptimizableIVTruncate(K, VF); }; + [&](Instruction *K) -> std::function { + return [=](ElementCount VF) -> bool { + return CM.isOptimizableIVTruncate(K, VF); + }; }; if (LoopVectorizationPlanner::getDecisionAndClampRange( - isOptimizableIVTruncate(I), Range)) + isOptimizableIVTruncate(I), Range)) { + + InductionDescriptor II = + Legal->getInductionVars().lookup(cast(I->getOperand(0))); + VPValue *Start = Plan.getOrAddVPValue(II.getStartValue()); return new VPWidenIntOrFpInductionRecipe(cast(I->getOperand(0)), - I); + Start, I); + } return nullptr; } @@ -6962,7 +8370,9 @@ VPWidenCallRecipe *VPRecipeBuilder::tryToWidenCall(CallInst *CI, VFRange &Range, VPlan &Plan) const { bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange( - [this, CI](unsigned VF) { return CM.isScalarWithPredication(CI, VF); }, + [this, CI](ElementCount VF) { + return CM.isScalarWithPredication(CI, VF); + }, Range); if (IsPredicated) @@ -6970,19 +8380,23 @@ VPWidenCallRecipe *VPRecipeBuilder::tryToWidenCall(CallInst *CI, VFRange &Range, Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); if (ID && (ID == Intrinsic::assume || ID == Intrinsic::lifetime_end || - ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect)) + ID == Intrinsic::lifetime_start || ID == Intrinsic::sideeffect || + ID == Intrinsic::pseudoprobe || + ID == Intrinsic::experimental_noalias_scope_decl)) return nullptr; - auto willWiden = [&](unsigned VF) -> bool { + auto willWiden = [&](ElementCount VF) -> bool { Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); // The following case may be scalarized depending on the VF. // The flag shows whether we use Intrinsic or a usual Call for vectorized // version of the instruction. // Is it beneficial to perform intrinsic call compared to lib call? bool NeedToScalarize = false; - unsigned CallCost = CM.getVectorCallCost(CI, VF, NeedToScalarize); - bool UseVectorIntrinsic = - ID && CM.getVectorIntrinsicCost(CI, VF) <= CallCost; + InstructionCost CallCost = CM.getVectorCallCost(CI, VF, NeedToScalarize); + InstructionCost IntrinsicCost = ID ? CM.getVectorIntrinsicCost(CI, VF) : 0; + bool UseVectorIntrinsic = ID && IntrinsicCost <= CallCost; + assert(IntrinsicCost.isValid() && CallCost.isValid() && + "Cannot have invalid costs while widening"); return UseVectorIntrinsic || !NeedToScalarize; }; @@ -6997,7 +8411,7 @@ bool VPRecipeBuilder::shouldWiden(Instruction *I, VFRange &Range) const { !isa(I) && "Instruction should have been handled earlier"); // Instruction should be widened, unless it is scalar after vectorization, // scalarization is profitable or it is predicated. - auto WillScalarize = [this, I](unsigned VF) -> bool { + auto WillScalarize = [this, I](ElementCount VF) -> bool { return CM.isScalarAfterVectorization(I, VF) || CM.isProfitableToScalarize(I, VF) || CM.isScalarWithPredication(I, VF); @@ -7060,15 +8474,17 @@ VPBasicBlock *VPRecipeBuilder::handleReplication( DenseMap &PredInst2Recipe, VPlanPtr &Plan) { bool IsUniform = LoopVectorizationPlanner::getDecisionAndClampRange( - [&](unsigned VF) { return CM.isUniformAfterVectorization(I, VF); }, + [&](ElementCount VF) { return CM.isUniformAfterVectorization(I, VF); }, Range); bool IsPredicated = LoopVectorizationPlanner::getDecisionAndClampRange( - [&](unsigned VF) { return CM.isScalarWithPredication(I, VF); }, Range); + [&](ElementCount VF) { return CM.isScalarWithPredication(I, VF); }, + Range); auto *Recipe = new VPReplicateRecipe(I, Plan->mapToVPValues(I->operands()), IsUniform, IsPredicated); setRecipe(I, Recipe); + Plan->addVPValue(I, Recipe); // Find if I uses a predicated instruction. If so, it will use its scalar // value. Avoid hoisting the insert-element which packs the scalar value into @@ -7110,8 +8526,9 @@ VPRegionBlock *VPRecipeBuilder::createReplicateRegion(Instruction *Instr, assert(Instr->getParent() && "Predicated instruction not in any basic block"); auto *BOMRecipe = new VPBranchOnMaskRecipe(BlockInMask); auto *Entry = new VPBasicBlock(Twine(RegionName) + ".entry", BOMRecipe); - auto *PHIRecipe = - Instr->getType()->isVoidTy() ? nullptr : new VPPredInstPHIRecipe(Instr); + auto *PHIRecipe = Instr->getType()->isVoidTy() + ? nullptr + : new VPPredInstPHIRecipe(Plan->getOrAddVPValue(Instr)); auto *Exit = new VPBasicBlock(Twine(RegionName) + ".continue", PHIRecipe); auto *Pred = new VPBasicBlock(Twine(RegionName) + ".if", PredRecipe); VPRegionBlock *Region = new VPRegionBlock(Entry, Exit, RegionName, true); @@ -7139,13 +8556,21 @@ VPRecipeBase *VPRecipeBuilder::tryToCreateWidenRecipe(Instruction *Instr, if (auto Phi = dyn_cast(Instr)) { if (Phi->getParent() != OrigLoop->getHeader()) return tryToBlend(Phi, Plan); - if ((Recipe = tryToOptimizeInductionPHI(Phi))) + if ((Recipe = tryToOptimizeInductionPHI(Phi, *Plan))) return Recipe; + + if (Legal->isReductionVariable(Phi)) { + RecurrenceDescriptor &RdxDesc = Legal->getReductionVars()[Phi]; + VPValue *StartV = + Plan->getOrAddVPValue(RdxDesc.getRecurrenceStartValue()); + return new VPWidenPHIRecipe(Phi, RdxDesc, *StartV); + } + return new VPWidenPHIRecipe(Phi); } - if (isa(Instr) && - (Recipe = tryToOptimizeInductionTruncate(cast(Instr), Range))) + if (isa(Instr) && (Recipe = tryToOptimizeInductionTruncate( + cast(Instr), Range, *Plan))) return Recipe; if (!shouldWiden(Instr, Range)) @@ -7165,35 +8590,9 @@ VPRecipeBase *VPRecipeBuilder::tryToCreateWidenRecipe(Instruction *Instr, return tryToWiden(Instr, *Plan); } -void LoopVectorizationPlanner::buildVPlansWithVPRecipes(unsigned MinVF, - unsigned MaxVF) { - assert(OrigLoop->empty() && "Inner loop expected."); - - // Collect conditions feeding internal conditional branches; they need to be - // represented in VPlan for it to model masking. - SmallPtrSet NeedDef; - - auto *Latch = OrigLoop->getLoopLatch(); - for (BasicBlock *BB : OrigLoop->blocks()) { - if (BB == Latch) - continue; - BranchInst *Branch = dyn_cast(BB->getTerminator()); - if (Branch && Branch->isConditional()) - NeedDef.insert(Branch->getCondition()); - } - - // If the tail is to be folded by masking, the primary induction variable, if - // exists needs to be represented in VPlan for it to model early-exit masking. - // Also, both the Phi and the live-out instruction of each reduction are - // required in order to introduce a select between them in VPlan. - if (CM.foldTailByMasking()) { - if (Legal->getPrimaryInduction()) - NeedDef.insert(Legal->getPrimaryInduction()); - for (auto &Reduction : Legal->getReductionVars()) { - NeedDef.insert(Reduction.first); - NeedDef.insert(Reduction.second.getLoopExitInstr()); - } - } +void LoopVectorizationPlanner::buildVPlansWithVPRecipes(ElementCount MinVF, + ElementCount MaxVF) { + assert(OrigLoop->isInnermost() && "Inner loop expected."); // Collect instructions from the original loop that will become trivially dead // in the vectorized loop. We don't need to vectorize these instructions. For @@ -7216,17 +8615,17 @@ void LoopVectorizationPlanner::buildVPlansWithVPRecipes(unsigned MinVF, for (Instruction *I : DeadInstructions) SinkAfter.erase(I); - for (unsigned VF = MinVF; VF < MaxVF + 1;) { - VFRange SubRange = {VF, MaxVF + 1}; - VPlans.push_back(buildVPlanWithVPRecipes(SubRange, NeedDef, - DeadInstructions, SinkAfter)); + auto MaxVFPlusOne = MaxVF.getWithIncrement(1); + for (ElementCount VF = MinVF; ElementCount::isKnownLT(VF, MaxVFPlusOne);) { + VFRange SubRange = {VF, MaxVFPlusOne}; + VPlans.push_back( + buildVPlanWithVPRecipes(SubRange, DeadInstructions, SinkAfter)); VF = SubRange.End; } } VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( - VFRange &Range, SmallPtrSetImpl &NeedDef, - SmallPtrSetImpl &DeadInstructions, + VFRange &Range, SmallPtrSetImpl &DeadInstructions, const DenseMap &SinkAfter) { // Hold a mapping from predicated instructions to their recipes, in order to @@ -7249,14 +8648,28 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( RecipeBuilder.recordRecipeOf(Entry.first); RecipeBuilder.recordRecipeOf(Entry.second); } + for (auto &Reduction : CM.getInLoopReductionChains()) { + PHINode *Phi = Reduction.first; + RecurKind Kind = Legal->getReductionVars()[Phi].getRecurrenceKind(); + const SmallVector &ReductionOperations = Reduction.second; + + RecipeBuilder.recordRecipeOf(Phi); + for (auto &R : ReductionOperations) { + RecipeBuilder.recordRecipeOf(R); + // For min/max reducitons, where we have a pair of icmp/select, we also + // need to record the ICmp recipe, so it can be removed later. + if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) + RecipeBuilder.recordRecipeOf(cast(R->getOperand(0))); + } + } // For each interleave group which is relevant for this (possibly trimmed) // Range, add it to the set of groups to be later applied to the VPlan and add // placeholders for its members' Recipes which we'll be replacing with a // single VPInterleaveRecipe. for (InterleaveGroup *IG : IAI.getInterleaveGroups()) { - auto applyIG = [IG, this](unsigned VF) -> bool { - return (VF >= 2 && // Query is illegal for VF == 1 + auto applyIG = [IG, this](ElementCount VF) -> bool { + return (VF.isVector() && // Query is illegal for VF == 1 CM.getWideningDecision(IG->getInsertPos(), VF) == LoopVectorizationCostModel::CM_Interleave); }; @@ -7278,10 +8691,6 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( VPBasicBlock *VPBB = new VPBasicBlock("Pre-Entry"); Plan->setEntry(VPBB); - // Represent values that will have defs inside VPlan. - for (Value *V : NeedDef) - Plan->addVPValue(V); - // Scan the body of the loop in a topological order to visit each basic block // after having visited its predecessor basic blocks. LoopBlocksDFS DFS(OrigLoop); @@ -7308,6 +8717,11 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( if (auto Recipe = RecipeBuilder.tryToCreateWidenRecipe(Instr, Range, Plan)) { + for (auto *Def : Recipe->definedValues()) { + auto *UV = Def->getUnderlyingValue(); + Plan->addVPValue(UV, Def); + } + RecipeBuilder.setRecipe(Instr, Recipe); VPBB->appendRecipe(Recipe); continue; @@ -7343,6 +8757,18 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( for (auto &Entry : SinkAfter) { VPRecipeBase *Sink = RecipeBuilder.getRecipe(Entry.first); VPRecipeBase *Target = RecipeBuilder.getRecipe(Entry.second); + // If the target is in a replication region, make sure to move Sink to the + // block after it, not into the replication region itself. + if (auto *Region = + dyn_cast_or_null(Target->getParent()->getParent())) { + if (Region->isReplicator()) { + assert(Region->getNumSuccessors() == 1 && "Expected SESE region!"); + VPBasicBlock *NextBlock = + cast(Region->getSuccessors().front()); + Sink->moveBefore(*NextBlock, NextBlock->getFirstNonPhi()); + continue; + } + } Sink->moveAfter(Target); } @@ -7352,33 +8778,52 @@ VPlanPtr LoopVectorizationPlanner::buildVPlanWithVPRecipes( for (auto IG : InterleaveGroups) { auto *Recipe = cast( RecipeBuilder.getRecipe(IG->getInsertPos())); - (new VPInterleaveRecipe(IG, Recipe->getAddr(), Recipe->getMask())) - ->insertBefore(Recipe); + SmallVector StoredValues; + for (unsigned i = 0; i < IG->getFactor(); ++i) + if (auto *SI = dyn_cast_or_null(IG->getMember(i))) + StoredValues.push_back(Plan->getOrAddVPValue(SI->getOperand(0))); + auto *VPIG = new VPInterleaveRecipe(IG, Recipe->getAddr(), StoredValues, + Recipe->getMask()); + VPIG->insertBefore(Recipe); + unsigned J = 0; for (unsigned i = 0; i < IG->getFactor(); ++i) if (Instruction *Member = IG->getMember(i)) { + if (!Member->getType()->isVoidTy()) { + VPValue *OriginalV = Plan->getVPValue(Member); + Plan->removeVPValueFor(Member); + Plan->addVPValue(Member, VPIG->getVPValue(J)); + OriginalV->replaceAllUsesWith(VPIG->getVPValue(J)); + J++; + } RecipeBuilder.getRecipe(Member)->eraseFromParent(); } } + // Adjust the recipes for any inloop reductions. + if (Range.Start.isVector()) + adjustRecipesForInLoopReductions(Plan, RecipeBuilder); + // Finally, if tail is folded by masking, introduce selects between the phi // and the live-out instruction of each reduction, at the end of the latch. - if (CM.foldTailByMasking()) { + if (CM.foldTailByMasking() && !Legal->getReductionVars().empty()) { Builder.setInsertPoint(VPBB); auto *Cond = RecipeBuilder.createBlockInMask(OrigLoop->getHeader(), Plan); for (auto &Reduction : Legal->getReductionVars()) { - VPValue *Phi = Plan->getVPValue(Reduction.first); - VPValue *Red = Plan->getVPValue(Reduction.second.getLoopExitInstr()); + if (CM.isInLoopReduction(Reduction.first)) + continue; + VPValue *Phi = Plan->getOrAddVPValue(Reduction.first); + VPValue *Red = Plan->getOrAddVPValue(Reduction.second.getLoopExitInstr()); Builder.createNaryOp(Instruction::Select, {Cond, Red, Phi}); } } std::string PlanName; raw_string_ostream RSO(PlanName); - unsigned VF = Range.Start; + ElementCount VF = Range.Start; Plan->addVF(VF); RSO << "Initial VPlan for VF={" << VF; - for (VF *= 2; VF < Range.End; VF *= 2) { + for (VF *= 2; ElementCount::isKnownLT(VF, Range.End); VF *= 2) { Plan->addVF(VF); RSO << "," << VF; } @@ -7394,7 +8839,7 @@ VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) { // transformations before even evaluating whether vectorization is profitable. // Since we cannot modify the incoming IR, we need to build VPlan upfront in // the vectorization pipeline. - assert(!OrigLoop->empty()); + assert(!OrigLoop->isInnermost()); assert(EnableVPlanNativePath && "VPlan-native path is not enabled."); // Create new empty VPlan @@ -7404,7 +8849,8 @@ VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) { VPlanHCFGBuilder HCFGBuilder(OrigLoop, LI, *Plan); HCFGBuilder.buildHierarchicalCFG(); - for (unsigned VF = Range.Start; VF < Range.End; VF *= 2) + for (ElementCount VF = Range.Start; ElementCount::isKnownLT(VF, Range.End); + VF *= 2) Plan->addVF(VF); if (EnableVPlanPredication) { @@ -7422,6 +8868,67 @@ VPlanPtr LoopVectorizationPlanner::buildVPlan(VFRange &Range) { return Plan; } +// Adjust the recipes for any inloop reductions. The chain of instructions +// leading from the loop exit instr to the phi need to be converted to +// reductions, with one operand being vector and the other being the scalar +// reduction chain. +void LoopVectorizationPlanner::adjustRecipesForInLoopReductions( + VPlanPtr &Plan, VPRecipeBuilder &RecipeBuilder) { + for (auto &Reduction : CM.getInLoopReductionChains()) { + PHINode *Phi = Reduction.first; + RecurrenceDescriptor &RdxDesc = Legal->getReductionVars()[Phi]; + const SmallVector &ReductionOperations = Reduction.second; + + // ReductionOperations are orders top-down from the phi's use to the + // LoopExitValue. We keep a track of the previous item (the Chain) to tell + // which of the two operands will remain scalar and which will be reduced. + // For minmax the chain will be the select instructions. + Instruction *Chain = Phi; + for (Instruction *R : ReductionOperations) { + VPRecipeBase *WidenRecipe = RecipeBuilder.getRecipe(R); + RecurKind Kind = RdxDesc.getRecurrenceKind(); + + VPValue *ChainOp = Plan->getVPValue(Chain); + unsigned FirstOpId; + if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) { + assert(isa(WidenRecipe) && + "Expected to replace a VPWidenSelectSC"); + FirstOpId = 1; + } else { + assert(isa(WidenRecipe) && + "Expected to replace a VPWidenSC"); + FirstOpId = 0; + } + unsigned VecOpId = + R->getOperand(FirstOpId) == Chain ? FirstOpId + 1 : FirstOpId; + VPValue *VecOp = Plan->getVPValue(R->getOperand(VecOpId)); + + auto *CondOp = CM.foldTailByMasking() + ? RecipeBuilder.createBlockInMask(R->getParent(), Plan) + : nullptr; + VPReductionRecipe *RedRecipe = new VPReductionRecipe( + &RdxDesc, R, ChainOp, VecOp, CondOp, Legal->hasFunNoNaNAttr(), TTI); + WidenRecipe->getVPValue()->replaceAllUsesWith(RedRecipe); + Plan->removeVPValueFor(R); + Plan->addVPValue(R, RedRecipe); + WidenRecipe->getParent()->insert(RedRecipe, WidenRecipe->getIterator()); + WidenRecipe->getVPValue()->replaceAllUsesWith(RedRecipe); + WidenRecipe->eraseFromParent(); + + if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) { + VPRecipeBase *CompareRecipe = + RecipeBuilder.getRecipe(cast(R->getOperand(0))); + assert(isa(CompareRecipe) && + "Expected to replace a VPWidenSC"); + assert(cast(CompareRecipe)->getNumUsers() == 0 && + "Expected no remaining users"); + CompareRecipe->eraseFromParent(); + } + Chain = R; + } + } +} + Value* LoopVectorizationPlanner::VPCallbackILV:: getOrCreateVectorValues(Value *V, unsigned Part) { return ILV.getOrCreateVectorValue(V, Part); @@ -7449,29 +8956,35 @@ void VPInterleaveRecipe::print(raw_ostream &O, const Twine &Indent, } void VPWidenCallRecipe::execute(VPTransformState &State) { - State.ILV->widenCallInstruction(Ingredient, User, State); + State.ILV->widenCallInstruction(*cast(getUnderlyingInstr()), this, + *this, State); } void VPWidenSelectRecipe::execute(VPTransformState &State) { - State.ILV->widenSelectInstruction(Ingredient, User, InvariantCond, State); + State.ILV->widenSelectInstruction(*cast(getUnderlyingInstr()), + this, *this, InvariantCond, State); } void VPWidenRecipe::execute(VPTransformState &State) { - State.ILV->widenInstruction(Ingredient, User, State); + State.ILV->widenInstruction(*getUnderlyingInstr(), this, *this, State); } void VPWidenGEPRecipe::execute(VPTransformState &State) { - State.ILV->widenGEP(GEP, User, State.UF, State.VF, IsPtrLoopInvariant, + State.ILV->widenGEP(cast(getUnderlyingInstr()), this, + *this, State.UF, State.VF, IsPtrLoopInvariant, IsIndexLoopInvariant, State); } void VPWidenIntOrFpInductionRecipe::execute(VPTransformState &State) { assert(!State.Instance && "Int or FP induction being replicated."); - State.ILV->widenIntOrFpInduction(IV, Trunc); + State.ILV->widenIntOrFpInduction(IV, getStartValue()->getLiveInIRValue(), + Trunc); } void VPWidenPHIRecipe::execute(VPTransformState &State) { - State.ILV->widenPHIInstruction(Phi, State.UF, State.VF); + Value *StartV = + getStartValue() ? getStartValue()->getLiveInIRValue() : nullptr; + State.ILV->widenPHIInstruction(Phi, RdxDesc, StartV, State.UF, State.VF); } void VPBlendRecipe::execute(VPTransformState &State) { @@ -7515,22 +9028,59 @@ void VPBlendRecipe::execute(VPTransformState &State) { void VPInterleaveRecipe::execute(VPTransformState &State) { assert(!State.Instance && "Interleave group being replicated."); - State.ILV->vectorizeInterleaveGroup(IG, State, getAddr(), getMask()); + State.ILV->vectorizeInterleaveGroup(IG, definedValues(), State, getAddr(), + getStoredValues(), getMask()); +} + +void VPReductionRecipe::execute(VPTransformState &State) { + assert(!State.Instance && "Reduction being replicated."); + for (unsigned Part = 0; Part < State.UF; ++Part) { + RecurKind Kind = RdxDesc->getRecurrenceKind(); + Value *NewVecOp = State.get(getVecOp(), Part); + if (VPValue *Cond = getCondOp()) { + Value *NewCond = State.get(Cond, Part); + VectorType *VecTy = cast(NewVecOp->getType()); + Constant *Iden = RecurrenceDescriptor::getRecurrenceIdentity( + Kind, VecTy->getElementType()); + Constant *IdenVec = + ConstantVector::getSplat(VecTy->getElementCount(), Iden); + Value *Select = State.Builder.CreateSelect(NewCond, NewVecOp, IdenVec); + NewVecOp = Select; + } + Value *NewRed = + createTargetReduction(State.Builder, TTI, *RdxDesc, NewVecOp); + Value *PrevInChain = State.get(getChainOp(), Part); + Value *NextInChain; + if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) { + NextInChain = + createMinMaxOp(State.Builder, RdxDesc->getRecurrenceKind(), + NewRed, PrevInChain); + } else { + NextInChain = State.Builder.CreateBinOp( + (Instruction::BinaryOps)getUnderlyingInstr()->getOpcode(), NewRed, + PrevInChain); + } + State.set(this, getUnderlyingInstr(), NextInChain, Part); + } } void VPReplicateRecipe::execute(VPTransformState &State) { if (State.Instance) { // Generate a single instance. - State.ILV->scalarizeInstruction(Ingredient, User, *State.Instance, - IsPredicated, State); + assert(!State.VF.isScalable() && "Can't scalarize a scalable vector"); + State.ILV->scalarizeInstruction(getUnderlyingInstr(), *this, + *State.Instance, IsPredicated, State); // Insert scalar instance packing it into a vector. - if (AlsoPack && State.VF > 1) { - // If we're constructing lane 0, initialize to start from undef. + if (AlsoPack && State.VF.isVector()) { + // If we're constructing lane 0, initialize to start from poison. if (State.Instance->Lane == 0) { - Value *Undef = UndefValue::get( - FixedVectorType::get(Ingredient->getType(), State.VF)); - State.ValueMap.setVectorValue(Ingredient, State.Instance->Part, Undef); + assert(!State.VF.isScalable() && "VF is assumed to be non scalable."); + Value *Poison = PoisonValue::get( + VectorType::get(getUnderlyingValue()->getType(), State.VF)); + State.ValueMap.setVectorValue(getUnderlyingInstr(), + State.Instance->Part, Poison); } - State.ILV->packScalarIntoVectorValue(Ingredient, *State.Instance); + State.ILV->packScalarIntoVectorValue(getUnderlyingInstr(), + *State.Instance); } return; } @@ -7538,10 +9088,12 @@ void VPReplicateRecipe::execute(VPTransformState &State) { // Generate scalar instances for all VF lanes of all UF parts, unless the // instruction is uniform inwhich case generate only the first lane for each // of the UF parts. - unsigned EndLane = IsUniform ? 1 : State.VF; + unsigned EndLane = IsUniform ? 1 : State.VF.getKnownMinValue(); + assert((!State.VF.isScalable() || IsUniform) && + "Can't scalarize a scalable vector"); for (unsigned Part = 0; Part < State.UF; ++Part) for (unsigned Lane = 0; Lane < EndLane; ++Lane) - State.ILV->scalarizeInstruction(Ingredient, User, {Part, Lane}, + State.ILV->scalarizeInstruction(getUnderlyingInstr(), *this, {Part, Lane}, IsPredicated, State); } @@ -7573,8 +9125,8 @@ void VPBranchOnMaskRecipe::execute(VPTransformState &State) { void VPPredInstPHIRecipe::execute(VPTransformState &State) { assert(State.Instance && "Predicated instruction PHI works per instance."); - Instruction *ScalarPredInst = cast( - State.ValueMap.getScalarValue(PredInst, *State.Instance)); + Instruction *ScalarPredInst = + cast(State.get(getOperand(0), *State.Instance)); BasicBlock *PredicatedBB = ScalarPredInst->getParent(); BasicBlock *PredicatingBB = PredicatedBB->getSinglePredecessor(); assert(PredicatingBB && "Predicated block has no single predecessor."); @@ -7586,6 +9138,8 @@ void VPPredInstPHIRecipe::execute(VPTransformState &State) { // also do that packing, thereby "hoisting" the insert-element sequence. // Otherwise, a phi node for the scalar value is needed. unsigned Part = State.Instance->Part; + Instruction *PredInst = + cast(getOperand(0)->getUnderlyingValue()); if (State.ValueMap.hasVectorValue(PredInst, Part)) { Value *VectorValue = State.ValueMap.getVectorValue(PredInst, Part); InsertElementInst *IEI = cast(VectorValue); @@ -7596,16 +9150,17 @@ void VPPredInstPHIRecipe::execute(VPTransformState &State) { } else { Type *PredInstType = PredInst->getType(); PHINode *Phi = State.Builder.CreatePHI(PredInstType, 2); - Phi->addIncoming(UndefValue::get(ScalarPredInst->getType()), PredicatingBB); + Phi->addIncoming(PoisonValue::get(ScalarPredInst->getType()), PredicatingBB); Phi->addIncoming(ScalarPredInst, PredicatedBB); State.ValueMap.resetScalarValue(PredInst, *State.Instance, Phi); } } void VPWidenMemoryInstructionRecipe::execute(VPTransformState &State) { - VPValue *StoredValue = isa(Instr) ? getStoredValue() : nullptr; - State.ILV->vectorizeMemoryInstruction(&Instr, State, getAddr(), StoredValue, - getMask()); + VPValue *StoredValue = isStore() ? getStoredValue() : nullptr; + State.ILV->vectorizeMemoryInstruction(&Ingredient, State, + StoredValue ? nullptr : getVPValue(), + getAddr(), StoredValue, getMask()); } // Determine how to lower the scalar epilogue, which depends on 1) optimising @@ -7617,35 +9172,53 @@ static ScalarEpilogueLowering getScalarEpilogueLowering( BlockFrequencyInfo *BFI, TargetTransformInfo *TTI, TargetLibraryInfo *TLI, AssumptionCache *AC, LoopInfo *LI, ScalarEvolution *SE, DominatorTree *DT, LoopVectorizationLegality &LVL) { - bool OptSize = - F->hasOptSize() || llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI, - PGSOQueryType::IRPass); // 1) OptSize takes precedence over all other options, i.e. if this is set, // don't look at hints or options, and don't request a scalar epilogue. - if (OptSize) + // (For PGSO, as shouldOptimizeForSize isn't currently accessible from + // LoopAccessInfo (due to code dependency and not being able to reliably get + // PSI/BFI from a loop analysis under NPM), we cannot suppress the collection + // of strides in LoopAccessInfo::analyzeLoop() and vectorize without + // versioning when the vectorization is forced, unlike hasOptSize. So revert + // back to the old way and vectorize with versioning when forced. See D81345.) + if (F->hasOptSize() || (llvm::shouldOptimizeForSize(L->getHeader(), PSI, BFI, + PGSOQueryType::IRPass) && + Hints.getForce() != LoopVectorizeHints::FK_Enabled)) return CM_ScalarEpilogueNotAllowedOptSize; - bool PredicateOptDisabled = PreferPredicateOverEpilog.getNumOccurrences() && - !PreferPredicateOverEpilog; + // 2) If set, obey the directives + if (PreferPredicateOverEpilogue.getNumOccurrences()) { + switch (PreferPredicateOverEpilogue) { + case PreferPredicateTy::ScalarEpilogue: + return CM_ScalarEpilogueAllowed; + case PreferPredicateTy::PredicateElseScalarEpilogue: + return CM_ScalarEpilogueNotNeededUsePredicate; + case PreferPredicateTy::PredicateOrDontVectorize: + return CM_ScalarEpilogueNotAllowedUsePredicate; + }; + } - // 2) Next, if disabling predication is requested on the command line, honour - // this and request a scalar epilogue. - if (PredicateOptDisabled) + // 3) If set, obey the hints + switch (Hints.getPredicate()) { + case LoopVectorizeHints::FK_Enabled: + return CM_ScalarEpilogueNotNeededUsePredicate; + case LoopVectorizeHints::FK_Disabled: return CM_ScalarEpilogueAllowed; + }; - // 3) and 4) look if enabling predication is requested on the command line, - // with a loop hint, or if the TTI hook indicates this is profitable, request - // predication . - if (PreferPredicateOverEpilog || - Hints.getPredicate() == LoopVectorizeHints::FK_Enabled || - (TTI->preferPredicateOverEpilogue(L, LI, *SE, *AC, TLI, DT, - LVL.getLAI()) && - Hints.getPredicate() != LoopVectorizeHints::FK_Disabled)) + // 4) if the TTI hook indicates this is profitable, request predication. + if (TTI->preferPredicateOverEpilogue(L, LI, *SE, *AC, TLI, DT, + LVL.getLAI())) return CM_ScalarEpilogueNotNeededUsePredicate; return CM_ScalarEpilogueAllowed; } +void VPTransformState::set(VPValue *Def, Value *IRDef, Value *V, + unsigned Part) { + set(Def, V, Part); + ILV->setVectorValue(IRDef, Part, V); +} + // Process the loop in the VPlan-native vectorization path. This path builds // VPlan upfront in the vectorization pipeline, which allows to apply // VPlan-to-VPlan transformations from the very beginning without modifying the @@ -7657,7 +9230,7 @@ static bool processLoopInVPlanNativePath( OptimizationRemarkEmitter *ORE, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, LoopVectorizeHints &Hints) { - if (PSE.getBackedgeTakenCount() == PSE.getSE()->getCouldNotCompute()) { + if (isa(PSE.getBackedgeTakenCount())) { LLVM_DEBUG(dbgs() << "LV: cannot compute the outer-loop trip count\n"); return false; } @@ -7676,7 +9249,7 @@ static bool processLoopInVPlanNativePath( LoopVectorizationPlanner LVP(L, LI, TLI, TTI, LVL, CM, IAI, PSE); // Get user vectorization factor. - const unsigned UserVF = Hints.getWidth(); + ElementCount UserVF = Hints.getWidth(); // Plan how to best vectorize, return the best VF and its cost. const VectorizationFactor VF = LVP.planInVPlanNativePath(UserVF); @@ -7691,7 +9264,7 @@ static bool processLoopInVPlanNativePath( LVP.setBestPlan(VF.Width, 1); InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width, 1, LVL, - &CM); + &CM, BFI, PSI); LLVM_DEBUG(dbgs() << "Vectorizing outer loop in \"" << L->getHeader()->getParent()->getName() << "\"\n"); LVP.executePlan(LB, DT); @@ -7710,7 +9283,7 @@ LoopVectorizePass::LoopVectorizePass(LoopVectorizeOptions Opts) !EnableLoopVectorization) {} bool LoopVectorizePass::processLoop(Loop *L) { - assert((EnableVPlanNativePath || L->empty()) && + assert((EnableVPlanNativePath || L->isInnermost()) && "VPlan-native path is not enabled. Only process inner loops."); #ifndef NDEBUG @@ -7755,7 +9328,7 @@ bool LoopVectorizePass::processLoop(Loop *L) { // Check if it is legal to vectorize the loop. LoopVectorizationRequirements Requirements(*ORE); LoopVectorizationLegality LVL(L, PSE, DT, TTI, TLI, AA, F, GetLAA, LI, ORE, - &Requirements, &Hints, DB, AC); + &Requirements, &Hints, DB, AC, BFI, PSI); if (!LVL.canVectorize(EnableVPlanNativePath)) { LLVM_DEBUG(dbgs() << "LV: Not vectorizing: Cannot prove legality.\n"); Hints.emitRemarkWithHints(); @@ -7772,11 +9345,11 @@ bool LoopVectorizePass::processLoop(Loop *L) { // even evaluating whether vectorization is profitable. Since we cannot modify // the incoming IR, we need to build VPlan upfront in the vectorization // pipeline. - if (!L->empty()) + if (!L->isInnermost()) return processLoopInVPlanNativePath(L, PSE, LI, DT, &LVL, TTI, TLI, DB, AC, ORE, BFI, PSI, Hints); - assert(L->empty() && "Inner loop expected."); + assert(L->isInnermost() && "Inner loop expected."); // Check the loop for a trip count threshold: vectorize loops with a tiny trip // count by optimizing for size, to minimize overheads. @@ -7841,7 +9414,7 @@ bool LoopVectorizePass::processLoop(Loop *L) { LoopVectorizationPlanner LVP(L, LI, TLI, TTI, &LVL, CM, IAI, PSE); // Get user vectorization factor and interleave count. - unsigned UserVF = Hints.getWidth(); + ElementCount UserVF = Hints.getWidth(); unsigned UserIC = Hints.getInterleave(); // Plan how to best vectorize, return the best VF and its cost. @@ -7866,7 +9439,7 @@ bool LoopVectorizePass::processLoop(Loop *L) { return false; } - if (VF.Width == 1) { + if (VF.Width.isScalar()) { LLVM_DEBUG(dbgs() << "LV: Vectorization is possible but not beneficial.\n"); VecDiagMsg = std::make_pair( "VectorizationNotBeneficial", @@ -7955,8 +9528,8 @@ bool LoopVectorizePass::processLoop(Loop *L) { assert(IC > 1 && "interleave count should not be 1 or 0"); // If we decided that it is not legal to vectorize the loop, then // interleave it. - InnerLoopUnroller Unroller(L, PSE, LI, DT, TLI, TTI, AC, ORE, IC, &LVL, - &CM); + InnerLoopUnroller Unroller(L, PSE, LI, DT, TLI, TTI, AC, ORE, IC, &LVL, &CM, + BFI, PSI); LVP.executePlan(Unroller, DT); ORE->emit([&]() { @@ -7967,16 +9540,51 @@ bool LoopVectorizePass::processLoop(Loop *L) { }); } else { // If we decided that it is *legal* to vectorize the loop, then do it. - InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width, IC, - &LVL, &CM); - LVP.executePlan(LB, DT); - ++LoopsVectorized; - // Add metadata to disable runtime unrolling a scalar loop when there are - // no runtime checks about strides and memory. A scalar loop that is - // rarely used is not worth unrolling. - if (!LB.areSafetyChecksAdded()) - DisableRuntimeUnroll = true; + // Consider vectorizing the epilogue too if it's profitable. + VectorizationFactor EpilogueVF = + CM.selectEpilogueVectorizationFactor(VF.Width, LVP); + if (EpilogueVF.Width.isVector()) { + + // The first pass vectorizes the main loop and creates a scalar epilogue + // to be vectorized by executing the plan (potentially with a different + // factor) again shortly afterwards. + EpilogueLoopVectorizationInfo EPI(VF.Width.getKnownMinValue(), IC, + EpilogueVF.Width.getKnownMinValue(), 1); + EpilogueVectorizerMainLoop MainILV(L, PSE, LI, DT, TLI, TTI, AC, ORE, EPI, + &LVL, &CM, BFI, PSI); + + LVP.setBestPlan(EPI.MainLoopVF, EPI.MainLoopUF); + LVP.executePlan(MainILV, DT); + ++LoopsVectorized; + + simplifyLoop(L, DT, LI, SE, AC, nullptr, false /* PreserveLCSSA */); + formLCSSARecursively(*L, *DT, LI, SE); + + // Second pass vectorizes the epilogue and adjusts the control flow + // edges from the first pass. + LVP.setBestPlan(EPI.EpilogueVF, EPI.EpilogueUF); + EPI.MainLoopVF = EPI.EpilogueVF; + EPI.MainLoopUF = EPI.EpilogueUF; + EpilogueVectorizerEpilogueLoop EpilogILV(L, PSE, LI, DT, TLI, TTI, AC, + ORE, EPI, &LVL, &CM, BFI, PSI); + LVP.executePlan(EpilogILV, DT); + ++LoopsEpilogueVectorized; + + if (!MainILV.areSafetyChecksAdded()) + DisableRuntimeUnroll = true; + } else { + InnerLoopVectorizer LB(L, PSE, LI, DT, TLI, TTI, AC, ORE, VF.Width, IC, + &LVL, &CM, BFI, PSI); + LVP.executePlan(LB, DT); + ++LoopsVectorized; + + // Add metadata to disable runtime unrolling a scalar loop when there are + // no runtime checks about strides and memory. A scalar loop that is + // rarely used is not worth unrolling. + if (!LB.areSafetyChecksAdded()) + DisableRuntimeUnroll = true; + } // Report the vectorization decision. ORE->emit([&]() { @@ -8090,7 +9698,8 @@ PreservedAnalyses LoopVectorizePass::run(Function &F, auto &LAM = AM.getResult(F).getManager(); std::function GetLAA = [&](Loop &L) -> const LoopAccessInfo & { - LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, TLI, TTI, MSSA}; + LoopStandardAnalysisResults AR = {AA, AC, DT, LI, SE, + TLI, TTI, nullptr, MSSA}; return LAM.getResult(L, AR); }; auto &MAMProxy = AM.getResult(F); diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp index 5bc35aa4695f..0b630197911a 100644 --- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp +++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp @@ -17,11 +17,8 @@ //===----------------------------------------------------------------------===// #include "llvm/Transforms/Vectorize/SLPVectorizer.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/MapVector.h" -#include "llvm/ADT/None.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/STLExtras.h" @@ -29,14 +26,16 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/iterator.h" #include "llvm/ADT/iterator_range.h" #include "llvm/Analysis/AliasAnalysis.h" +#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CodeMetrics.h" #include "llvm/Analysis/DemandedBits.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/IVDescriptors.h" #include "llvm/Analysis/LoopAccessAnalysis.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemoryLocation.h" @@ -47,7 +46,6 @@ #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" -#include "llvm/Analysis/AssumptionCache.h" #include "llvm/IR/Attributes.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constant.h" @@ -66,7 +64,6 @@ #include "llvm/IR/Module.h" #include "llvm/IR/NoFolder.h" #include "llvm/IR/Operator.h" -#include "llvm/IR/PassManager.h" #include "llvm/IR/PatternMatch.h" #include "llvm/IR/Type.h" #include "llvm/IR/Use.h" @@ -83,6 +80,7 @@ #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/GraphWriter.h" +#include "llvm/Support/InstructionCost.h" #include "llvm/Support/KnownBits.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" @@ -130,6 +128,10 @@ static cl::opt MaxVectorRegSizeOption("slp-max-reg-size", cl::init(128), cl::Hidden, cl::desc("Attempt to vectorize for this register size in bits")); +static cl::opt +MaxVFOption("slp-max-vf", cl::init(0), cl::Hidden, + cl::desc("Maximum SLP vectorization factor (0=unlimited)")); + static cl::opt MaxStoreLookup("slp-max-store-lookup", cl::init(32), cl::Hidden, cl::desc("Maximum depth of the lookup for consecutive stores.")); @@ -204,12 +206,12 @@ static bool allSameBlock(ArrayRef VL) { if (!I0) return false; BasicBlock *BB = I0->getParent(); - for (int i = 1, e = VL.size(); i < e; i++) { - Instruction *I = dyn_cast(VL[i]); - if (!I) + for (int I = 1, E = VL.size(); I < E; I++) { + auto *II = dyn_cast(VL[I]); + if (!II) return false; - if (BB != I->getParent()) + if (BB != II->getParent()) return false; } return true; @@ -234,11 +236,16 @@ static bool isSplat(ArrayRef VL) { return true; } -/// \returns True if \p I is commutative, handles CmpInst as well as Instruction. +/// \returns True if \p I is commutative, handles CmpInst and BinaryOperator. static bool isCommutative(Instruction *I) { - if (auto *IC = dyn_cast(I)) - return IC->isCommutative(); - return I->isCommutative(); + if (auto *Cmp = dyn_cast(I)) + return Cmp->isCommutative(); + if (auto *BO = dyn_cast(I)) + return BO->isCommutative(); + // TODO: This should check for generic Instruction::isCommutative(), but + // we need to confirm that the caller code correctly handles Intrinsics + // for example (does not have 2 operands). + return false; } /// Checks if the vector of instructions can be represented as a shuffle, like: @@ -250,7 +257,7 @@ static bool isCommutative(Instruction *I) { /// %x3x3 = mul i8 %x3, %x3 /// %y1y1 = mul i8 %y1, %y1 /// %y2y2 = mul i8 %y2, %y2 -/// %ins1 = insertelement <4 x i8> undef, i8 %x0x0, i32 0 +/// %ins1 = insertelement <4 x i8> poison, i8 %x0x0, i32 0 /// %ins2 = insertelement <4 x i8> %ins1, i8 %x3x3, i32 1 /// %ins3 = insertelement <4 x i8> %ins2, i8 %y1y1, i32 2 /// %ins4 = insertelement <4 x i8> %ins3, i8 %y2y2, i32 3 @@ -265,13 +272,13 @@ static bool isCommutative(Instruction *I) { /// %x3 = extractelement <4 x i8> %x, i32 3 /// %y1 = extractelement <4 x i8> %y, i32 1 /// %y2 = extractelement <4 x i8> %y, i32 2 -/// %1 = insertelement <4 x i8> undef, i8 %x0, i32 0 +/// %1 = insertelement <4 x i8> poison, i8 %x0, i32 0 /// %2 = insertelement <4 x i8> %1, i8 %x3, i32 1 /// %3 = insertelement <4 x i8> %2, i8 %y1, i32 2 /// %4 = insertelement <4 x i8> %3, i8 %y2, i32 3 /// %5 = mul <4 x i8> %4, %4 /// %6 = extractelement <4 x i8> %5, i32 0 -/// %ins1 = insertelement <4 x i8> undef, i8 %6, i32 0 +/// %ins1 = insertelement <4 x i8> poison, i8 %6, i32 0 /// %7 = extractelement <4 x i8> %5, i32 1 /// %ins2 = insertelement <4 x i8> %ins1, i8 %7, i32 1 /// %8 = extractelement <4 x i8> %5, i32 2 @@ -285,7 +292,8 @@ static bool isCommutative(Instruction *I) { static Optional isShuffle(ArrayRef VL) { auto *EI0 = cast(VL[0]); - unsigned Size = EI0->getVectorOperandType()->getNumElements(); + unsigned Size = + cast(EI0->getVectorOperandType())->getNumElements(); Value *Vec1 = nullptr; Value *Vec2 = nullptr; enum ShuffleMode { Unknown, Select, Permute }; @@ -294,7 +302,7 @@ isShuffle(ArrayRef VL) { auto *EI = cast(VL[I]); auto *Vec = EI->getVectorOperand(); // All vector operands must have the same number of vector elements. - if (cast(Vec->getType())->getNumElements() != Size) + if (cast(Vec->getType())->getNumElements() != Size) return None; auto *Idx = dyn_cast(EI->getIndexOperand()); if (!Idx) @@ -303,7 +311,7 @@ isShuffle(ArrayRef VL) { if (Idx->getValue().uge(Size)) continue; unsigned IntIdx = Idx->getValue().getZExtValue(); - // We can extractelement from undef vector. + // We can extractelement from undef or poison vector. if (isa(Vec)) continue; // For correct shuffling we have to have at most 2 different vector operands @@ -500,7 +508,7 @@ static bool InTreeUserNeedToExtract(Value *Scalar, Instruction *UserInst, } /// \returns the AA location that is being access by the instruction. -static MemoryLocation getLocation(Instruction *I, AliasAnalysis *AA) { +static MemoryLocation getLocation(Instruction *I, AAResults *AA) { if (StoreInst *SI = dyn_cast(I)) return MemoryLocation::get(SI); if (LoadInst *LI = dyn_cast(I)) @@ -521,6 +529,15 @@ static bool isSimple(Instruction *I) { namespace llvm { +static void inversePermutation(ArrayRef Indices, + SmallVectorImpl &Mask) { + Mask.clear(); + const unsigned E = Indices.size(); + Mask.resize(E, E + 1); + for (unsigned I = 0; I < E; ++I) + Mask[Indices[I]] = I; +} + namespace slpvectorizer { /// Bottom Up SLP Vectorizer. @@ -535,9 +552,10 @@ public: using StoreList = SmallVector; using ExtraValueToDebugLocsMap = MapVector>; + using OrdersType = SmallVector; BoUpSLP(Function *Func, ScalarEvolution *Se, TargetTransformInfo *Tti, - TargetLibraryInfo *TLi, AliasAnalysis *Aa, LoopInfo *Li, + TargetLibraryInfo *TLi, AAResults *Aa, LoopInfo *Li, DominatorTree *Dt, AssumptionCache *AC, DemandedBits *DB, const DataLayout *DL, OptimizationRemarkEmitter *ORE) : F(Func), SE(Se), TTI(Tti), TLI(TLi), AA(Aa), LI(Li), DT(Dt), AC(AC), @@ -571,11 +589,11 @@ public: /// \returns the cost incurred by unwanted spills and fills, caused by /// holding live values over call sites. - int getSpillCost() const; + InstructionCost getSpillCost() const; /// \returns the vectorization cost of the subtree that starts at \p VL. /// A negative number means that this is profitable. - int getTreeCost(); + InstructionCost getTreeCost(); /// Construct a vectorizable tree that starts at \p Roots, ignoring users for /// the purpose of scheduling and extraction in the \p UserIgnoreLst. @@ -612,6 +630,14 @@ public: /// \returns The best order of instructions for vectorization. Optional> bestOrder() const { + assert(llvm::all_of( + NumOpsWantToKeepOrder, + [this](const decltype(NumOpsWantToKeepOrder)::value_type &D) { + return D.getFirst().size() == + VectorizableTree[0]->Scalars.size(); + }) && + "All orders must have the same size as number of instructions in " + "tree node."); auto I = std::max_element( NumOpsWantToKeepOrder.begin(), NumOpsWantToKeepOrder.end(), [](const decltype(NumOpsWantToKeepOrder)::value_type &D1, @@ -625,6 +651,81 @@ public: return makeArrayRef(I->getFirst()); } + /// Builds the correct order for root instructions. + /// If some leaves have the same instructions to be vectorized, we may + /// incorrectly evaluate the best order for the root node (it is built for the + /// vector of instructions without repeated instructions and, thus, has less + /// elements than the root node). This function builds the correct order for + /// the root node. + /// For example, if the root node is \, then the leaves + /// are \ and \. When we try to vectorize the first + /// leaf, it will be shrink to \. If instructions in this leaf should + /// be reordered, the best order will be \<1, 0\>. We need to extend this + /// order for the root node. For the root node this order should look like + /// \<3, 0, 1, 2\>. This function extends the order for the reused + /// instructions. + void findRootOrder(OrdersType &Order) { + // If the leaf has the same number of instructions to vectorize as the root + // - order must be set already. + unsigned RootSize = VectorizableTree[0]->Scalars.size(); + if (Order.size() == RootSize) + return; + SmallVector RealOrder(Order.size()); + std::swap(Order, RealOrder); + SmallVector Mask; + inversePermutation(RealOrder, Mask); + Order.assign(Mask.begin(), Mask.end()); + // The leaf has less number of instructions - need to find the true order of + // the root. + // Scan the nodes starting from the leaf back to the root. + const TreeEntry *PNode = VectorizableTree.back().get(); + SmallVector Nodes(1, PNode); + SmallPtrSet Visited; + while (!Nodes.empty() && Order.size() != RootSize) { + const TreeEntry *PNode = Nodes.pop_back_val(); + if (!Visited.insert(PNode).second) + continue; + const TreeEntry &Node = *PNode; + for (const EdgeInfo &EI : Node.UserTreeIndices) + if (EI.UserTE) + Nodes.push_back(EI.UserTE); + if (Node.ReuseShuffleIndices.empty()) + continue; + // Build the order for the parent node. + OrdersType NewOrder(Node.ReuseShuffleIndices.size(), RootSize); + SmallVector OrderCounter(Order.size(), 0); + // The algorithm of the order extension is: + // 1. Calculate the number of the same instructions for the order. + // 2. Calculate the index of the new order: total number of instructions + // with order less than the order of the current instruction + reuse + // number of the current instruction. + // 3. The new order is just the index of the instruction in the original + // vector of the instructions. + for (unsigned I : Node.ReuseShuffleIndices) + ++OrderCounter[Order[I]]; + SmallVector CurrentCounter(Order.size(), 0); + for (unsigned I = 0, E = Node.ReuseShuffleIndices.size(); I < E; ++I) { + unsigned ReusedIdx = Node.ReuseShuffleIndices[I]; + unsigned OrderIdx = Order[ReusedIdx]; + unsigned NewIdx = 0; + for (unsigned J = 0; J < OrderIdx; ++J) + NewIdx += OrderCounter[J]; + NewIdx += CurrentCounter[OrderIdx]; + ++CurrentCounter[OrderIdx]; + assert(NewOrder[NewIdx] == RootSize && + "The order index should not be written already."); + NewOrder[NewIdx] = I; + } + std::swap(Order, NewOrder); + } + assert(Order.size() == RootSize && + "Root node is expected or the size of the order must be the same as " + "the number of elements in the root node."); + assert(llvm::all_of(Order, + [RootSize](unsigned Val) { return Val != RootSize; }) && + "All indices must be initialized"); + } + /// \return The vector element size in bits to use when vectorizing the /// expression tree ending at \p V. If V is a store, the size is the width of /// the stored value. Otherwise, the size is the width of the largest loaded @@ -646,6 +747,12 @@ public: return MinVecRegSize; } + unsigned getMaximumVF(unsigned ElemWidth, unsigned Opcode) const { + unsigned MaxVF = MaxVFOption.getNumOccurrences() ? + MaxVFOption : TTI->getMaximumVF(ElemWidth, Opcode); + return MaxVF ? MaxVF : UINT_MAX; + } + /// Check if homogeneous aggregate is isomorphic to some VectorType. /// Accepts homogeneous multidimensional aggregate of scalars/vectors like /// {[4 x i16], [4 x i16]}, { <2 x float>, <2 x float> }, @@ -665,7 +772,7 @@ public: /// effectively impossible for the backend to undo. /// TODO: If load combining is allowed in the IR optimizer, this analysis /// may not be necessary. - bool isLoadCombineReductionCandidate(unsigned ReductionOpcode) const; + bool isLoadCombineReductionCandidate(RecurKind RdxKind) const; /// Assume that a vector of stores of bitwise-or/shifted/zexted loaded values /// can be load combined in the backend. Load combining may not be allowed in @@ -880,6 +987,14 @@ public: std::array, 2> Values = {{LHS, RHS}}; for (int Idx = 0, IdxE = Values.size(); Idx != IdxE; ++Idx) { Value *V = Values[Idx].first; + if (isa(V)) { + // Since this is a function pass, it doesn't make semantic sense to + // walk the users of a subclass of Constant. The users could be in + // another function, or even another module that happens to be in + // the same LLVMContext. + continue; + } + // Calculate the absolute lane, using the minimum relative lane of LHS // and RHS as base and Idx as the offset. int Ln = std::min(LHS.second, RHS.second) + Idx; @@ -1388,7 +1503,7 @@ private: bool areAllUsersVectorized(Instruction *I) const; /// \returns the cost of the vectorizable entry. - int getEntryCost(TreeEntry *E); + InstructionCost getEntryCost(TreeEntry *E); /// This is the recursive part of buildTree. void buildTree_rec(ArrayRef Roots, unsigned Depth, @@ -1410,20 +1525,21 @@ private: /// \returns the scalarization cost for this type. Scalarization in this /// context means the creation of vectors from a group of scalars. - int getGatherCost(VectorType *Ty, - const DenseSet &ShuffledIndices) const; + InstructionCost + getGatherCost(FixedVectorType *Ty, + const DenseSet &ShuffledIndices) const; /// \returns the scalarization cost for this list of values. Assuming that /// this subtree gets vectorized, we may need to extract the values from the /// roots. This method calculates the cost of extracting the values. - int getGatherCost(ArrayRef VL) const; + InstructionCost getGatherCost(ArrayRef VL) const; /// Set the Builder insert point to one after the last instruction in /// the bundle void setInsertPointAfterBundle(TreeEntry *E); /// \returns a vector from a collection of scalars in \p VL. - Value *Gather(ArrayRef VL, VectorType *Ty); + Value *gather(ArrayRef VL); /// \returns whether the VectorizableTree is fully vectorizable and will /// be beneficial even the tree height is tiny. @@ -1457,15 +1573,17 @@ private: /// The Scalars are vectorized into this value. It is initialized to Null. Value *VectorizedValue = nullptr; - /// Do we need to gather this sequence ? - enum EntryState { Vectorize, NeedToGather }; + /// Do we need to gather this sequence or vectorize it + /// (either with vector instruction or with scatter/gather + /// intrinsics for store/load)? + enum EntryState { Vectorize, ScatterVectorize, NeedToGather }; EntryState State; /// Does this sequence require some shuffling? SmallVector ReuseShuffleIndices; /// Does this entry require reordering? - ArrayRef ReorderIndices; + SmallVector ReorderIndices; /// Points back to the VectorizableTree. /// @@ -1606,6 +1724,9 @@ private: case Vectorize: dbgs() << "Vectorize\n"; break; + case ScatterVectorize: + dbgs() << "ScatterVectorize\n"; + break; case NeedToGather: dbgs() << "NeedToGather\n"; break; @@ -1627,7 +1748,7 @@ private: dbgs() << "NULL\n"; dbgs() << "ReuseShuffleIndices: "; if (ReuseShuffleIndices.empty()) - dbgs() << "Emtpy"; + dbgs() << "Empty"; else for (unsigned ReuseIdx : ReuseShuffleIndices) dbgs() << ReuseIdx << ", "; @@ -1644,26 +1765,55 @@ private: #endif }; +#ifndef NDEBUG + void dumpTreeCosts(TreeEntry *E, InstructionCost ReuseShuffleCost, + InstructionCost VecCost, + InstructionCost ScalarCost) const { + dbgs() << "SLP: Calculated costs for Tree:\n"; E->dump(); + dbgs() << "SLP: Costs:\n"; + dbgs() << "SLP: ReuseShuffleCost = " << ReuseShuffleCost << "\n"; + dbgs() << "SLP: VectorCost = " << VecCost << "\n"; + dbgs() << "SLP: ScalarCost = " << ScalarCost << "\n"; + dbgs() << "SLP: ReuseShuffleCost + VecCost - ScalarCost = " << + ReuseShuffleCost + VecCost - ScalarCost << "\n"; + } +#endif + /// Create a new VectorizableTree entry. TreeEntry *newTreeEntry(ArrayRef VL, Optional Bundle, const InstructionsState &S, const EdgeInfo &UserTreeIdx, ArrayRef ReuseShuffleIndices = None, ArrayRef ReorderIndices = None) { - bool Vectorized = (bool)Bundle; + TreeEntry::EntryState EntryState = + Bundle ? TreeEntry::Vectorize : TreeEntry::NeedToGather; + return newTreeEntry(VL, EntryState, Bundle, S, UserTreeIdx, + ReuseShuffleIndices, ReorderIndices); + } + + TreeEntry *newTreeEntry(ArrayRef VL, + TreeEntry::EntryState EntryState, + Optional Bundle, + const InstructionsState &S, + const EdgeInfo &UserTreeIdx, + ArrayRef ReuseShuffleIndices = None, + ArrayRef ReorderIndices = None) { + assert(((!Bundle && EntryState == TreeEntry::NeedToGather) || + (Bundle && EntryState != TreeEntry::NeedToGather)) && + "Need to vectorize gather entry?"); VectorizableTree.push_back(std::make_unique(VectorizableTree)); TreeEntry *Last = VectorizableTree.back().get(); Last->Idx = VectorizableTree.size() - 1; Last->Scalars.insert(Last->Scalars.begin(), VL.begin(), VL.end()); - Last->State = Vectorized ? TreeEntry::Vectorize : TreeEntry::NeedToGather; + Last->State = EntryState; Last->ReuseShuffleIndices.append(ReuseShuffleIndices.begin(), ReuseShuffleIndices.end()); - Last->ReorderIndices = ReorderIndices; + Last->ReorderIndices.append(ReorderIndices.begin(), ReorderIndices.end()); Last->setOperations(S); - if (Vectorized) { - for (int i = 0, e = VL.size(); i != e; ++i) { - assert(!getTreeEntry(VL[i]) && "Scalar already in tree!"); - ScalarToTreeEntry[VL[i]] = Last; + if (Last->State != TreeEntry::NeedToGather) { + for (Value *V : VL) { + assert(!getTreeEntry(V) && "Scalar already in tree!"); + ScalarToTreeEntry[V] = Last; } // Update the scheduler bundle to point to this TreeEntry. unsigned Lane = 0; @@ -1699,18 +1849,10 @@ private: } #endif - TreeEntry *getTreeEntry(Value *V) { - auto I = ScalarToTreeEntry.find(V); - if (I != ScalarToTreeEntry.end()) - return I->second; - return nullptr; - } + TreeEntry *getTreeEntry(Value *V) { return ScalarToTreeEntry.lookup(V); } const TreeEntry *getTreeEntry(Value *V) const { - auto I = ScalarToTreeEntry.find(V); - if (I != ScalarToTreeEntry.end()) - return I->second; - return nullptr; + return ScalarToTreeEntry.lookup(V); } /// Maps a specific scalar to its tree entry. @@ -2195,7 +2337,6 @@ private: /// List of users to ignore during scheduling and that don't need extracting. ArrayRef UserIgnoreList; - using OrdersType = SmallVector; /// A DenseMapInfo implementation for holding DenseMaps and DenseSets of /// sorted SmallVectors of unsigned. struct OrdersTypeDenseMapInfo { @@ -2233,7 +2374,7 @@ private: ScalarEvolution *SE; TargetTransformInfo *TTI; TargetLibraryInfo *TLI; - AliasAnalysis *AA; + AAResults *AA; LoopInfo *LI; DominatorTree *DT; AssumptionCache *AC; @@ -2332,9 +2473,9 @@ template <> struct DOTGraphTraits : public DefaultDOTGraphTraits { } for (auto V : Entry->Scalars) { OS << *V; - if (std::any_of( - R->ExternalUses.begin(), R->ExternalUses.end(), - [&](const BoUpSLP::ExternalUser &EU) { return EU.Scalar == V; })) + if (llvm::any_of(R->ExternalUses, [&](const BoUpSLP::ExternalUser &EU) { + return EU.Scalar == V; + })) OS << " "; OS << "\n"; } @@ -2366,13 +2507,17 @@ BoUpSLP::~BoUpSLP() { "trying to erase instruction with users."); Pair.getFirst()->eraseFromParent(); } +#ifdef EXPENSIVE_CHECKS + // If we could guarantee that this call is not extremely slow, we could + // remove the ifdef limitation (see PR47712). assert(!verifyFunction(*F, &dbgs())); +#endif } void BoUpSLP::eraseInstructions(ArrayRef AV) { for (auto *V : AV) { if (auto *I = dyn_cast(V)) - eraseInstruction(I, /*ReplaceWithUndef=*/true); + eraseInstruction(I, /*ReplaceOpsWithUndef=*/true); }; } @@ -2597,11 +2742,11 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, auto *PH = cast(VL0); // Check for terminator values (e.g. invoke). - for (unsigned j = 0; j < VL.size(); ++j) - for (unsigned i = 0, e = PH->getNumIncomingValues(); i < e; ++i) { + for (Value *V : VL) + for (unsigned I = 0, E = PH->getNumIncomingValues(); I < E; ++I) { Instruction *Term = dyn_cast( - cast(VL[j])->getIncomingValueForBlock( - PH->getIncomingBlock(i))); + cast(V)->getIncomingValueForBlock( + PH->getIncomingBlock(I))); if (Term && Term->isTerminator()) { LLVM_DEBUG(dbgs() << "SLP: Need to swizzle PHINodes (terminator use).\n"); @@ -2618,13 +2763,13 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, // Keeps the reordered operands to avoid code duplication. SmallVector OperandsVec; - for (unsigned i = 0, e = PH->getNumIncomingValues(); i < e; ++i) { + for (unsigned I = 0, E = PH->getNumIncomingValues(); I < E; ++I) { ValueList Operands; // Prepare the operand vector. - for (Value *j : VL) - Operands.push_back(cast(j)->getIncomingValueForBlock( - PH->getIncomingBlock(i))); - TE->setOperand(i, Operands); + for (Value *V : VL) + Operands.push_back(cast(V)->getIncomingValueForBlock( + PH->getIncomingBlock(I))); + TE->setOperand(I, Operands); OperandsVec.push_back(Operands); } for (unsigned OpIdx = 0, OpE = OperandsVec.size(); OpIdx != OpE; ++OpIdx) @@ -2657,12 +2802,10 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, }); // Insert new order with initial value 0, if it does not exist, // otherwise return the iterator to the existing one. - auto StoredCurrentOrderAndNum = - NumOpsWantToKeepOrder.try_emplace(CurrentOrder).first; - ++StoredCurrentOrderAndNum->getSecond(); newTreeEntry(VL, Bundle /*vectorized*/, S, UserTreeIdx, - ReuseShuffleIndicies, - StoredCurrentOrderAndNum->getFirst()); + ReuseShuffleIndicies, CurrentOrder); + findRootOrder(CurrentOrder); + ++NumOpsWantToKeepOrder[CurrentOrder]; // This is a special case, as it does not gather, but at the same time // we are not extending buildTree_rec() towards the operands. ValueList Op0; @@ -2739,16 +2882,23 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, LLVM_DEBUG(dbgs() << "SLP: added a vector of loads.\n"); } else { // Need to reorder. - auto I = NumOpsWantToKeepOrder.try_emplace(CurrentOrder).first; - ++I->getSecond(); TreeEntry *TE = newTreeEntry(VL, Bundle /*vectorized*/, S, UserTreeIdx, - ReuseShuffleIndicies, I->getFirst()); + ReuseShuffleIndicies, CurrentOrder); TE->setOperandsInOrder(); LLVM_DEBUG(dbgs() << "SLP: added a vector of jumbled loads.\n"); + findRootOrder(CurrentOrder); + ++NumOpsWantToKeepOrder[CurrentOrder]; } return; } + // Vectorizing non-consecutive loads with `llvm.masked.gather`. + TreeEntry *TE = newTreeEntry(VL, TreeEntry::ScatterVectorize, Bundle, S, + UserTreeIdx, ReuseShuffleIndicies); + TE->setOperandsInOrder(); + buildTree_rec(PointerOps, Depth + 1, {TE, 0}); + LLVM_DEBUG(dbgs() << "SLP: added a vector of non-consecutive loads.\n"); + return; } LLVM_DEBUG(dbgs() << "SLP: Gathering non-consecutive loads.\n"); @@ -2883,8 +3033,8 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, for (unsigned i = 0, e = VL0->getNumOperands(); i < e; ++i) { ValueList Operands; // Prepare the operand vector. - for (Value *j : VL) - Operands.push_back(cast(j)->getOperand(i)); + for (Value *V : VL) + Operands.push_back(cast(V)->getOperand(i)); buildTree_rec(Operands, Depth + 1, {TE, i}); } @@ -2952,6 +3102,16 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, case Instruction::Store: { // Check if the stores are consecutive or if we need to swizzle them. llvm::Type *ScalarTy = cast(VL0)->getValueOperand()->getType(); + // Avoid types that are padded when being allocated as scalars, while + // being packed together in a vector (such as i1). + if (DL->getTypeSizeInBits(ScalarTy) != + DL->getTypeAllocSizeInBits(ScalarTy)) { + BS.cancelScheduling(VL, VL0); + newTreeEntry(VL, None /*not vectorized*/, S, UserTreeIdx, + ReuseShuffleIndicies); + LLVM_DEBUG(dbgs() << "SLP: Gathering stores of non-packed type.\n"); + return; + } // Make sure all stores in the bundle are simple - we can't vectorize // atomic or volatile stores. SmallVector PointerOps(VL.size()); @@ -3001,15 +3161,14 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, buildTree_rec(Operands, Depth + 1, {TE, 0}); LLVM_DEBUG(dbgs() << "SLP: added a vector of stores.\n"); } else { - // Need to reorder. - auto I = NumOpsWantToKeepOrder.try_emplace(CurrentOrder).first; - ++(I->getSecond()); TreeEntry *TE = newTreeEntry(VL, Bundle /*vectorized*/, S, UserTreeIdx, - ReuseShuffleIndicies, I->getFirst()); + ReuseShuffleIndicies, CurrentOrder); TE->setOperandsInOrder(); buildTree_rec(Operands, Depth + 1, {TE, 0}); LLVM_DEBUG(dbgs() << "SLP: added a vector of jumbled stores.\n"); + findRootOrder(CurrentOrder); + ++NumOpsWantToKeepOrder[CurrentOrder]; } return; } @@ -3028,7 +3187,7 @@ void BoUpSLP::buildTree_rec(ArrayRef VL, unsigned Depth, Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); VFShape Shape = VFShape::get( - *CI, {static_cast(VL.size()), false /*Scalable*/}, + *CI, ElementCount::getFixed(static_cast(VL.size())), false /*HasGlobalPred*/); Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape); @@ -3165,7 +3324,7 @@ unsigned BoUpSLP::canMapToVector(Type *T, const DataLayout &DL) const { N *= AT->getNumElements(); EltTy = AT->getElementType(); } else { - auto *VT = cast(EltTy); + auto *VT = cast(EltTy); N *= VT->getNumElements(); EltTy = VT->getElementType(); } @@ -3203,7 +3362,7 @@ bool BoUpSLP::canReuseExtract(ArrayRef VL, Value *OpValue, if (!LI || !LI->isSimple() || !LI->hasNUses(VL.size())) return false; } else { - NElts = cast(Vec->getType())->getNumElements(); + NElts = cast(Vec->getType())->getNumElements(); } if (NElts != VL.size()) @@ -3247,27 +3406,26 @@ bool BoUpSLP::canReuseExtract(ArrayRef VL, Value *OpValue, } bool BoUpSLP::areAllUsersVectorized(Instruction *I) const { - return I->hasOneUse() || - std::all_of(I->user_begin(), I->user_end(), [this](User *U) { + return I->hasOneUse() || llvm::all_of(I->users(), [this](User *U) { return ScalarToTreeEntry.count(U) > 0; }); } -static std::pair -getVectorCallCosts(CallInst *CI, VectorType *VecTy, TargetTransformInfo *TTI, - TargetLibraryInfo *TLI) { +static std::pair +getVectorCallCosts(CallInst *CI, FixedVectorType *VecTy, + TargetTransformInfo *TTI, TargetLibraryInfo *TLI) { Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); // Calculate the cost of the scalar and vector calls. - IntrinsicCostAttributes CostAttrs(ID, *CI, VecTy->getNumElements()); - int IntrinsicCost = + IntrinsicCostAttributes CostAttrs(ID, *CI, VecTy->getElementCount()); + auto IntrinsicCost = TTI->getIntrinsicInstrCost(CostAttrs, TTI::TCK_RecipThroughput); - auto Shape = - VFShape::get(*CI, {static_cast(VecTy->getNumElements()), false}, - false /*HasGlobalPred*/); + auto Shape = VFShape::get(*CI, ElementCount::getFixed(static_cast( + VecTy->getNumElements())), + false /*HasGlobalPred*/); Function *VecFunc = VFDatabase(*CI).getVectorizedFunction(Shape); - int LibCost = IntrinsicCost; + auto LibCost = IntrinsicCost; if (!CI->isNoBuiltin() && VecFunc) { // Calculate the cost of the vector library call. SmallVector VecTys; @@ -3282,7 +3440,7 @@ getVectorCallCosts(CallInst *CI, VectorType *VecTy, TargetTransformInfo *TTI, return {IntrinsicCost, LibCost}; } -int BoUpSLP::getEntryCost(TreeEntry *E) { +InstructionCost BoUpSLP::getEntryCost(TreeEntry *E) { ArrayRef VL = E->Scalars; Type *ScalarTy = VL[0]->getType(); @@ -3301,7 +3459,7 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { unsigned ReuseShuffleNumbers = E->ReuseShuffleIndices.size(); bool NeedToShuffleReuses = !E->ReuseShuffleIndices.empty(); - int ReuseShuffleCost = 0; + InstructionCost ReuseShuffleCost = 0; if (NeedToShuffleReuses) { ReuseShuffleCost = TTI->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, VecTy); @@ -3317,7 +3475,8 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { allSameType(VL) && allSameBlock(VL)) { Optional ShuffleKind = isShuffle(VL); if (ShuffleKind.hasValue()) { - int Cost = TTI->getShuffleCost(ShuffleKind.getValue(), VecTy); + InstructionCost Cost = + TTI->getShuffleCost(ShuffleKind.getValue(), VecTy); for (auto *V : VL) { // If all users of instruction are going to be vectorized and this // instruction itself is not going to be vectorized, consider this @@ -3336,7 +3495,9 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { } return ReuseShuffleCost + getGatherCost(VL); } - assert(E->State == TreeEntry::Vectorize && "Unhandled state"); + assert((E->State == TreeEntry::Vectorize || + E->State == TreeEntry::ScatterVectorize) && + "Unhandled state"); assert(E->getOpcode() && allSameType(VL) && allSameBlock(VL) && "Invalid VL"); Instruction *VL0 = E->getMainOp(); unsigned ShuffleOrOp = @@ -3375,37 +3536,37 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { TTI->getVectorInstrCost(Instruction::ExtractElement, VecTy, Idx); } } - int DeadCost = ReuseShuffleCost; + InstructionCost DeadCost = ReuseShuffleCost; if (!E->ReorderIndices.empty()) { // TODO: Merge this shuffle with the ReuseShuffleCost. DeadCost += TTI->getShuffleCost( TargetTransformInfo::SK_PermuteSingleSrc, VecTy); } - for (unsigned i = 0, e = VL.size(); i < e; ++i) { - Instruction *E = cast(VL[i]); + for (unsigned I = 0, E = VL.size(); I < E; ++I) { + Instruction *EI = cast(VL[I]); // If all users are going to be vectorized, instruction can be // considered as dead. // The same, if have only one user, it will be vectorized for sure. - if (areAllUsersVectorized(E)) { + if (areAllUsersVectorized(EI)) { // Take credit for instruction that will become dead. - if (E->hasOneUse()) { - Instruction *Ext = E->user_back(); + if (EI->hasOneUse()) { + Instruction *Ext = EI->user_back(); if ((isa(Ext) || isa(Ext)) && all_of(Ext->users(), [](User *U) { return isa(U); })) { // Use getExtractWithExtendCost() to calculate the cost of // extractelement/ext pair. DeadCost -= TTI->getExtractWithExtendCost( - Ext->getOpcode(), Ext->getType(), VecTy, i); + Ext->getOpcode(), Ext->getType(), VecTy, I); // Add back the cost of s|zext which is subtracted separately. DeadCost += TTI->getCastInstrCost( - Ext->getOpcode(), Ext->getType(), E->getType(), CostKind, - Ext); + Ext->getOpcode(), Ext->getType(), EI->getType(), + TTI::getCastContextHint(Ext), CostKind, Ext); continue; } } DeadCost -= - TTI->getVectorInstrCost(Instruction::ExtractElement, VecTy, i); + TTI->getVectorInstrCost(Instruction::ExtractElement, VecTy, I); } } return DeadCost; @@ -3423,40 +3584,78 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { case Instruction::FPTrunc: case Instruction::BitCast: { Type *SrcTy = VL0->getOperand(0)->getType(); - int ScalarEltCost = - TTI->getCastInstrCost(E->getOpcode(), ScalarTy, SrcTy, CostKind, - VL0); + InstructionCost ScalarEltCost = + TTI->getCastInstrCost(E->getOpcode(), ScalarTy, SrcTy, + TTI::getCastContextHint(VL0), CostKind, VL0); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } // Calculate the cost of this instruction. - int ScalarCost = VL.size() * ScalarEltCost; + InstructionCost ScalarCost = VL.size() * ScalarEltCost; auto *SrcVecTy = FixedVectorType::get(SrcTy, VL.size()); - int VecCost = 0; + InstructionCost VecCost = 0; // Check if the values are candidates to demote. if (!MinBWs.count(VL0) || VecTy != SrcVecTy) { - VecCost = ReuseShuffleCost + - TTI->getCastInstrCost(E->getOpcode(), VecTy, SrcVecTy, - CostKind, VL0); + VecCost = + ReuseShuffleCost + + TTI->getCastInstrCost(E->getOpcode(), VecTy, SrcVecTy, + TTI::getCastContextHint(VL0), CostKind, VL0); } + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecCost, ScalarCost)); return VecCost - ScalarCost; } case Instruction::FCmp: case Instruction::ICmp: case Instruction::Select: { // Calculate the cost of this instruction. - int ScalarEltCost = TTI->getCmpSelInstrCost(E->getOpcode(), ScalarTy, - Builder.getInt1Ty(), - CostKind, VL0); + InstructionCost ScalarEltCost = + TTI->getCmpSelInstrCost(E->getOpcode(), ScalarTy, Builder.getInt1Ty(), + CmpInst::BAD_ICMP_PREDICATE, CostKind, VL0); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } auto *MaskTy = FixedVectorType::get(Builder.getInt1Ty(), VL.size()); - int ScalarCost = VecTy->getNumElements() * ScalarEltCost; - int VecCost = TTI->getCmpSelInstrCost(E->getOpcode(), VecTy, MaskTy, - CostKind, VL0); + InstructionCost ScalarCost = VecTy->getNumElements() * ScalarEltCost; + + // Check if all entries in VL are either compares or selects with compares + // as condition that have the same predicates. + CmpInst::Predicate VecPred = CmpInst::BAD_ICMP_PREDICATE; + bool First = true; + for (auto *V : VL) { + CmpInst::Predicate CurrentPred; + auto MatchCmp = m_Cmp(CurrentPred, m_Value(), m_Value()); + if ((!match(V, m_Select(MatchCmp, m_Value(), m_Value())) && + !match(V, MatchCmp)) || + (!First && VecPred != CurrentPred)) { + VecPred = CmpInst::BAD_ICMP_PREDICATE; + break; + } + First = false; + VecPred = CurrentPred; + } + + InstructionCost VecCost = TTI->getCmpSelInstrCost( + E->getOpcode(), VecTy, MaskTy, VecPred, CostKind, VL0); + // Check if it is possible and profitable to use min/max for selects in + // VL. + // + auto IntrinsicAndUse = canConvertToMinOrMaxIntrinsic(VL); + if (IntrinsicAndUse.first != Intrinsic::not_intrinsic) { + IntrinsicCostAttributes CostAttrs(IntrinsicAndUse.first, VecTy, + {VecTy, VecTy}); + InstructionCost IntrinsicCost = + TTI->getIntrinsicInstrCost(CostAttrs, CostKind); + // If the selects are the only uses of the compares, they will be dead + // and we can adjust the cost by removing their cost. + if (IntrinsicAndUse.second) + IntrinsicCost -= + TTI->getCmpSelInstrCost(Instruction::ICmp, VecTy, MaskTy, + CmpInst::BAD_ICMP_PREDICATE, CostKind); + VecCost = std::min(VecCost, IntrinsicCost); + } + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecCost, ScalarCost)); return ReuseShuffleCost + VecCost - ScalarCost; } case Instruction::FNeg: @@ -3516,16 +3715,17 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { } SmallVector Operands(VL0->operand_values()); - int ScalarEltCost = TTI->getArithmeticInstrCost( - E->getOpcode(), ScalarTy, CostKind, Op1VK, Op2VK, Op1VP, Op2VP, - Operands, VL0); + InstructionCost ScalarEltCost = + TTI->getArithmeticInstrCost(E->getOpcode(), ScalarTy, CostKind, Op1VK, + Op2VK, Op1VP, Op2VP, Operands, VL0); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } - int ScalarCost = VecTy->getNumElements() * ScalarEltCost; - int VecCost = TTI->getArithmeticInstrCost( - E->getOpcode(), VecTy, CostKind, Op1VK, Op2VK, Op1VP, Op2VP, - Operands, VL0); + InstructionCost ScalarCost = VecTy->getNumElements() * ScalarEltCost; + InstructionCost VecCost = + TTI->getArithmeticInstrCost(E->getOpcode(), VecTy, CostKind, Op1VK, + Op2VK, Op1VP, Op2VP, Operands, VL0); + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecCost, ScalarCost)); return ReuseShuffleCost + VecCost - ScalarCost; } case Instruction::GetElementPtr: { @@ -3534,36 +3734,42 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { TargetTransformInfo::OperandValueKind Op2VK = TargetTransformInfo::OK_UniformConstantValue; - int ScalarEltCost = - TTI->getArithmeticInstrCost(Instruction::Add, ScalarTy, CostKind, - Op1VK, Op2VK); + InstructionCost ScalarEltCost = TTI->getArithmeticInstrCost( + Instruction::Add, ScalarTy, CostKind, Op1VK, Op2VK); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } - int ScalarCost = VecTy->getNumElements() * ScalarEltCost; - int VecCost = - TTI->getArithmeticInstrCost(Instruction::Add, VecTy, CostKind, - Op1VK, Op2VK); + InstructionCost ScalarCost = VecTy->getNumElements() * ScalarEltCost; + InstructionCost VecCost = TTI->getArithmeticInstrCost( + Instruction::Add, VecTy, CostKind, Op1VK, Op2VK); + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecCost, ScalarCost)); return ReuseShuffleCost + VecCost - ScalarCost; } case Instruction::Load: { // Cost of wide load - cost of scalar loads. Align alignment = cast(VL0)->getAlign(); - int ScalarEltCost = - TTI->getMemoryOpCost(Instruction::Load, ScalarTy, alignment, 0, - CostKind, VL0); + InstructionCost ScalarEltCost = TTI->getMemoryOpCost( + Instruction::Load, ScalarTy, alignment, 0, CostKind, VL0); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } - int ScalarLdCost = VecTy->getNumElements() * ScalarEltCost; - int VecLdCost = - TTI->getMemoryOpCost(Instruction::Load, VecTy, alignment, 0, - CostKind, VL0); + InstructionCost ScalarLdCost = VecTy->getNumElements() * ScalarEltCost; + InstructionCost VecLdCost; + if (E->State == TreeEntry::Vectorize) { + VecLdCost = TTI->getMemoryOpCost(Instruction::Load, VecTy, alignment, 0, + CostKind, VL0); + } else { + assert(E->State == TreeEntry::ScatterVectorize && "Unknown EntryState"); + VecLdCost = TTI->getGatherScatterOpCost( + Instruction::Load, VecTy, cast(VL0)->getPointerOperand(), + /*VariableMask=*/false, alignment, CostKind, VL0); + } if (!E->ReorderIndices.empty()) { // TODO: Merge this shuffle with the ReuseShuffleCost. VecLdCost += TTI->getShuffleCost( TargetTransformInfo::SK_PermuteSingleSrc, VecTy); } + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecLdCost, ScalarLdCost)); return ReuseShuffleCost + VecLdCost - ScalarLdCost; } case Instruction::Store: { @@ -3572,19 +3778,19 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { auto *SI = cast(IsReorder ? VL[E->ReorderIndices.front()] : VL0); Align Alignment = SI->getAlign(); - int ScalarEltCost = - TTI->getMemoryOpCost(Instruction::Store, ScalarTy, Alignment, 0, - CostKind, VL0); + InstructionCost ScalarEltCost = TTI->getMemoryOpCost( + Instruction::Store, ScalarTy, Alignment, 0, CostKind, VL0); if (NeedToShuffleReuses) ReuseShuffleCost = -(ReuseShuffleNumbers - VL.size()) * ScalarEltCost; - int ScalarStCost = VecTy->getNumElements() * ScalarEltCost; - int VecStCost = TTI->getMemoryOpCost(Instruction::Store, - VecTy, Alignment, 0, CostKind, VL0); + InstructionCost ScalarStCost = VecTy->getNumElements() * ScalarEltCost; + InstructionCost VecStCost = TTI->getMemoryOpCost( + Instruction::Store, VecTy, Alignment, 0, CostKind, VL0); if (IsReorder) { // TODO: Merge this shuffle with the ReuseShuffleCost. VecStCost += TTI->getShuffleCost( TargetTransformInfo::SK_PermuteSingleSrc, VecTy); } + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecStCost, ScalarStCost)); return ReuseShuffleCost + VecStCost - ScalarStCost; } case Instruction::Call: { @@ -3592,15 +3798,17 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { Intrinsic::ID ID = getVectorIntrinsicIDForCall(CI, TLI); // Calculate the cost of the scalar and vector calls. - IntrinsicCostAttributes CostAttrs(ID, *CI, 1, 1); - int ScalarEltCost = TTI->getIntrinsicInstrCost(CostAttrs, CostKind); + IntrinsicCostAttributes CostAttrs(ID, *CI, ElementCount::getFixed(1), 1); + InstructionCost ScalarEltCost = + TTI->getIntrinsicInstrCost(CostAttrs, CostKind); if (NeedToShuffleReuses) { ReuseShuffleCost -= (ReuseShuffleNumbers - VL.size()) * ScalarEltCost; } - int ScalarCallCost = VecTy->getNumElements() * ScalarEltCost; + InstructionCost ScalarCallCost = VecTy->getNumElements() * ScalarEltCost; auto VecCallCosts = getVectorCallCosts(CI, VecTy, TTI, TLI); - int VecCallCost = std::min(VecCallCosts.first, VecCallCosts.second); + InstructionCost VecCallCost = + std::min(VecCallCosts.first, VecCallCosts.second); LLVM_DEBUG(dbgs() << "SLP: Call cost " << VecCallCost - ScalarCallCost << " (" << VecCallCost << "-" << ScalarCallCost << ")" @@ -3615,7 +3823,7 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { (Instruction::isCast(E->getOpcode()) && Instruction::isCast(E->getAltOpcode()))) && "Invalid Shuffle Vector Operand"); - int ScalarCost = 0; + InstructionCost ScalarCost = 0; if (NeedToShuffleReuses) { for (unsigned Idx : E->ReuseShuffleIndices) { Instruction *I = cast(VL[Idx]); @@ -3633,7 +3841,7 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { } // VecCost is equal to sum of the cost of creating 2 vectors // and the cost of creating shuffle. - int VecCost = 0; + InstructionCost VecCost = 0; if (Instruction::isBinaryOp(E->getOpcode())) { VecCost = TTI->getArithmeticInstrCost(E->getOpcode(), VecTy, CostKind); VecCost += TTI->getArithmeticInstrCost(E->getAltOpcode(), VecTy, @@ -3644,11 +3852,12 @@ int BoUpSLP::getEntryCost(TreeEntry *E) { auto *Src0Ty = FixedVectorType::get(Src0SclTy, VL.size()); auto *Src1Ty = FixedVectorType::get(Src1SclTy, VL.size()); VecCost = TTI->getCastInstrCost(E->getOpcode(), VecTy, Src0Ty, - CostKind); + TTI::CastContextHint::None, CostKind); VecCost += TTI->getCastInstrCost(E->getAltOpcode(), VecTy, Src1Ty, - CostKind); + TTI::CastContextHint::None, CostKind); } VecCost += TTI->getShuffleCost(TargetTransformInfo::SK_Select, VecTy, 0); + LLVM_DEBUG(dumpTreeCosts(E, ReuseShuffleCost, VecCost, ScalarCost)); return ReuseShuffleCost + VecCost - ScalarCost; } default: @@ -3686,11 +3895,13 @@ static bool isLoadCombineCandidateImpl(Value *Root, unsigned NumElts, TargetTransformInfo *TTI) { // Look past the root to find a source value. Arbitrarily follow the // path through operand 0 of any 'or'. Also, peek through optional - // shift-left-by-constant. + // shift-left-by-multiple-of-8-bits. Value *ZextLoad = Root; + const APInt *ShAmtC; while (!isa(ZextLoad) && (match(ZextLoad, m_Or(m_Value(), m_Value())) || - match(ZextLoad, m_Shl(m_Value(), m_Constant())))) + (match(ZextLoad, m_Shl(m_Value(), m_APInt(ShAmtC))) && + ShAmtC->urem(8) == 0))) ZextLoad = cast(ZextLoad)->getOperand(0); // Check if the input is an extended load of the required or/shift expression. @@ -3714,8 +3925,8 @@ static bool isLoadCombineCandidateImpl(Value *Root, unsigned NumElts, return true; } -bool BoUpSLP::isLoadCombineReductionCandidate(unsigned RdxOpcode) const { - if (RdxOpcode != Instruction::Or) +bool BoUpSLP::isLoadCombineReductionCandidate(RecurKind RdxKind) const { + if (RdxKind != RecurKind::Or) return false; unsigned NumElts = VectorizableTree[0]->Scalars.size(); @@ -3756,22 +3967,35 @@ bool BoUpSLP::isTreeTinyAndNotFullyVectorizable() const { return true; } -int BoUpSLP::getSpillCost() const { +InstructionCost BoUpSLP::getSpillCost() const { // Walk from the bottom of the tree to the top, tracking which values are // live. When we see a call instruction that is not part of our tree, // query TTI to see if there is a cost to keeping values live over it // (for example, if spills and fills are required). unsigned BundleWidth = VectorizableTree.front()->Scalars.size(); - int Cost = 0; + InstructionCost Cost = 0; SmallPtrSet LiveValues; Instruction *PrevInst = nullptr; + // The entries in VectorizableTree are not necessarily ordered by their + // position in basic blocks. Collect them and order them by dominance so later + // instructions are guaranteed to be visited first. For instructions in + // different basic blocks, we only scan to the beginning of the block, so + // their order does not matter, as long as all instructions in a basic block + // are grouped together. Using dominance ensures a deterministic order. + SmallVector OrderedScalars; for (const auto &TEPtr : VectorizableTree) { Instruction *Inst = dyn_cast(TEPtr->Scalars[0]); if (!Inst) continue; + OrderedScalars.push_back(Inst); + } + llvm::stable_sort(OrderedScalars, [this](Instruction *A, Instruction *B) { + return DT->dominates(B, A); + }); + for (Instruction *Inst : OrderedScalars) { if (!PrevInst) { PrevInst = Inst; continue; @@ -3825,8 +4049,8 @@ int BoUpSLP::getSpillCost() const { return Cost; } -int BoUpSLP::getTreeCost() { - int Cost = 0; +InstructionCost BoUpSLP::getTreeCost() { + InstructionCost Cost = 0; LLVM_DEBUG(dbgs() << "SLP: Calculating cost for tree of size " << VectorizableTree.size() << ".\n"); @@ -3856,15 +4080,16 @@ int BoUpSLP::getTreeCost() { })) continue; - int C = getEntryCost(&TE); + InstructionCost C = getEntryCost(&TE); + Cost += C; LLVM_DEBUG(dbgs() << "SLP: Adding cost " << C << " for bundle that starts with " << *TE.Scalars[0] - << ".\n"); - Cost += C; + << ".\n" + << "SLP: Current total cost = " << Cost << "\n"); } SmallPtrSet ExtractCostCalculated; - int ExtractCost = 0; + InstructionCost ExtractCost = 0; for (ExternalUser &EU : ExternalUses) { // We only add extract cost once for the same scalar. if (!ExtractCostCalculated.insert(EU.Scalar).second) @@ -3894,39 +4119,42 @@ int BoUpSLP::getTreeCost() { } } - int SpillCost = getSpillCost(); + InstructionCost SpillCost = getSpillCost(); Cost += SpillCost + ExtractCost; - std::string Str; +#ifndef NDEBUG + SmallString<256> Str; { - raw_string_ostream OS(Str); + raw_svector_ostream OS(Str); OS << "SLP: Spill Cost = " << SpillCost << ".\n" << "SLP: Extract Cost = " << ExtractCost << ".\n" << "SLP: Total Cost = " << Cost << ".\n"; } LLVM_DEBUG(dbgs() << Str); - if (ViewSLPTree) ViewGraph(this, "SLP" + F->getName(), false, Str); +#endif return Cost; } -int BoUpSLP::getGatherCost(VectorType *Ty, - const DenseSet &ShuffledIndices) const { +InstructionCost +BoUpSLP::getGatherCost(FixedVectorType *Ty, + const DenseSet &ShuffledIndices) const { unsigned NumElts = Ty->getNumElements(); APInt DemandedElts = APInt::getNullValue(NumElts); - for (unsigned i = 0; i < NumElts; ++i) - if (!ShuffledIndices.count(i)) - DemandedElts.setBit(i); - int Cost = TTI->getScalarizationOverhead(Ty, DemandedElts, /*Insert*/ true, - /*Extract*/ false); + for (unsigned I = 0; I < NumElts; ++I) + if (!ShuffledIndices.count(I)) + DemandedElts.setBit(I); + InstructionCost Cost = + TTI->getScalarizationOverhead(Ty, DemandedElts, /*Insert*/ true, + /*Extract*/ false); if (!ShuffledIndices.empty()) Cost += TTI->getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, Ty); return Cost; } -int BoUpSLP::getGatherCost(ArrayRef VL) const { +InstructionCost BoUpSLP::getGatherCost(ArrayRef VL) const { // Find the type of the operands in VL. Type *ScalarTy = VL[0]->getType(); if (StoreInst *SI = dyn_cast(VL[0])) @@ -3968,11 +4196,10 @@ void BoUpSLP::setInsertPointAfterBundle(TreeEntry *E) { // should be in this block. auto *Front = E->getMainOp(); auto *BB = Front->getParent(); - assert(llvm::all_of(make_range(E->Scalars.begin(), E->Scalars.end()), - [=](Value *V) -> bool { - auto *I = cast(V); - return !E->isOpcodeOrAlt(I) || I->getParent() == BB; - })); + assert(llvm::all_of(E->Scalars, [=](Value *V) -> bool { + auto *I = cast(V); + return !E->isOpcodeOrAlt(I) || I->getParent() == BB; + })); // The last instruction in the bundle in program order. Instruction *LastInst = nullptr; @@ -4025,34 +4252,30 @@ void BoUpSLP::setInsertPointAfterBundle(TreeEntry *E) { Builder.SetCurrentDebugLocation(Front->getDebugLoc()); } -Value *BoUpSLP::Gather(ArrayRef VL, VectorType *Ty) { - Value *Vec = UndefValue::get(Ty); - // Generate the 'InsertElement' instruction. - for (unsigned i = 0; i < Ty->getNumElements(); ++i) { - Vec = Builder.CreateInsertElement(Vec, VL[i], Builder.getInt32(i)); - if (auto *Insrt = dyn_cast(Vec)) { - GatherSeq.insert(Insrt); - CSEBlocks.insert(Insrt->getParent()); - - // Add to our 'need-to-extract' list. - if (TreeEntry *E = getTreeEntry(VL[i])) { - // Find which lane we need to extract. - int FoundLane = -1; - for (unsigned Lane = 0, LE = E->Scalars.size(); Lane != LE; ++Lane) { - // Is this the lane of the scalar that we are looking for ? - if (E->Scalars[Lane] == VL[i]) { - FoundLane = Lane; - break; - } - } - assert(FoundLane >= 0 && "Could not find the correct lane"); - if (!E->ReuseShuffleIndices.empty()) { - FoundLane = - std::distance(E->ReuseShuffleIndices.begin(), - llvm::find(E->ReuseShuffleIndices, FoundLane)); - } - ExternalUses.push_back(ExternalUser(VL[i], Insrt, FoundLane)); +Value *BoUpSLP::gather(ArrayRef VL) { + Value *Val0 = + isa(VL[0]) ? cast(VL[0])->getValueOperand() : VL[0]; + FixedVectorType *VecTy = FixedVectorType::get(Val0->getType(), VL.size()); + Value *Vec = PoisonValue::get(VecTy); + unsigned InsIndex = 0; + for (Value *Val : VL) { + Vec = Builder.CreateInsertElement(Vec, Val, Builder.getInt32(InsIndex++)); + auto *InsElt = dyn_cast(Vec); + if (!InsElt) + continue; + GatherSeq.insert(InsElt); + CSEBlocks.insert(InsElt->getParent()); + // Add to our 'need-to-extract' list. + if (TreeEntry *Entry = getTreeEntry(Val)) { + // Find which lane we need to extract. + unsigned FoundLane = std::distance(Entry->Scalars.begin(), + find(Entry->Scalars, Val)); + assert(FoundLane < Entry->Scalars.size() && "Couldn't find extract lane"); + if (!Entry->ReuseShuffleIndices.empty()) { + FoundLane = std::distance(Entry->ReuseShuffleIndices.begin(), + find(Entry->ReuseShuffleIndices, FoundLane)); } + ExternalUses.push_back(ExternalUser(Val, InsElt, FoundLane)); } } @@ -4076,8 +4299,7 @@ Value *BoUpSLP::vectorizeTree(ArrayRef VL) { for (int Idx : E->ReuseShuffleIndices) if (UsedIdxs.insert(Idx).second) UniqueIdxs.emplace_back(Idx); - V = Builder.CreateShuffleVector(V, UndefValue::get(V->getType()), - UniqueIdxs); + V = Builder.CreateShuffleVector(V, UniqueIdxs); } } return V; @@ -4085,10 +4307,6 @@ Value *BoUpSLP::vectorizeTree(ArrayRef VL) { } } - Type *ScalarTy = S.OpValue->getType(); - if (StoreInst *SI = dyn_cast(S.OpValue)) - ScalarTy = SI->getValueOperand()->getType(); - // Check that every instruction appears once in this bundle. SmallVector ReuseShuffleIndicies; SmallVector UniqueValues; @@ -4108,27 +4326,16 @@ Value *BoUpSLP::vectorizeTree(ArrayRef VL) { else VL = UniqueValues; } - auto *VecTy = FixedVectorType::get(ScalarTy, VL.size()); - Value *V = Gather(VL, VecTy); + Value *Vec = gather(VL); if (!ReuseShuffleIndicies.empty()) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - ReuseShuffleIndicies, "shuffle"); - if (auto *I = dyn_cast(V)) { + Vec = Builder.CreateShuffleVector(Vec, ReuseShuffleIndicies, "shuffle"); + if (auto *I = dyn_cast(Vec)) { GatherSeq.insert(I); CSEBlocks.insert(I->getParent()); } } - return V; -} - -static void inversePermutation(ArrayRef Indices, - SmallVectorImpl &Mask) { - Mask.clear(); - const unsigned E = Indices.size(); - Mask.resize(E); - for (unsigned I = 0; I < E; ++I) - Mask[Indices[I]] = I; + return Vec; } Value *BoUpSLP::vectorizeTree(TreeEntry *E) { @@ -4139,32 +4346,31 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { return E->VectorizedValue; } - Instruction *VL0 = E->getMainOp(); - Type *ScalarTy = VL0->getType(); - if (StoreInst *SI = dyn_cast(VL0)) - ScalarTy = SI->getValueOperand()->getType(); - auto *VecTy = FixedVectorType::get(ScalarTy, E->Scalars.size()); - bool NeedToShuffleReuses = !E->ReuseShuffleIndices.empty(); - if (E->State == TreeEntry::NeedToGather) { setInsertPointAfterBundle(E); - auto *V = Gather(E->Scalars, VecTy); + Value *Vec = gather(E->Scalars); if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - if (auto *I = dyn_cast(V)) { + Vec = Builder.CreateShuffleVector(Vec, E->ReuseShuffleIndices, "shuffle"); + if (auto *I = dyn_cast(Vec)) { GatherSeq.insert(I); CSEBlocks.insert(I->getParent()); } } - E->VectorizedValue = V; - return V; + E->VectorizedValue = Vec; + return Vec; } - assert(E->State == TreeEntry::Vectorize && "Unhandled state"); + assert((E->State == TreeEntry::Vectorize || + E->State == TreeEntry::ScatterVectorize) && + "Unhandled state"); unsigned ShuffleOrOp = E->isAltShuffle() ? (unsigned)Instruction::ShuffleVector : E->getOpcode(); + Instruction *VL0 = E->getMainOp(); + Type *ScalarTy = VL0->getType(); + if (auto *Store = dyn_cast(VL0)) + ScalarTy = Store->getValueOperand()->getType(); + auto *VecTy = FixedVectorType::get(ScalarTy, E->Scalars.size()); switch (ShuffleOrOp) { case Instruction::PHI: { auto *PH = cast(VL0); @@ -4172,10 +4378,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { Builder.SetCurrentDebugLocation(PH->getDebugLoc()); PHINode *NewPhi = Builder.CreatePHI(VecTy, PH->getNumIncomingValues()); Value *V = NewPhi; - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; // PHINodes may have multiple entries from the same block. We want to @@ -4208,37 +4413,33 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { SmallVector Mask; inversePermutation(E->ReorderIndices, Mask); Builder.SetInsertPoint(VL0); - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), Mask, - "reorder_shuffle"); + V = Builder.CreateShuffleVector(V, Mask, "reorder_shuffle"); } if (NeedToShuffleReuses) { // TODO: Merge this shuffle with the ReorderShuffleMask. if (E->ReorderIndices.empty()) Builder.SetInsertPoint(VL0); - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); } E->VectorizedValue = V; return V; } case Instruction::ExtractValue: { - LoadInst *LI = cast(E->getSingleOperand(0)); + auto *LI = cast(E->getSingleOperand(0)); Builder.SetInsertPoint(LI); - PointerType *PtrTy = - PointerType::get(VecTy, LI->getPointerAddressSpace()); + auto *PtrTy = PointerType::get(VecTy, LI->getPointerAddressSpace()); Value *Ptr = Builder.CreateBitCast(LI->getOperand(0), PtrTy); LoadInst *V = Builder.CreateAlignedLoad(VecTy, Ptr, LI->getAlign()); Value *NewV = propagateMetadata(V, E->Scalars); if (!E->ReorderIndices.empty()) { SmallVector Mask; inversePermutation(E->ReorderIndices, Mask); - NewV = Builder.CreateShuffleVector(NewV, UndefValue::get(VecTy), Mask, - "reorder_shuffle"); + NewV = Builder.CreateShuffleVector(NewV, Mask, "reorder_shuffle"); } if (NeedToShuffleReuses) { // TODO: Merge this shuffle with the ReorderShuffleMask. - NewV = Builder.CreateShuffleVector(NewV, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); + NewV = Builder.CreateShuffleVector(NewV, E->ReuseShuffleIndices, + "shuffle"); } E->VectorizedValue = NewV; return NewV; @@ -4266,10 +4467,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { auto *CI = cast(VL0); Value *V = Builder.CreateCast(CI->getOpcode(), InVec, VecTy); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; return V; @@ -4289,10 +4489,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { CmpInst::Predicate P0 = cast(VL0)->getPredicate(); Value *V = Builder.CreateCmp(P0, L, R); propagateIRFlags(V, E->Scalars, VL0); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; return V; @@ -4310,10 +4509,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { } Value *V = Builder.CreateSelect(Cond, True, False); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; return V; @@ -4334,10 +4532,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { if (auto *I = dyn_cast(V)) V = propagateMetadata(I, E->Scalars); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; @@ -4378,10 +4575,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { if (auto *I = dyn_cast(V)) V = propagateMetadata(I, E->Scalars); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; @@ -4396,30 +4592,40 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { setInsertPointAfterBundle(E); LoadInst *LI = cast(VL0); + Instruction *NewLI; unsigned AS = LI->getPointerAddressSpace(); + Value *PO = LI->getPointerOperand(); + if (E->State == TreeEntry::Vectorize) { - Value *VecPtr = Builder.CreateBitCast(LI->getPointerOperand(), - VecTy->getPointerTo(AS)); + Value *VecPtr = Builder.CreateBitCast(PO, VecTy->getPointerTo(AS)); - // The pointer operand uses an in-tree scalar so we add the new BitCast to - // ExternalUses list to make sure that an extract will be generated in the - // future. - Value *PO = LI->getPointerOperand(); - if (getTreeEntry(PO)) - ExternalUses.push_back(ExternalUser(PO, cast(VecPtr), 0)); + // The pointer operand uses an in-tree scalar so we add the new BitCast + // to ExternalUses list to make sure that an extract will be generated + // in the future. + if (getTreeEntry(PO)) + ExternalUses.emplace_back(PO, cast(VecPtr), 0); + + NewLI = Builder.CreateAlignedLoad(VecTy, VecPtr, LI->getAlign()); + } else { + assert(E->State == TreeEntry::ScatterVectorize && "Unhandled state"); + Value *VecPtr = vectorizeTree(E->getOperand(0)); + // Use the minimum alignment of the gathered loads. + Align CommonAlignment = LI->getAlign(); + for (Value *V : E->Scalars) + CommonAlignment = + commonAlignment(CommonAlignment, cast(V)->getAlign()); + NewLI = Builder.CreateMaskedGather(VecPtr, CommonAlignment); + } + Value *V = propagateMetadata(NewLI, E->Scalars); - LI = Builder.CreateAlignedLoad(VecTy, VecPtr, LI->getAlign()); - Value *V = propagateMetadata(LI, E->Scalars); if (IsReorder) { SmallVector Mask; inversePermutation(E->ReorderIndices, Mask); - V = Builder.CreateShuffleVector(V, UndefValue::get(V->getType()), - Mask, "reorder_shuffle"); + V = Builder.CreateShuffleVector(V, Mask, "reorder_shuffle"); } if (NeedToShuffleReuses) { // TODO: Merge this shuffle with the ReorderShuffleMask. - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); } E->VectorizedValue = V; ++NumVectorInstructions; @@ -4437,9 +4643,7 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { if (IsReorder) { SmallVector Mask(E->ReorderIndices.begin(), E->ReorderIndices.end()); - VecValue = Builder.CreateShuffleVector( - VecValue, UndefValue::get(VecValue->getType()), Mask, - "reorder_shuffle"); + VecValue = Builder.CreateShuffleVector(VecValue, Mask, "reorder_shuf"); } Value *ScalarPtr = SI->getPointerOperand(); Value *VecPtr = Builder.CreateBitCast( @@ -4454,10 +4658,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { ExternalUses.push_back(ExternalUser(ScalarPtr, cast(VecPtr), 0)); Value *V = propagateMetadata(ST, E->Scalars); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; return V; @@ -4494,10 +4697,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { if (Instruction *I = dyn_cast(V)) V = propagateMetadata(I, E->Scalars); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; @@ -4537,9 +4739,10 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { Function *CF; if (!UseIntrinsic) { - VFShape Shape = VFShape::get( - *CI, {static_cast(VecTy->getNumElements()), false}, - false /*HasGlobalPred*/); + VFShape Shape = + VFShape::get(*CI, ElementCount::getFixed(static_cast( + VecTy->getNumElements())), + false /*HasGlobalPred*/); CF = VFDatabase(*CI).getVectorizedFunction(Shape); } else { Type *Tys[] = {FixedVectorType::get(CI->getType(), E->Scalars.size())}; @@ -4557,10 +4760,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { ExternalUses.push_back(ExternalUser(ScalarArg, cast(V), 0)); propagateIRFlags(V, E->Scalars, VL0); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; return V; @@ -4625,10 +4827,9 @@ Value *BoUpSLP::vectorizeTree(TreeEntry *E) { Value *V = Builder.CreateShuffleVector(V0, V1, Mask); if (Instruction *I = dyn_cast(V)) V = propagateMetadata(I, E->Scalars); - if (NeedToShuffleReuses) { - V = Builder.CreateShuffleVector(V, UndefValue::get(VecTy), - E->ReuseShuffleIndices, "shuffle"); - } + if (NeedToShuffleReuses) + V = Builder.CreateShuffleVector(V, E->ReuseShuffleIndices, "shuffle"); + E->VectorizedValue = V; ++NumVectorInstructions; @@ -4693,7 +4894,8 @@ BoUpSLP::vectorizeTree(ExtraValueToDebugLocsMap &ExternallyUsedValues) { continue; TreeEntry *E = getTreeEntry(Scalar); assert(E && "Invalid scalar"); - assert(E->State == TreeEntry::Vectorize && "Extracting from a gather list"); + assert(E->State != TreeEntry::NeedToGather && + "Extracting from a gather list"); Value *Vec = E->VectorizedValue; assert(Vec && "Can't find vectorizable value"); @@ -4851,7 +5053,8 @@ void BoUpSLP::optimizeGatherSequence() { // instructions into different buckets based on the insert lane. SmallVector Visited; for (auto I = CSEWorkList.begin(), E = CSEWorkList.end(); I != E; ++I) { - assert((I == CSEWorkList.begin() || !DT->dominates(*I, *std::prev(I))) && + assert(*I && + (I == CSEWorkList.begin() || !DT->dominates(*I, *std::prev(I))) && "Worklist not sorted properly!"); BasicBlock *BB = (*I)->getBlock(); // For all instructions in blocks containing gather sequences: @@ -4961,8 +5164,7 @@ BoUpSLP::BlockScheduling::tryScheduleBundle(ArrayRef VL, BoUpSLP *SLP, // cancelScheduling). while (!Bundle->isReady() && !ReadyInsts.empty()) { - ScheduleData *pickedSD = ReadyInsts.back(); - ReadyInsts.pop_back(); + ScheduleData *pickedSD = ReadyInsts.pop_back_val(); if (pickedSD->isSchedulingEntity() && pickedSD->isReady()) { schedule(pickedSD, ReadyInsts); @@ -5106,7 +5308,9 @@ void BoUpSLP::BlockScheduling::initScheduleData(Instruction *FromI, if (I->mayReadOrWriteMemory() && (!isa(I) || - cast(I)->getIntrinsicID() != Intrinsic::sideeffect)) { + (cast(I)->getIntrinsicID() != Intrinsic::sideeffect && + cast(I)->getIntrinsicID() != + Intrinsic::pseudoprobe))) { // Update the linked list of memory accessing instructions. if (CurrentLoadStore) { CurrentLoadStore->NextLoadStore = SD; @@ -5133,8 +5337,7 @@ void BoUpSLP::BlockScheduling::calculateDependencies(ScheduleData *SD, WorkList.push_back(SD); while (!WorkList.empty()) { - ScheduleData *SD = WorkList.back(); - WorkList.pop_back(); + ScheduleData *SD = WorkList.pop_back_val(); ScheduleData *BundleMember = SD; while (BundleMember) { @@ -5331,10 +5534,15 @@ void BoUpSLP::scheduleBlock(BlockScheduling *BS) { } unsigned BoUpSLP::getVectorElementSize(Value *V) { - // If V is a store, just return the width of the stored value without - // traversing the expression tree. This is the common case. - if (auto *Store = dyn_cast(V)) - return DL->getTypeSizeInBits(Store->getValueOperand()->getType()); + // If V is a store, just return the width of the stored value (or value + // truncated just before storing) without traversing the expression tree. + // This is the common case. + if (auto *Store = dyn_cast(V)) { + if (auto *Trunc = dyn_cast(Store->getValueOperand())) + return DL->getTypeSizeInBits(Trunc->getSrcTy()); + else + return DL->getTypeSizeInBits(Store->getValueOperand()->getType()); + } auto E = InstrElementSize.find(V); if (E != InstrElementSize.end()) @@ -5683,7 +5891,7 @@ PreservedAnalyses SLPVectorizerPass::run(Function &F, FunctionAnalysisManager &A bool SLPVectorizerPass::runImpl(Function &F, ScalarEvolution *SE_, TargetTransformInfo *TTI_, - TargetLibraryInfo *TLI_, AliasAnalysis *AA_, + TargetLibraryInfo *TLI_, AAResults *AA_, LoopInfo *LI_, DominatorTree *DT_, AssumptionCache *AC_, DemandedBits *DB_, OptimizationRemarkEmitter *ORE_) { @@ -5783,11 +5991,11 @@ bool SLPVectorizerPass::vectorizeStoreChain(ArrayRef Chain, BoUpSLP &R, R.computeMinimumValueSizes(); - int Cost = R.getTreeCost(); + InstructionCost Cost = R.getTreeCost(); - LLVM_DEBUG(dbgs() << "SLP: Found cost=" << Cost << " for VF=" << VF << "\n"); + LLVM_DEBUG(dbgs() << "SLP: Found cost = " << Cost << " for VF =" << VF << "\n"); if (Cost < -SLPCostThreshold) { - LLVM_DEBUG(dbgs() << "SLP: Decided to vectorize cost=" << Cost << "\n"); + LLVM_DEBUG(dbgs() << "SLP: Decided to vectorize cost = " << Cost << "\n"); using namespace ore; @@ -5860,7 +6068,7 @@ bool SLPVectorizerPass::vectorizeStores(ArrayRef Stores, // If a vector register can't hold 1 element, we are done. unsigned MaxVecRegSize = R.getMaxVecRegSize(); - unsigned EltSize = R.getVectorElementSize(Stores[0]); + unsigned EltSize = R.getVectorElementSize(Operands[0]); if (MaxVecRegSize % EltSize != 0) continue; @@ -5911,7 +6119,7 @@ void SLPVectorizerPass::collectSeedInstructions(BasicBlock *BB) { continue; if (!isValidElementType(SI->getValueOperand()->getType())) continue; - Stores[GetUnderlyingObject(SI->getPointerOperand(), *DL)].push_back(SI); + Stores[getUnderlyingObject(SI->getPointerOperand())].push_back(SI); } // Ignore getelementptr instructions that have more than one index, a @@ -5975,6 +6183,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef VL, BoUpSLP &R, unsigned Sz = R.getVectorElementSize(I0); unsigned MinVF = std::max(2U, R.getMinVecRegSize() / Sz); unsigned MaxVF = std::max(PowerOf2Floor(VL.size()), MinVF); + MaxVF = std::min(R.getMaximumVF(Sz, S.getOpcode()), MaxVF); if (MaxVF < 2) { R.getORE()->emit([&]() { return OptimizationRemarkMissed(SV_NAME, "SmallVF", I0) @@ -5986,7 +6195,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef VL, BoUpSLP &R, bool Changed = false; bool CandidateFound = false; - int MinCost = SLPCostThreshold; + InstructionCost MinCost = SLPCostThreshold.getValue(); bool CompensateUseCost = !InsertUses.empty() && llvm::all_of(InsertUses, [](const Value *V) { @@ -6042,7 +6251,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef VL, BoUpSLP &R, continue; R.computeMinimumValueSizes(); - int Cost = R.getTreeCost(); + InstructionCost Cost = R.getTreeCost(); CandidateFound = true; if (CompensateUseCost) { // TODO: Use TTI's getScalarizationOverhead for sequence of inserts @@ -6052,7 +6261,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef VL, BoUpSLP &R, // part should also switch to same interface. // For example, the following case is projected code after SLP: // %4 = extractelement <4 x i64> %3, i32 0 - // %v0 = insertelement <4 x i64> undef, i64 %4, i32 0 + // %v0 = insertelement <4 x i64> poison, i64 %4, i32 0 // %5 = extractelement <4 x i64> %3, i32 1 // %v1 = insertelement <4 x i64> %v0, i64 %5, i32 1 // %6 = extractelement <4 x i64> %3, i32 2 @@ -6072,7 +6281,7 @@ bool SLPVectorizerPass::tryToVectorizeList(ArrayRef VL, BoUpSLP &R, // Switching to the TTI interface might help a bit. // Alternative solution could be pattern-match to detect a no-op or // shuffle. - unsigned UserCost = 0; + InstructionCost UserCost = 0; for (unsigned Lane = 0; Lane < OpsWidth; Lane++) { auto *IE = cast(InsertUses[I + Lane]); if (auto *CI = dyn_cast(IE->getOperand(2))) @@ -6163,50 +6372,20 @@ bool SLPVectorizerPass::tryToVectorize(Instruction *I, BoUpSLP &R) { return false; } -/// Generate a shuffle mask to be used in a reduction tree. -/// -/// \param VecLen The length of the vector to be reduced. -/// \param NumEltsToRdx The number of elements that should be reduced in the -/// vector. -/// \param IsPairwise Whether the reduction is a pairwise or splitting -/// reduction. A pairwise reduction will generate a mask of -/// <0,2,...> or <1,3,..> while a splitting reduction will generate -/// <2,3, undef,undef> for a vector of 4 and NumElts = 2. -/// \param IsLeft True will generate a mask of even elements, odd otherwise. -static SmallVector createRdxShuffleMask(unsigned VecLen, - unsigned NumEltsToRdx, - bool IsPairwise, bool IsLeft) { - assert((IsPairwise || !IsLeft) && "Don't support a <0,1,undef,...> mask"); - - SmallVector ShuffleMask(VecLen, -1); - - if (IsPairwise) - // Build a mask of 0, 2, ... (left) or 1, 3, ... (right). - for (unsigned i = 0; i != NumEltsToRdx; ++i) - ShuffleMask[i] = 2 * i + !IsLeft; - else - // Move the upper half of the vector to the lower half. - for (unsigned i = 0; i != NumEltsToRdx; ++i) - ShuffleMask[i] = NumEltsToRdx + i; - - return ShuffleMask; -} - namespace { /// Model horizontal reductions. /// -/// A horizontal reduction is a tree of reduction operations (currently add and -/// fadd) that has operations that can be put into a vector as its leaf. -/// For example, this tree: +/// A horizontal reduction is a tree of reduction instructions that has values +/// that can be put into a vector as its leaves. For example: /// /// mul mul mul mul /// \ / \ / /// + + /// \ / /// + -/// This tree has "mul" as its reduced values and "+" as its reduction -/// operations. A reduction might be feeding into a store or a binary operation +/// This tree has "mul" as its leaf values and "+" as its reduction +/// instructions. A reduction can feed into a store or a binary operation /// feeding a phi. /// ... /// \ / @@ -6224,333 +6403,30 @@ namespace { class HorizontalReduction { using ReductionOpsType = SmallVector; using ReductionOpsListType = SmallVector; - ReductionOpsListType ReductionOps; + ReductionOpsListType ReductionOps; SmallVector ReducedVals; // Use map vector to make stable output. MapVector ExtraArgs; - - /// Kind of the reduction data. - enum ReductionKind { - RK_None, /// Not a reduction. - RK_Arithmetic, /// Binary reduction data. - RK_Min, /// Minimum reduction data. - RK_UMin, /// Unsigned minimum reduction data. - RK_Max, /// Maximum reduction data. - RK_UMax, /// Unsigned maximum reduction data. - }; - - /// Contains info about operation, like its opcode, left and right operands. - class OperationData { - /// Opcode of the instruction. - unsigned Opcode = 0; - - /// Left operand of the reduction operation. - Value *LHS = nullptr; - - /// Right operand of the reduction operation. - Value *RHS = nullptr; - - /// Kind of the reduction operation. - ReductionKind Kind = RK_None; - - /// True if float point min/max reduction has no NaNs. - bool NoNaN = false; - - /// Checks if the reduction operation can be vectorized. - bool isVectorizable() const { - return LHS && RHS && - // We currently only support add/mul/logical && min/max reductions. - ((Kind == RK_Arithmetic && - (Opcode == Instruction::Add || Opcode == Instruction::FAdd || - Opcode == Instruction::Mul || Opcode == Instruction::FMul || - Opcode == Instruction::And || Opcode == Instruction::Or || - Opcode == Instruction::Xor)) || - ((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) && - (Kind == RK_Min || Kind == RK_Max)) || - (Opcode == Instruction::ICmp && - (Kind == RK_UMin || Kind == RK_UMax))); - } - - /// Creates reduction operation with the current opcode. - Value *createOp(IRBuilder<> &Builder, const Twine &Name) const { - assert(isVectorizable() && - "Expected add|fadd or min/max reduction operation."); - Value *Cmp = nullptr; - switch (Kind) { - case RK_Arithmetic: - return Builder.CreateBinOp((Instruction::BinaryOps)Opcode, LHS, RHS, - Name); - case RK_Min: - Cmp = Opcode == Instruction::ICmp ? Builder.CreateICmpSLT(LHS, RHS) - : Builder.CreateFCmpOLT(LHS, RHS); - return Builder.CreateSelect(Cmp, LHS, RHS, Name); - case RK_Max: - Cmp = Opcode == Instruction::ICmp ? Builder.CreateICmpSGT(LHS, RHS) - : Builder.CreateFCmpOGT(LHS, RHS); - return Builder.CreateSelect(Cmp, LHS, RHS, Name); - case RK_UMin: - assert(Opcode == Instruction::ICmp && "Expected integer types."); - Cmp = Builder.CreateICmpULT(LHS, RHS); - return Builder.CreateSelect(Cmp, LHS, RHS, Name); - case RK_UMax: - assert(Opcode == Instruction::ICmp && "Expected integer types."); - Cmp = Builder.CreateICmpUGT(LHS, RHS); - return Builder.CreateSelect(Cmp, LHS, RHS, Name); - case RK_None: - break; - } - llvm_unreachable("Unknown reduction operation."); - } - - public: - explicit OperationData() = default; - - /// Construction for reduced values. They are identified by opcode only and - /// don't have associated LHS/RHS values. - explicit OperationData(Value *V) { - if (auto *I = dyn_cast(V)) - Opcode = I->getOpcode(); - } - - /// Constructor for reduction operations with opcode and its left and - /// right operands. - OperationData(unsigned Opcode, Value *LHS, Value *RHS, ReductionKind Kind, - bool NoNaN = false) - : Opcode(Opcode), LHS(LHS), RHS(RHS), Kind(Kind), NoNaN(NoNaN) { - assert(Kind != RK_None && "One of the reduction operations is expected."); - } - - explicit operator bool() const { return Opcode; } - - /// Return true if this operation is any kind of minimum or maximum. - bool isMinMax() const { - switch (Kind) { - case RK_Arithmetic: - return false; - case RK_Min: - case RK_Max: - case RK_UMin: - case RK_UMax: - return true; - case RK_None: - break; - } - llvm_unreachable("Reduction kind is not set"); - } - - /// Get the index of the first operand. - unsigned getFirstOperandIndex() const { - assert(!!*this && "The opcode is not set."); - // We allow calling this before 'Kind' is set, so handle that specially. - if (Kind == RK_None) - return 0; - return isMinMax() ? 1 : 0; - } - - /// Total number of operands in the reduction operation. - unsigned getNumberOfOperands() const { - assert(Kind != RK_None && !!*this && LHS && RHS && - "Expected reduction operation."); - return isMinMax() ? 3 : 2; - } - - /// Checks if the operation has the same parent as \p P. - bool hasSameParent(Instruction *I, Value *P, bool IsRedOp) const { - assert(Kind != RK_None && !!*this && LHS && RHS && - "Expected reduction operation."); - if (!IsRedOp) - return I->getParent() == P; - if (isMinMax()) { - // SelectInst must be used twice while the condition op must have single - // use only. - auto *Cmp = cast(cast(I)->getCondition()); - return I->getParent() == P && Cmp && Cmp->getParent() == P; - } - // Arithmetic reduction operation must be used once only. - return I->getParent() == P; - } - - /// Expected number of uses for reduction operations/reduced values. - bool hasRequiredNumberOfUses(Instruction *I, bool IsReductionOp) const { - assert(Kind != RK_None && !!*this && LHS && RHS && - "Expected reduction operation."); - if (isMinMax()) - return I->hasNUses(2) && - (!IsReductionOp || - cast(I)->getCondition()->hasOneUse()); - return I->hasOneUse(); - } - - /// Initializes the list of reduction operations. - void initReductionOps(ReductionOpsListType &ReductionOps) { - assert(Kind != RK_None && !!*this && LHS && RHS && - "Expected reduction operation."); - if (isMinMax()) - ReductionOps.assign(2, ReductionOpsType()); - else - ReductionOps.assign(1, ReductionOpsType()); - } - - /// Add all reduction operations for the reduction instruction \p I. - void addReductionOps(Instruction *I, ReductionOpsListType &ReductionOps) { - assert(Kind != RK_None && !!*this && LHS && RHS && - "Expected reduction operation."); - if (isMinMax()) { - ReductionOps[0].emplace_back(cast(I)->getCondition()); - ReductionOps[1].emplace_back(I); - } else { - ReductionOps[0].emplace_back(I); - } - } - - /// Checks if instruction is associative and can be vectorized. - bool isAssociative(Instruction *I) const { - assert(Kind != RK_None && *this && LHS && RHS && - "Expected reduction operation."); - switch (Kind) { - case RK_Arithmetic: - return I->isAssociative(); - case RK_Min: - case RK_Max: - return Opcode == Instruction::ICmp || - cast(I->getOperand(0))->isFast(); - case RK_UMin: - case RK_UMax: - assert(Opcode == Instruction::ICmp && - "Only integer compare operation is expected."); - return true; - case RK_None: - break; - } - llvm_unreachable("Reduction kind is not set"); - } - - /// Checks if the reduction operation can be vectorized. - bool isVectorizable(Instruction *I) const { - return isVectorizable() && isAssociative(I); - } - - /// Checks if two operation data are both a reduction op or both a reduced - /// value. - bool operator==(const OperationData &OD) const { - assert(((Kind != OD.Kind) || ((!LHS == !OD.LHS) && (!RHS == !OD.RHS))) && - "One of the comparing operations is incorrect."); - return this == &OD || (Kind == OD.Kind && Opcode == OD.Opcode); - } - bool operator!=(const OperationData &OD) const { return !(*this == OD); } - void clear() { - Opcode = 0; - LHS = nullptr; - RHS = nullptr; - Kind = RK_None; - NoNaN = false; - } - - /// Get the opcode of the reduction operation. - unsigned getOpcode() const { - assert(isVectorizable() && "Expected vectorizable operation."); - return Opcode; - } - - /// Get kind of reduction data. - ReductionKind getKind() const { return Kind; } - Value *getLHS() const { return LHS; } - Value *getRHS() const { return RHS; } - Type *getConditionType() const { - return isMinMax() ? CmpInst::makeCmpResultType(LHS->getType()) : nullptr; - } - - /// Creates reduction operation with the current opcode with the IR flags - /// from \p ReductionOps. - Value *createOp(IRBuilder<> &Builder, const Twine &Name, - const ReductionOpsListType &ReductionOps) const { - assert(isVectorizable() && - "Expected add|fadd or min/max reduction operation."); - auto *Op = createOp(Builder, Name); - switch (Kind) { - case RK_Arithmetic: - propagateIRFlags(Op, ReductionOps[0]); - return Op; - case RK_Min: - case RK_Max: - case RK_UMin: - case RK_UMax: - if (auto *SI = dyn_cast(Op)) - propagateIRFlags(SI->getCondition(), ReductionOps[0]); - propagateIRFlags(Op, ReductionOps[1]); - return Op; - case RK_None: - break; - } - llvm_unreachable("Unknown reduction operation."); - } - /// Creates reduction operation with the current opcode with the IR flags - /// from \p I. - Value *createOp(IRBuilder<> &Builder, const Twine &Name, - Instruction *I) const { - assert(isVectorizable() && - "Expected add|fadd or min/max reduction operation."); - auto *Op = createOp(Builder, Name); - switch (Kind) { - case RK_Arithmetic: - propagateIRFlags(Op, I); - return Op; - case RK_Min: - case RK_Max: - case RK_UMin: - case RK_UMax: - if (auto *SI = dyn_cast(Op)) { - propagateIRFlags(SI->getCondition(), - cast(I)->getCondition()); - } - propagateIRFlags(Op, I); - return Op; - case RK_None: - break; - } - llvm_unreachable("Unknown reduction operation."); - } - - TargetTransformInfo::ReductionFlags getFlags() const { - TargetTransformInfo::ReductionFlags Flags; - Flags.NoNaN = NoNaN; - switch (Kind) { - case RK_Arithmetic: - break; - case RK_Min: - Flags.IsSigned = Opcode == Instruction::ICmp; - Flags.IsMaxOp = false; - break; - case RK_Max: - Flags.IsSigned = Opcode == Instruction::ICmp; - Flags.IsMaxOp = true; - break; - case RK_UMin: - Flags.IsSigned = false; - Flags.IsMaxOp = false; - break; - case RK_UMax: - Flags.IsSigned = false; - Flags.IsMaxOp = true; - break; - case RK_None: - llvm_unreachable("Reduction kind is not set"); - } - return Flags; - } - }; - WeakTrackingVH ReductionRoot; + /// The type of reduction operation. + RecurKind RdxKind; - /// The operation data of the reduction operation. - OperationData ReductionData; + /// Checks if instruction is associative and can be vectorized. + static bool isVectorizable(RecurKind Kind, Instruction *I) { + if (Kind == RecurKind::None) + return false; + if (RecurrenceDescriptor::isIntMinMaxRecurrenceKind(Kind)) + return true; - /// The operation data of the values we perform a reduction on. - OperationData ReducedValueData; + if (Kind == RecurKind::FMax || Kind == RecurKind::FMin) { + // FP min/max are associative except for NaN and -0.0. We do not + // have to rule out -0.0 here because the intrinsic semantics do not + // specify a fixed result for it. + return I->getFastMathFlags().noNaNs(); + } - /// Should we model this reduction as a pairwise reduction tree or a tree that - /// splits the vector in halves and adds those halves. - bool IsPairwiseReduction = false; + return I->isAssociative(); + } /// Checks if the ParentStackElem.first should be marked as a reduction /// operation with an extra argument or as extra argument itself. @@ -6564,7 +6440,8 @@ class HorizontalReduction { // in this case. // Do not perform analysis of remaining operands of ParentStackElem.first // instruction, this whole instruction is an extra argument. - ParentStackElem.second = ParentStackElem.first->getNumOperands(); + RecurKind ParentRdxKind = getRdxKind(ParentStackElem.first); + ParentStackElem.second = getNumberOfOperands(ParentRdxKind); } else { // We ran into something like: // ParentStackElem.first += ... + ExtraArg + ... @@ -6572,110 +6449,238 @@ class HorizontalReduction { } } - static OperationData getOperationData(Value *V) { - if (!V) - return OperationData(); - - Value *LHS; - Value *RHS; - if (m_BinOp(m_Value(LHS), m_Value(RHS)).match(V)) { - return OperationData(cast(V)->getOpcode(), LHS, RHS, - RK_Arithmetic); - } - if (auto *Select = dyn_cast(V)) { - // Look for a min/max pattern. - if (m_UMin(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData(Instruction::ICmp, LHS, RHS, RK_UMin); - } else if (m_SMin(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData(Instruction::ICmp, LHS, RHS, RK_Min); - } else if (m_OrdFMin(m_Value(LHS), m_Value(RHS)).match(Select) || - m_UnordFMin(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData( - Instruction::FCmp, LHS, RHS, RK_Min, - cast(Select->getCondition())->hasNoNaNs()); - } else if (m_UMax(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData(Instruction::ICmp, LHS, RHS, RK_UMax); - } else if (m_SMax(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData(Instruction::ICmp, LHS, RHS, RK_Max); - } else if (m_OrdFMax(m_Value(LHS), m_Value(RHS)).match(Select) || - m_UnordFMax(m_Value(LHS), m_Value(RHS)).match(Select)) { - return OperationData( - Instruction::FCmp, LHS, RHS, RK_Max, - cast(Select->getCondition())->hasNoNaNs()); - } else { - // Try harder: look for min/max pattern based on instructions producing - // same values such as: select ((cmp Inst1, Inst2), Inst1, Inst2). - // During the intermediate stages of SLP, it's very common to have - // pattern like this (since optimizeGatherSequence is run only once - // at the end): - // %1 = extractelement <2 x i32> %a, i32 0 - // %2 = extractelement <2 x i32> %a, i32 1 - // %cond = icmp sgt i32 %1, %2 - // %3 = extractelement <2 x i32> %a, i32 0 - // %4 = extractelement <2 x i32> %a, i32 1 - // %select = select i1 %cond, i32 %3, i32 %4 - CmpInst::Predicate Pred; - Instruction *L1; - Instruction *L2; - - LHS = Select->getTrueValue(); - RHS = Select->getFalseValue(); - Value *Cond = Select->getCondition(); - - // TODO: Support inverse predicates. - if (match(Cond, m_Cmp(Pred, m_Specific(LHS), m_Instruction(L2)))) { - if (!isa(RHS) || - !L2->isIdenticalTo(cast(RHS))) - return OperationData(V); - } else if (match(Cond, m_Cmp(Pred, m_Instruction(L1), m_Specific(RHS)))) { - if (!isa(LHS) || - !L1->isIdenticalTo(cast(LHS))) - return OperationData(V); - } else { - if (!isa(LHS) || !isa(RHS)) - return OperationData(V); - if (!match(Cond, m_Cmp(Pred, m_Instruction(L1), m_Instruction(L2))) || - !L1->isIdenticalTo(cast(LHS)) || - !L2->isIdenticalTo(cast(RHS))) - return OperationData(V); - } - switch (Pred) { - default: - return OperationData(V); - - case CmpInst::ICMP_ULT: - case CmpInst::ICMP_ULE: - return OperationData(Instruction::ICmp, LHS, RHS, RK_UMin); - - case CmpInst::ICMP_SLT: - case CmpInst::ICMP_SLE: - return OperationData(Instruction::ICmp, LHS, RHS, RK_Min); - - case CmpInst::FCMP_OLT: - case CmpInst::FCMP_OLE: - case CmpInst::FCMP_ULT: - case CmpInst::FCMP_ULE: - return OperationData(Instruction::FCmp, LHS, RHS, RK_Min, - cast(Cond)->hasNoNaNs()); - - case CmpInst::ICMP_UGT: - case CmpInst::ICMP_UGE: - return OperationData(Instruction::ICmp, LHS, RHS, RK_UMax); - - case CmpInst::ICMP_SGT: - case CmpInst::ICMP_SGE: - return OperationData(Instruction::ICmp, LHS, RHS, RK_Max); - - case CmpInst::FCMP_OGT: - case CmpInst::FCMP_OGE: - case CmpInst::FCMP_UGT: - case CmpInst::FCMP_UGE: - return OperationData(Instruction::FCmp, LHS, RHS, RK_Max, - cast(Cond)->hasNoNaNs()); - } + /// Creates reduction operation with the current opcode. + static Value *createOp(IRBuilder<> &Builder, RecurKind Kind, Value *LHS, + Value *RHS, const Twine &Name) { + unsigned RdxOpcode = RecurrenceDescriptor::getOpcode(Kind); + switch (Kind) { + case RecurKind::Add: + case RecurKind::Mul: + case RecurKind::Or: + case RecurKind::And: + case RecurKind::Xor: + case RecurKind::FAdd: + case RecurKind::FMul: + return Builder.CreateBinOp((Instruction::BinaryOps)RdxOpcode, LHS, RHS, + Name); + case RecurKind::FMax: + return Builder.CreateBinaryIntrinsic(Intrinsic::maxnum, LHS, RHS); + case RecurKind::FMin: + return Builder.CreateBinaryIntrinsic(Intrinsic::minnum, LHS, RHS); + + case RecurKind::SMax: { + Value *Cmp = Builder.CreateICmpSGT(LHS, RHS, Name); + return Builder.CreateSelect(Cmp, LHS, RHS, Name); + } + case RecurKind::SMin: { + Value *Cmp = Builder.CreateICmpSLT(LHS, RHS, Name); + return Builder.CreateSelect(Cmp, LHS, RHS, Name); + } + case RecurKind::UMax: { + Value *Cmp = Builder.CreateICmpUGT(LHS, RHS, Name); + return Builder.CreateSelect(Cmp, LHS, RHS, Name); + } + case RecurKind::UMin: { + Value *Cmp = Builder.CreateICmpULT(LHS, RHS, Name); + return Builder.CreateSelect(Cmp, LHS, RHS, Name); + } + default: + llvm_unreachable("Unknown reduction operation."); + } + } + + /// Creates reduction operation with the current opcode with the IR flags + /// from \p ReductionOps. + static Value *createOp(IRBuilder<> &Builder, RecurKind RdxKind, Value *LHS, + Value *RHS, const Twine &Name, + const ReductionOpsListType &ReductionOps) { + Value *Op = createOp(Builder, RdxKind, LHS, RHS, Name); + if (RecurrenceDescriptor::isIntMinMaxRecurrenceKind(RdxKind)) { + if (auto *Sel = dyn_cast(Op)) + propagateIRFlags(Sel->getCondition(), ReductionOps[0]); + propagateIRFlags(Op, ReductionOps[1]); + return Op; + } + propagateIRFlags(Op, ReductionOps[0]); + return Op; + } + /// Creates reduction operation with the current opcode with the IR flags + /// from \p I. + static Value *createOp(IRBuilder<> &Builder, RecurKind RdxKind, Value *LHS, + Value *RHS, const Twine &Name, Instruction *I) { + Value *Op = createOp(Builder, RdxKind, LHS, RHS, Name); + if (RecurrenceDescriptor::isIntMinMaxRecurrenceKind(RdxKind)) { + if (auto *Sel = dyn_cast(Op)) { + propagateIRFlags(Sel->getCondition(), + cast(I)->getCondition()); } } - return OperationData(V); + propagateIRFlags(Op, I); + return Op; + } + + static RecurKind getRdxKind(Instruction *I) { + assert(I && "Expected instruction for reduction matching"); + TargetTransformInfo::ReductionFlags RdxFlags; + if (match(I, m_Add(m_Value(), m_Value()))) + return RecurKind::Add; + if (match(I, m_Mul(m_Value(), m_Value()))) + return RecurKind::Mul; + if (match(I, m_And(m_Value(), m_Value()))) + return RecurKind::And; + if (match(I, m_Or(m_Value(), m_Value()))) + return RecurKind::Or; + if (match(I, m_Xor(m_Value(), m_Value()))) + return RecurKind::Xor; + if (match(I, m_FAdd(m_Value(), m_Value()))) + return RecurKind::FAdd; + if (match(I, m_FMul(m_Value(), m_Value()))) + return RecurKind::FMul; + + if (match(I, m_Intrinsic(m_Value(), m_Value()))) + return RecurKind::FMax; + if (match(I, m_Intrinsic(m_Value(), m_Value()))) + return RecurKind::FMin; + + if (match(I, m_SMax(m_Value(), m_Value()))) + return RecurKind::SMax; + if (match(I, m_SMin(m_Value(), m_Value()))) + return RecurKind::SMin; + if (match(I, m_UMax(m_Value(), m_Value()))) + return RecurKind::UMax; + if (match(I, m_UMin(m_Value(), m_Value()))) + return RecurKind::UMin; + + if (auto *Select = dyn_cast(I)) { + // Try harder: look for min/max pattern based on instructions producing + // same values such as: select ((cmp Inst1, Inst2), Inst1, Inst2). + // During the intermediate stages of SLP, it's very common to have + // pattern like this (since optimizeGatherSequence is run only once + // at the end): + // %1 = extractelement <2 x i32> %a, i32 0 + // %2 = extractelement <2 x i32> %a, i32 1 + // %cond = icmp sgt i32 %1, %2 + // %3 = extractelement <2 x i32> %a, i32 0 + // %4 = extractelement <2 x i32> %a, i32 1 + // %select = select i1 %cond, i32 %3, i32 %4 + CmpInst::Predicate Pred; + Instruction *L1; + Instruction *L2; + + Value *LHS = Select->getTrueValue(); + Value *RHS = Select->getFalseValue(); + Value *Cond = Select->getCondition(); + + // TODO: Support inverse predicates. + if (match(Cond, m_Cmp(Pred, m_Specific(LHS), m_Instruction(L2)))) { + if (!isa(RHS) || + !L2->isIdenticalTo(cast(RHS))) + return RecurKind::None; + } else if (match(Cond, m_Cmp(Pred, m_Instruction(L1), m_Specific(RHS)))) { + if (!isa(LHS) || + !L1->isIdenticalTo(cast(LHS))) + return RecurKind::None; + } else { + if (!isa(LHS) || !isa(RHS)) + return RecurKind::None; + if (!match(Cond, m_Cmp(Pred, m_Instruction(L1), m_Instruction(L2))) || + !L1->isIdenticalTo(cast(LHS)) || + !L2->isIdenticalTo(cast(RHS))) + return RecurKind::None; + } + + TargetTransformInfo::ReductionFlags RdxFlags; + switch (Pred) { + default: + return RecurKind::None; + case CmpInst::ICMP_SGT: + case CmpInst::ICMP_SGE: + return RecurKind::SMax; + case CmpInst::ICMP_SLT: + case CmpInst::ICMP_SLE: + return RecurKind::SMin; + case CmpInst::ICMP_UGT: + case CmpInst::ICMP_UGE: + return RecurKind::UMax; + case CmpInst::ICMP_ULT: + case CmpInst::ICMP_ULE: + return RecurKind::UMin; + } + } + return RecurKind::None; + } + + /// Return true if this operation is a cmp+select idiom. + static bool isCmpSel(RecurKind Kind) { + return RecurrenceDescriptor::isIntMinMaxRecurrenceKind(Kind); + } + + /// Get the index of the first operand. + static unsigned getFirstOperandIndex(RecurKind Kind) { + // We allow calling this before 'Kind' is set, so handle that specially. + if (Kind == RecurKind::None) + return 0; + return isCmpSel(Kind) ? 1 : 0; + } + + /// Total number of operands in the reduction operation. + static unsigned getNumberOfOperands(RecurKind Kind) { + return isCmpSel(Kind) ? 3 : 2; + } + + /// Checks if the instruction is in basic block \p BB. + /// For a min/max reduction check that both compare and select are in \p BB. + static bool hasSameParent(RecurKind Kind, Instruction *I, BasicBlock *BB, + bool IsRedOp) { + if (IsRedOp && isCmpSel(Kind)) { + auto *Cmp = cast(cast(I)->getCondition()); + return I->getParent() == BB && Cmp && Cmp->getParent() == BB; + } + return I->getParent() == BB; + } + + /// Expected number of uses for reduction operations/reduced values. + static bool hasRequiredNumberOfUses(RecurKind Kind, Instruction *I, + bool IsReductionOp) { + // SelectInst must be used twice while the condition op must have single + // use only. + if (isCmpSel(Kind)) + return I->hasNUses(2) && + (!IsReductionOp || + cast(I)->getCondition()->hasOneUse()); + + // Arithmetic reduction operation must be used once only. + return I->hasOneUse(); + } + + /// Initializes the list of reduction operations. + void initReductionOps(RecurKind Kind) { + if (isCmpSel(Kind)) + ReductionOps.assign(2, ReductionOpsType()); + else + ReductionOps.assign(1, ReductionOpsType()); + } + + /// Add all reduction operations for the reduction instruction \p I. + void addReductionOps(RecurKind Kind, Instruction *I) { + assert(Kind != RecurKind::None && "Expected reduction operation."); + if (isCmpSel(Kind)) { + ReductionOps[0].emplace_back(cast(I)->getCondition()); + ReductionOps[1].emplace_back(I); + } else { + ReductionOps[0].emplace_back(I); + } + } + + static Value *getLHS(RecurKind Kind, Instruction *I) { + if (Kind == RecurKind::None) + return nullptr; + return I->getOperand(getFirstOperandIndex(Kind)); + } + static Value *getRHS(RecurKind Kind, Instruction *I) { + if (Kind == RecurKind::None) + return nullptr; + return I->getOperand(getFirstOperandIndex(Kind) + 1); } public: @@ -6684,50 +6689,59 @@ public: /// Try to find a reduction tree. bool matchAssociativeReduction(PHINode *Phi, Instruction *B) { assert((!Phi || is_contained(Phi->operands(), B)) && - "Thi phi needs to use the binary operator"); + "Phi needs to use the binary operator"); - ReductionData = getOperationData(B); + RdxKind = getRdxKind(B); // We could have a initial reductions that is not an add. // r *= v1 + v2 + v3 + v4 // In such a case start looking for a tree rooted in the first '+'. if (Phi) { - if (ReductionData.getLHS() == Phi) { + if (getLHS(RdxKind, B) == Phi) { Phi = nullptr; - B = dyn_cast(ReductionData.getRHS()); - ReductionData = getOperationData(B); - } else if (ReductionData.getRHS() == Phi) { + B = dyn_cast(getRHS(RdxKind, B)); + if (!B) + return false; + RdxKind = getRdxKind(B); + } else if (getRHS(RdxKind, B) == Phi) { Phi = nullptr; - B = dyn_cast(ReductionData.getLHS()); - ReductionData = getOperationData(B); + B = dyn_cast(getLHS(RdxKind, B)); + if (!B) + return false; + RdxKind = getRdxKind(B); } } - if (!ReductionData.isVectorizable(B)) + if (!isVectorizable(RdxKind, B)) return false; + // Analyze "regular" integer/FP types for reductions - no target-specific + // types or pointers. Type *Ty = B->getType(); - if (!isValidElementType(Ty)) - return false; - if (!Ty->isIntOrIntVectorTy() && !Ty->isFPOrFPVectorTy()) + if (!isValidElementType(Ty) || Ty->isPointerTy()) return false; - ReducedValueData.clear(); ReductionRoot = B; + // The opcode for leaf values that we perform a reduction on. + // For example: load(x) + load(y) + load(z) + fptoui(w) + // The leaf opcode for 'w' does not match, so we don't include it as a + // potential candidate for the reduction. + unsigned LeafOpcode = 0; + // Post order traverse the reduction tree starting at B. We only handle true // trees containing only binary operators. SmallVector, 32> Stack; - Stack.push_back(std::make_pair(B, ReductionData.getFirstOperandIndex())); - ReductionData.initReductionOps(ReductionOps); + Stack.push_back(std::make_pair(B, getFirstOperandIndex(RdxKind))); + initReductionOps(RdxKind); while (!Stack.empty()) { Instruction *TreeN = Stack.back().first; - unsigned EdgeToVist = Stack.back().second++; - OperationData OpData = getOperationData(TreeN); - bool IsReducedValue = OpData != ReductionData; + unsigned EdgeToVisit = Stack.back().second++; + const RecurKind TreeRdxKind = getRdxKind(TreeN); + bool IsReducedValue = TreeRdxKind != RdxKind; - // Postorder vist. - if (IsReducedValue || EdgeToVist == OpData.getNumberOfOperands()) { + // Postorder visit. + if (IsReducedValue || EdgeToVisit == getNumberOfOperands(TreeRdxKind)) { if (IsReducedValue) ReducedVals.push_back(TreeN); else { @@ -6745,7 +6759,7 @@ public: markExtraArg(Stack[Stack.size() - 2], TreeN); ExtraArgs.erase(TreeN); } else - ReductionData.addReductionOps(TreeN, ReductionOps); + addReductionOps(RdxKind, TreeN); } // Retract. Stack.pop_back(); @@ -6753,91 +6767,72 @@ public: } // Visit left or right. - Value *NextV = TreeN->getOperand(EdgeToVist); - if (NextV != Phi) { - auto *I = dyn_cast(NextV); - OpData = getOperationData(I); - // Continue analysis if the next operand is a reduction operation or - // (possibly) a reduced value. If the reduced value opcode is not set, - // the first met operation != reduction operation is considered as the - // reduced value class. - if (I && (!ReducedValueData || OpData == ReducedValueData || - OpData == ReductionData)) { - const bool IsReductionOperation = OpData == ReductionData; - // Only handle trees in the current basic block. - if (!ReductionData.hasSameParent(I, B->getParent(), - IsReductionOperation)) { - // I is an extra argument for TreeN (its parent operation). - markExtraArg(Stack.back(), I); - continue; - } - - // Each tree node needs to have minimal number of users except for the - // ultimate reduction. - if (!ReductionData.hasRequiredNumberOfUses(I, - OpData == ReductionData) && - I != B) { + Value *EdgeVal = TreeN->getOperand(EdgeToVisit); + auto *I = dyn_cast(EdgeVal); + if (!I) { + // Edge value is not a reduction instruction or a leaf instruction. + // (It may be a constant, function argument, or something else.) + markExtraArg(Stack.back(), EdgeVal); + continue; + } + RecurKind EdgeRdxKind = getRdxKind(I); + // Continue analysis if the next operand is a reduction operation or + // (possibly) a leaf value. If the leaf value opcode is not set, + // the first met operation != reduction operation is considered as the + // leaf opcode. + // Only handle trees in the current basic block. + // Each tree node needs to have minimal number of users except for the + // ultimate reduction. + const bool IsRdxInst = EdgeRdxKind == RdxKind; + if (I != Phi && I != B && + hasSameParent(RdxKind, I, B->getParent(), IsRdxInst) && + hasRequiredNumberOfUses(RdxKind, I, IsRdxInst) && + (!LeafOpcode || LeafOpcode == I->getOpcode() || IsRdxInst)) { + if (IsRdxInst) { + // We need to be able to reassociate the reduction operations. + if (!isVectorizable(EdgeRdxKind, I)) { // I is an extra argument for TreeN (its parent operation). markExtraArg(Stack.back(), I); continue; } - - if (IsReductionOperation) { - // We need to be able to reassociate the reduction operations. - if (!OpData.isAssociative(I)) { - // I is an extra argument for TreeN (its parent operation). - markExtraArg(Stack.back(), I); - continue; - } - } else if (ReducedValueData && - ReducedValueData != OpData) { - // Make sure that the opcodes of the operations that we are going to - // reduce match. - // I is an extra argument for TreeN (its parent operation). - markExtraArg(Stack.back(), I); - continue; - } else if (!ReducedValueData) - ReducedValueData = OpData; - - Stack.push_back(std::make_pair(I, OpData.getFirstOperandIndex())); - continue; + } else if (!LeafOpcode) { + LeafOpcode = I->getOpcode(); } + Stack.push_back(std::make_pair(I, getFirstOperandIndex(EdgeRdxKind))); + continue; } - // NextV is an extra argument for TreeN (its parent operation). - markExtraArg(Stack.back(), NextV); + // I is an extra argument for TreeN (its parent operation). + markExtraArg(Stack.back(), I); } return true; } - /// Attempt to vectorize the tree found by - /// matchAssociativeReduction. + /// Attempt to vectorize the tree found by matchAssociativeReduction. bool tryToReduce(BoUpSLP &V, TargetTransformInfo *TTI) { - if (ReducedVals.empty()) - return false; - - // If there is a sufficient number of reduction values, reduce - // to a nearby power-of-2. Can safely generate oversized + // If there are a sufficient number of reduction values, reduce + // to a nearby power-of-2. We can safely generate oversized // vectors and rely on the backend to split them to legal sizes. unsigned NumReducedVals = ReducedVals.size(); if (NumReducedVals < 4) return false; - unsigned ReduxWidth = PowerOf2Floor(NumReducedVals); - - Value *VectorizedTree = nullptr; + // Intersect the fast-math-flags from all reduction operations. + FastMathFlags RdxFMF; + RdxFMF.set(); + for (ReductionOpsType &RdxOp : ReductionOps) { + for (Value *RdxVal : RdxOp) { + if (auto *FPMO = dyn_cast(RdxVal)) + RdxFMF &= FPMO->getFastMathFlags(); + } + } - // FIXME: Fast-math-flags should be set based on the instructions in the - // reduction (not all of 'fast' are required). IRBuilder<> Builder(cast(ReductionRoot)); - FastMathFlags Unsafe; - Unsafe.setFast(); - Builder.setFastMathFlags(Unsafe); - unsigned i = 0; + Builder.setFastMathFlags(RdxFMF); BoUpSLP::ExtraValueToDebugLocsMap ExternallyUsedValues; - // The same extra argument may be used several time, so log each attempt + // The same extra argument may be used several times, so log each attempt // to use it. - for (auto &Pair : ExtraArgs) { + for (const std::pair &Pair : ExtraArgs) { assert(Pair.first && "DebugLoc must be set."); ExternallyUsedValues[Pair.second].push_back(Pair.first); } @@ -6857,14 +6852,48 @@ public: // so set it as externally used to prevent it from being deleted. ExternallyUsedValues[ReductionRoot]; SmallVector IgnoreList; - for (auto &V : ReductionOps) - IgnoreList.append(V.begin(), V.end()); + for (ReductionOpsType &RdxOp : ReductionOps) + IgnoreList.append(RdxOp.begin(), RdxOp.end()); + + unsigned ReduxWidth = PowerOf2Floor(NumReducedVals); + if (NumReducedVals > ReduxWidth) { + // In the loop below, we are building a tree based on a window of + // 'ReduxWidth' values. + // If the operands of those values have common traits (compare predicate, + // constant operand, etc), then we want to group those together to + // minimize the cost of the reduction. + + // TODO: This should be extended to count common operands for + // compares and binops. + + // Step 1: Count the number of times each compare predicate occurs. + SmallDenseMap PredCountMap; + for (Value *RdxVal : ReducedVals) { + CmpInst::Predicate Pred; + if (match(RdxVal, m_Cmp(Pred, m_Value(), m_Value()))) + ++PredCountMap[Pred]; + } + // Step 2: Sort the values so the most common predicates come first. + stable_sort(ReducedVals, [&PredCountMap](Value *A, Value *B) { + CmpInst::Predicate PredA, PredB; + if (match(A, m_Cmp(PredA, m_Value(), m_Value())) && + match(B, m_Cmp(PredB, m_Value(), m_Value()))) { + return PredCountMap[PredA] > PredCountMap[PredB]; + } + return false; + }); + } + + Value *VectorizedTree = nullptr; + unsigned i = 0; while (i < NumReducedVals - ReduxWidth + 1 && ReduxWidth > 2) { - auto VL = makeArrayRef(&ReducedVals[i], ReduxWidth); + ArrayRef VL(&ReducedVals[i], ReduxWidth); V.buildTree(VL, ExternallyUsedValues, IgnoreList); Optional> Order = V.bestOrder(); - // TODO: Handle orders of size less than number of elements in the vector. - if (Order && Order->size() == VL.size()) { + if (Order) { + assert(Order->size() == VL.size() && + "Order size must be the same as number of vectorized " + "instructions."); // TODO: reorder tree nodes without tree rebuilding. SmallVector ReorderedOps(VL.size()); llvm::transform(*Order, ReorderedOps.begin(), @@ -6873,60 +6902,66 @@ public: } if (V.isTreeTinyAndNotFullyVectorizable()) break; - if (V.isLoadCombineReductionCandidate(ReductionData.getOpcode())) + if (V.isLoadCombineReductionCandidate(RdxKind)) break; V.computeMinimumValueSizes(); // Estimate cost. - int TreeCost = V.getTreeCost(); - int ReductionCost = getReductionCost(TTI, ReducedVals[i], ReduxWidth); - int Cost = TreeCost + ReductionCost; + InstructionCost TreeCost = V.getTreeCost(); + InstructionCost ReductionCost = + getReductionCost(TTI, ReducedVals[i], ReduxWidth); + InstructionCost Cost = TreeCost + ReductionCost; + if (!Cost.isValid()) { + LLVM_DEBUG(dbgs() << "Encountered invalid baseline cost.\n"); + return false; + } if (Cost >= -SLPCostThreshold) { - V.getORE()->emit([&]() { - return OptimizationRemarkMissed( - SV_NAME, "HorSLPNotBeneficial", cast(VL[0])) - << "Vectorizing horizontal reduction is possible" - << "but not beneficial with cost " - << ore::NV("Cost", Cost) << " and threshold " - << ore::NV("Threshold", -SLPCostThreshold); - }); - break; + V.getORE()->emit([&]() { + return OptimizationRemarkMissed(SV_NAME, "HorSLPNotBeneficial", + cast(VL[0])) + << "Vectorizing horizontal reduction is possible" + << "but not beneficial with cost " << ore::NV("Cost", Cost) + << " and threshold " + << ore::NV("Threshold", -SLPCostThreshold); + }); + break; } LLVM_DEBUG(dbgs() << "SLP: Vectorizing horizontal reduction at cost:" << Cost << ". (HorRdx)\n"); V.getORE()->emit([&]() { - return OptimizationRemark( - SV_NAME, "VectorizedHorizontalReduction", cast(VL[0])) - << "Vectorized horizontal reduction with cost " - << ore::NV("Cost", Cost) << " and with tree size " - << ore::NV("TreeSize", V.getTreeSize()); + return OptimizationRemark(SV_NAME, "VectorizedHorizontalReduction", + cast(VL[0])) + << "Vectorized horizontal reduction with cost " + << ore::NV("Cost", Cost) << " and with tree size " + << ore::NV("TreeSize", V.getTreeSize()); }); // Vectorize a tree. DebugLoc Loc = cast(ReducedVals[i])->getDebugLoc(); Value *VectorizedRoot = V.vectorizeTree(ExternallyUsedValues); - // Emit a reduction. For min/max, the root is a select, but the insertion + // Emit a reduction. If the root is a select (min/max idiom), the insert // point is the compare condition of that select. Instruction *RdxRootInst = cast(ReductionRoot); - if (ReductionData.isMinMax()) + if (isCmpSel(RdxKind)) Builder.SetInsertPoint(getCmpForMinMaxReduction(RdxRootInst)); else Builder.SetInsertPoint(RdxRootInst); Value *ReducedSubTree = emitReduction(VectorizedRoot, Builder, ReduxWidth, TTI); - if (VectorizedTree) { - Builder.SetCurrentDebugLocation(Loc); - OperationData VectReductionData(ReductionData.getOpcode(), - VectorizedTree, ReducedSubTree, - ReductionData.getKind()); - VectorizedTree = - VectReductionData.createOp(Builder, "op.rdx", ReductionOps); - } else + + if (!VectorizedTree) { + // Initialize the final value in the reduction. VectorizedTree = ReducedSubTree; + } else { + // Update the final value in the reduction. + Builder.SetCurrentDebugLocation(Loc); + VectorizedTree = createOp(Builder, RdxKind, VectorizedTree, + ReducedSubTree, "op.rdx", ReductionOps); + } i += ReduxWidth; ReduxWidth = PowerOf2Floor(NumReducedVals - i); } @@ -6936,19 +6971,15 @@ public: for (; i < NumReducedVals; ++i) { auto *I = cast(ReducedVals[i]); Builder.SetCurrentDebugLocation(I->getDebugLoc()); - OperationData VectReductionData(ReductionData.getOpcode(), - VectorizedTree, I, - ReductionData.getKind()); - VectorizedTree = VectReductionData.createOp(Builder, "", ReductionOps); + VectorizedTree = + createOp(Builder, RdxKind, VectorizedTree, I, "", ReductionOps); } for (auto &Pair : ExternallyUsedValues) { // Add each externally used value to the final reduction. for (auto *I : Pair.second) { Builder.SetCurrentDebugLocation(I->getDebugLoc()); - OperationData VectReductionData(ReductionData.getOpcode(), - VectorizedTree, Pair.first, - ReductionData.getKind()); - VectorizedTree = VectReductionData.createOp(Builder, "op.extra", I); + VectorizedTree = createOp(Builder, RdxKind, VectorizedTree, + Pair.first, "op.extra", I); } } @@ -6956,7 +6987,7 @@ public: // select, we also have to RAUW for the compare instruction feeding the // reduction root. That's because the original compare may have extra uses // besides the final select of the reduction. - if (ReductionData.isMinMax()) { + if (isCmpSel(RdxKind)) { if (auto *VecSelect = dyn_cast(VectorizedTree)) { Instruction *ScalarCmp = getCmpForMinMaxReduction(cast(ReductionRoot)); @@ -6972,77 +7003,68 @@ public: return VectorizedTree != nullptr; } - unsigned numReductionValues() const { - return ReducedVals.size(); - } + unsigned numReductionValues() const { return ReducedVals.size(); } private: /// Calculate the cost of a reduction. - int getReductionCost(TargetTransformInfo *TTI, Value *FirstReducedVal, - unsigned ReduxWidth) { + InstructionCost getReductionCost(TargetTransformInfo *TTI, + Value *FirstReducedVal, + unsigned ReduxWidth) { Type *ScalarTy = FirstReducedVal->getType(); - auto *VecTy = FixedVectorType::get(ScalarTy, ReduxWidth); - - int PairwiseRdxCost; - int SplittingRdxCost; - switch (ReductionData.getKind()) { - case RK_Arithmetic: - PairwiseRdxCost = - TTI->getArithmeticReductionCost(ReductionData.getOpcode(), VecTy, - /*IsPairwiseForm=*/true); - SplittingRdxCost = - TTI->getArithmeticReductionCost(ReductionData.getOpcode(), VecTy, - /*IsPairwiseForm=*/false); - break; - case RK_Min: - case RK_Max: - case RK_UMin: - case RK_UMax: { - auto *VecCondTy = cast(CmpInst::makeCmpResultType(VecTy)); - bool IsUnsigned = ReductionData.getKind() == RK_UMin || - ReductionData.getKind() == RK_UMax; - PairwiseRdxCost = - TTI->getMinMaxReductionCost(VecTy, VecCondTy, - /*IsPairwiseForm=*/true, IsUnsigned); - SplittingRdxCost = - TTI->getMinMaxReductionCost(VecTy, VecCondTy, - /*IsPairwiseForm=*/false, IsUnsigned); + FixedVectorType *VectorTy = FixedVectorType::get(ScalarTy, ReduxWidth); + InstructionCost VectorCost, ScalarCost; + switch (RdxKind) { + case RecurKind::Add: + case RecurKind::Mul: + case RecurKind::Or: + case RecurKind::And: + case RecurKind::Xor: + case RecurKind::FAdd: + case RecurKind::FMul: { + unsigned RdxOpcode = RecurrenceDescriptor::getOpcode(RdxKind); + VectorCost = TTI->getArithmeticReductionCost(RdxOpcode, VectorTy, + /*IsPairwiseForm=*/false); + ScalarCost = TTI->getArithmeticInstrCost(RdxOpcode, ScalarTy); break; } - case RK_None: - llvm_unreachable("Expected arithmetic or min/max reduction operation"); - } - - IsPairwiseReduction = PairwiseRdxCost < SplittingRdxCost; - int VecReduxCost = IsPairwiseReduction ? PairwiseRdxCost : SplittingRdxCost; - - int ScalarReduxCost = 0; - switch (ReductionData.getKind()) { - case RK_Arithmetic: - ScalarReduxCost = - TTI->getArithmeticInstrCost(ReductionData.getOpcode(), ScalarTy); + case RecurKind::FMax: + case RecurKind::FMin: { + auto *VecCondTy = cast(CmpInst::makeCmpResultType(VectorTy)); + VectorCost = + TTI->getMinMaxReductionCost(VectorTy, VecCondTy, + /*pairwise=*/false, /*unsigned=*/false); + ScalarCost = + TTI->getCmpSelInstrCost(Instruction::FCmp, ScalarTy) + + TTI->getCmpSelInstrCost(Instruction::Select, ScalarTy, + CmpInst::makeCmpResultType(ScalarTy)); break; - case RK_Min: - case RK_Max: - case RK_UMin: - case RK_UMax: - ScalarReduxCost = - TTI->getCmpSelInstrCost(ReductionData.getOpcode(), ScalarTy) + + } + case RecurKind::SMax: + case RecurKind::SMin: + case RecurKind::UMax: + case RecurKind::UMin: { + auto *VecCondTy = cast(CmpInst::makeCmpResultType(VectorTy)); + bool IsUnsigned = + RdxKind == RecurKind::UMax || RdxKind == RecurKind::UMin; + VectorCost = + TTI->getMinMaxReductionCost(VectorTy, VecCondTy, + /*IsPairwiseForm=*/false, IsUnsigned); + ScalarCost = + TTI->getCmpSelInstrCost(Instruction::ICmp, ScalarTy) + TTI->getCmpSelInstrCost(Instruction::Select, ScalarTy, CmpInst::makeCmpResultType(ScalarTy)); break; - case RK_None: + } + default: llvm_unreachable("Expected arithmetic or min/max reduction operation"); } - ScalarReduxCost *= (ReduxWidth - 1); - LLVM_DEBUG(dbgs() << "SLP: Adding cost " << VecReduxCost - ScalarReduxCost + // Scalar cost is repeated for N-1 elements. + ScalarCost *= (ReduxWidth - 1); + LLVM_DEBUG(dbgs() << "SLP: Adding cost " << VectorCost - ScalarCost << " for reduction that starts with " << *FirstReducedVal - << " (It is a " - << (IsPairwiseReduction ? "pairwise" : "splitting") - << " reduction)\n"); - - return VecReduxCost - ScalarReduxCost; + << " (It is a splitting reduction)\n"); + return VectorCost - ScalarCost; } /// Emit a horizontal reduction of the vectorized value. @@ -7052,92 +7074,142 @@ private: assert(isPowerOf2_32(ReduxWidth) && "We only handle power-of-two reductions for now"); - if (!IsPairwiseReduction) { - // FIXME: The builder should use an FMF guard. It should not be hard-coded - // to 'fast'. - assert(Builder.getFastMathFlags().isFast() && "Expected 'fast' FMF"); - return createSimpleTargetReduction( - Builder, TTI, ReductionData.getOpcode(), VectorizedValue, - ReductionData.getFlags(), ReductionOps.back()); - } + return createSimpleTargetReduction(Builder, TTI, VectorizedValue, RdxKind, + ReductionOps.back()); + } +}; + +} // end anonymous namespace - Value *TmpVec = VectorizedValue; - for (unsigned i = ReduxWidth / 2; i != 0; i >>= 1) { - auto LeftMask = createRdxShuffleMask(ReduxWidth, i, true, true); - auto RightMask = createRdxShuffleMask(ReduxWidth, i, true, false); +static Optional getAggregateSize(Instruction *InsertInst) { + if (auto *IE = dyn_cast(InsertInst)) + return cast(IE->getType())->getNumElements(); - Value *LeftShuf = Builder.CreateShuffleVector( - TmpVec, UndefValue::get(TmpVec->getType()), LeftMask, "rdx.shuf.l"); - Value *RightShuf = Builder.CreateShuffleVector( - TmpVec, UndefValue::get(TmpVec->getType()), (RightMask), - "rdx.shuf.r"); - OperationData VectReductionData(ReductionData.getOpcode(), LeftShuf, - RightShuf, ReductionData.getKind()); - TmpVec = VectReductionData.createOp(Builder, "op.rdx", ReductionOps); + unsigned AggregateSize = 1; + auto *IV = cast(InsertInst); + Type *CurrentType = IV->getType(); + do { + if (auto *ST = dyn_cast(CurrentType)) { + for (auto *Elt : ST->elements()) + if (Elt != ST->getElementType(0)) // check homogeneity + return None; + AggregateSize *= ST->getNumElements(); + CurrentType = ST->getElementType(0); + } else if (auto *AT = dyn_cast(CurrentType)) { + AggregateSize *= AT->getNumElements(); + CurrentType = AT->getElementType(); + } else if (auto *VT = dyn_cast(CurrentType)) { + AggregateSize *= VT->getNumElements(); + return AggregateSize; + } else if (CurrentType->isSingleValueType()) { + return AggregateSize; + } else { + return None; } + } while (true); +} - // The result is in the first element of the vector. - return Builder.CreateExtractElement(TmpVec, Builder.getInt32(0)); +static Optional getOperandIndex(Instruction *InsertInst, + unsigned OperandOffset) { + unsigned OperandIndex = OperandOffset; + if (auto *IE = dyn_cast(InsertInst)) { + if (auto *CI = dyn_cast(IE->getOperand(2))) { + auto *VT = cast(IE->getType()); + OperandIndex *= VT->getNumElements(); + OperandIndex += CI->getZExtValue(); + return OperandIndex; + } + return None; } -}; -} // end anonymous namespace + auto *IV = cast(InsertInst); + Type *CurrentType = IV->getType(); + for (unsigned int Index : IV->indices()) { + if (auto *ST = dyn_cast(CurrentType)) { + OperandIndex *= ST->getNumElements(); + CurrentType = ST->getElementType(Index); + } else if (auto *AT = dyn_cast(CurrentType)) { + OperandIndex *= AT->getNumElements(); + CurrentType = AT->getElementType(); + } else { + return None; + } + OperandIndex += Index; + } + return OperandIndex; +} + +static bool findBuildAggregate_rec(Instruction *LastInsertInst, + TargetTransformInfo *TTI, + SmallVectorImpl &BuildVectorOpds, + SmallVectorImpl &InsertElts, + unsigned OperandOffset) { + do { + Value *InsertedOperand = LastInsertInst->getOperand(1); + Optional OperandIndex = + getOperandIndex(LastInsertInst, OperandOffset); + if (!OperandIndex) + return false; + if (isa(InsertedOperand) || + isa(InsertedOperand)) { + if (!findBuildAggregate_rec(cast(InsertedOperand), TTI, + BuildVectorOpds, InsertElts, *OperandIndex)) + return false; + } else { + BuildVectorOpds[*OperandIndex] = InsertedOperand; + InsertElts[*OperandIndex] = LastInsertInst; + } + if (isa(LastInsertInst->getOperand(0))) + return true; + LastInsertInst = dyn_cast(LastInsertInst->getOperand(0)); + } while (LastInsertInst != nullptr && + (isa(LastInsertInst) || + isa(LastInsertInst)) && + LastInsertInst->hasOneUse()); + return false; +} /// Recognize construction of vectors like -/// %ra = insertelement <4 x float> undef, float %s0, i32 0 +/// %ra = insertelement <4 x float> poison, float %s0, i32 0 /// %rb = insertelement <4 x float> %ra, float %s1, i32 1 /// %rc = insertelement <4 x float> %rb, float %s2, i32 2 /// %rd = insertelement <4 x float> %rc, float %s3, i32 3 /// starting from the last insertelement or insertvalue instruction. /// -/// Also recognize aggregates like {<2 x float>, <2 x float>}, +/// Also recognize homogeneous aggregates like {<2 x float>, <2 x float>}, /// {{float, float}, {float, float}}, [2 x {float, float}] and so on. /// See llvm/test/Transforms/SLPVectorizer/X86/pr42022.ll for examples. /// /// Assume LastInsertInst is of InsertElementInst or InsertValueInst type. /// /// \return true if it matches. -static bool findBuildAggregate(Value *LastInsertInst, TargetTransformInfo *TTI, +static bool findBuildAggregate(Instruction *LastInsertInst, + TargetTransformInfo *TTI, SmallVectorImpl &BuildVectorOpds, SmallVectorImpl &InsertElts) { + assert((isa(LastInsertInst) || isa(LastInsertInst)) && "Expected insertelement or insertvalue instruction!"); - do { - Value *InsertedOperand; - auto *IE = dyn_cast(LastInsertInst); - if (IE) { - InsertedOperand = IE->getOperand(1); - LastInsertInst = IE->getOperand(0); - } else { - auto *IV = cast(LastInsertInst); - InsertedOperand = IV->getInsertedValueOperand(); - LastInsertInst = IV->getAggregateOperand(); - } - if (isa(InsertedOperand) || - isa(InsertedOperand)) { - SmallVector TmpBuildVectorOpds; - SmallVector TmpInsertElts; - if (!findBuildAggregate(InsertedOperand, TTI, TmpBuildVectorOpds, - TmpInsertElts)) - return false; - BuildVectorOpds.append(TmpBuildVectorOpds.rbegin(), - TmpBuildVectorOpds.rend()); - InsertElts.append(TmpInsertElts.rbegin(), TmpInsertElts.rend()); - } else { - BuildVectorOpds.push_back(InsertedOperand); - InsertElts.push_back(IE); - } - if (isa(LastInsertInst)) - break; - if ((!isa(LastInsertInst) && - !isa(LastInsertInst)) || - !LastInsertInst->hasOneUse()) - return false; - } while (true); - std::reverse(BuildVectorOpds.begin(), BuildVectorOpds.end()); - std::reverse(InsertElts.begin(), InsertElts.end()); - return true; + + assert((BuildVectorOpds.empty() && InsertElts.empty()) && + "Expected empty result vectors!"); + + Optional AggregateSize = getAggregateSize(LastInsertInst); + if (!AggregateSize) + return false; + BuildVectorOpds.resize(*AggregateSize); + InsertElts.resize(*AggregateSize); + + if (findBuildAggregate_rec(LastInsertInst, TTI, BuildVectorOpds, InsertElts, + 0)) { + llvm::erase_value(BuildVectorOpds, nullptr); + llvm::erase_value(InsertElts, nullptr); + if (BuildVectorOpds.size() >= 2) + return true; + } + + return false; } static bool PhiTypeSorterFunc(Value *V, Value *V2) { @@ -7195,6 +7267,16 @@ static Value *getReductionValue(const DominatorTree *DT, PHINode *P, return nullptr; } +static bool matchRdxBop(Instruction *I, Value *&V0, Value *&V1) { + if (match(I, m_BinOp(m_Value(V0), m_Value(V1)))) + return true; + if (match(I, m_Intrinsic(m_Value(V0), m_Value(V1)))) + return true; + if (match(I, m_Intrinsic(m_Value(V0), m_Value(V1)))) + return true; + return false; +} + /// Attempt to reduce a horizontal reduction. /// If it is legal to match a horizontal reduction feeding the phi node \a P /// with reduction operators \a Root (or one of its operands) in a basic block @@ -7234,9 +7316,10 @@ static bool tryToVectorizeHorReductionOrInstOperands( Instruction *Inst; unsigned Level; std::tie(Inst, Level) = Stack.pop_back_val(); - auto *BI = dyn_cast(Inst); - auto *SI = dyn_cast(Inst); - if (BI || SI) { + Value *B0, *B1; + bool IsBinop = matchRdxBop(Inst, B0, B1); + bool IsSelect = match(Inst, m_Select(m_Value(), m_Value(), m_Value())); + if (IsBinop || IsSelect) { HorizontalReduction HorRdx; if (HorRdx.matchAssociativeReduction(P, Inst)) { if (HorRdx.tryToReduce(R, TTI)) { @@ -7247,10 +7330,10 @@ static bool tryToVectorizeHorReductionOrInstOperands( continue; } } - if (P && BI) { - Inst = dyn_cast(BI->getOperand(0)); + if (P && IsBinop) { + Inst = dyn_cast(B0); if (Inst == P) - Inst = dyn_cast(BI->getOperand(1)); + Inst = dyn_cast(B1); if (!Inst) { // Set P to nullptr to avoid re-analysis of phi node in // matchAssociativeReduction function unless this is the root node. @@ -7283,9 +7366,7 @@ static bool tryToVectorizeHorReductionOrInstOperands( bool SLPVectorizerPass::vectorizeRootInstruction(PHINode *P, Value *V, BasicBlock *BB, BoUpSLP &R, TargetTransformInfo *TTI) { - if (!V) - return false; - auto *I = dyn_cast(V); + auto *I = dyn_cast_or_null(V); if (!I) return false; @@ -7307,8 +7388,7 @@ bool SLPVectorizerPass::vectorizeInsertValueInst(InsertValueInst *IVI, SmallVector BuildVectorOpds; SmallVector BuildVectorInsts; - if (!findBuildAggregate(IVI, TTI, BuildVectorOpds, BuildVectorInsts) || - BuildVectorOpds.size() < 2) + if (!findBuildAggregate(IVI, TTI, BuildVectorOpds, BuildVectorInsts)) return false; LLVM_DEBUG(dbgs() << "SLP: array mappable to vector: " << *IVI << "\n"); @@ -7323,7 +7403,6 @@ bool SLPVectorizerPass::vectorizeInsertElementInst(InsertElementInst *IEI, SmallVector BuildVectorInsts; SmallVector BuildVectorOpds; if (!findBuildAggregate(IEI, TTI, BuildVectorOpds, BuildVectorInsts) || - BuildVectorOpds.size() < 2 || (llvm::all_of(BuildVectorOpds, [](Value *V) { return isa(V); }) && isShuffle(BuildVectorOpds))) @@ -7369,7 +7448,6 @@ bool SLPVectorizerPass::vectorizeChainsInBlock(BasicBlock *BB, BoUpSLP &R) { bool Changed = false; SmallVector Incoming; SmallPtrSet VisitedInstrs; - unsigned MaxVecRegSize = R.getMaxVecRegSize(); bool HaveVectorizedPhiNodes = true; while (HaveVectorizedPhiNodes) { @@ -7396,18 +7474,8 @@ bool SLPVectorizerPass::vectorizeChainsInBlock(BasicBlock *BB, BoUpSLP &R) { // Look for the next elements with the same type. SmallVector::iterator SameTypeIt = IncIt; - Type *EltTy = (*IncIt)->getType(); - unsigned EltSize = EltTy->isSized() ? DL->getTypeSizeInBits(EltTy) - : MaxVecRegSize; - unsigned MaxNumElts = MaxVecRegSize / EltSize; - if (MaxNumElts < 2) { - ++IncIt; - continue; - } - while (SameTypeIt != E && - (*SameTypeIt)->getType() == EltTy && - (SameTypeIt - IncIt) < MaxNumElts) { + (*SameTypeIt)->getType() == (*IncIt)->getType()) { VisitedInstrs.insert(*SameTypeIt); ++SameTypeIt; } @@ -7439,12 +7507,17 @@ bool SLPVectorizerPass::vectorizeChainsInBlock(BasicBlock *BB, BoUpSLP &R) { SmallVector PostProcessInstructions; SmallDenseSet KeyNodes; for (BasicBlock::iterator it = BB->begin(), e = BB->end(); it != e; ++it) { + // Skip instructions with scalable type. The num of elements is unknown at + // compile-time for scalable type. + if (isa(it->getType())) + continue; + // Skip instructions marked for the deletion. if (R.isDeleted(&*it)) continue; // We may go through BB multiple times so skip the one we have checked. if (!VisitedInstrs.insert(&*it).second) { - if (it->use_empty() && KeyNodes.count(&*it) > 0 && + if (it->use_empty() && KeyNodes.contains(&*it) && vectorizeSimpleInstructions(PostProcessInstructions, BB, R)) { // We would like to start over since some instructions are deleted // and the iterator may become invalid value. @@ -7461,16 +7534,29 @@ bool SLPVectorizerPass::vectorizeChainsInBlock(BasicBlock *BB, BoUpSLP &R) { // Try to vectorize reductions that use PHINodes. if (PHINode *P = dyn_cast(it)) { // Check that the PHI is a reduction PHI. - if (P->getNumIncomingValues() != 2) - return Changed; + if (P->getNumIncomingValues() == 2) { + // Try to match and vectorize a horizontal reduction. + if (vectorizeRootInstruction(P, getReductionValue(DT, P, BB, LI), BB, R, + TTI)) { + Changed = true; + it = BB->begin(); + e = BB->end(); + continue; + } + } + // Try to vectorize the incoming values of the PHI, to catch reductions + // that feed into PHIs. + for (unsigned I = 0, E = P->getNumIncomingValues(); I != E; I++) { + // Skip if the incoming block is the current BB for now. Also, bypass + // unreachable IR for efficiency and to avoid crashing. + // TODO: Collect the skipped incoming values and try to vectorize them + // after processing BB. + if (BB == P->getIncomingBlock(I) || + !DT->isReachableFromEntry(P->getIncomingBlock(I))) + continue; - // Try to match and vectorize a horizontal reduction. - if (vectorizeRootInstruction(P, getReductionValue(DT, P, BB, LI), BB, R, - TTI)) { - Changed = true; - it = BB->begin(); - e = BB->end(); - continue; + Changed |= vectorizeRootInstruction(nullptr, P->getIncomingValue(I), + P->getIncomingBlock(I), R, TTI); } continue; } @@ -7534,7 +7620,7 @@ bool SLPVectorizerPass::vectorizeGEPIndices(BasicBlock *BB, BoUpSLP &R) { unsigned MaxElts = MaxVecRegSize / EltSize; for (unsigned BI = 0, BE = Entry.second.size(); BI < BE; BI += MaxElts) { auto Len = std::min(BE - BI, MaxElts); - auto GEPList = makeArrayRef(&Entry.second[BI], Len); + ArrayRef GEPList(&Entry.second[BI], Len); // Initialize a set a candidate getelementptrs. Note that we use a // SetVector here to preserve program order. If the index computations diff --git a/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h b/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h index 6f055ca80ff2..873701676067 100644 --- a/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h +++ b/llvm/lib/Transforms/Vectorize/VPRecipeBuilder.h @@ -61,17 +61,19 @@ class VPRecipeBuilder { /// Check if the load or store instruction \p I should widened for \p /// Range.Start and potentially masked. Such instructions are handled by a /// recipe that takes an additional VPInstruction for the mask. - VPWidenMemoryInstructionRecipe * - tryToWidenMemory(Instruction *I, VFRange &Range, VPlanPtr &Plan); + VPRecipeBase *tryToWidenMemory(Instruction *I, VFRange &Range, + VPlanPtr &Plan); /// Check if an induction recipe should be constructed for \I. If so build and /// return it. If not, return null. - VPWidenIntOrFpInductionRecipe *tryToOptimizeInductionPHI(PHINode *Phi) const; + VPWidenIntOrFpInductionRecipe *tryToOptimizeInductionPHI(PHINode *Phi, + VPlan &Plan) const; /// Optimize the special case where the operand of \p I is a constant integer /// induction variable. VPWidenIntOrFpInductionRecipe * - tryToOptimizeInductionTruncate(TruncInst *I, VFRange &Range) const; + tryToOptimizeInductionTruncate(TruncInst *I, VFRange &Range, + VPlan &Plan) const; /// Handle non-loop phi nodes. Currently all such phi nodes are turned into /// a sequence of select instructions as the vectorizer currently performs diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp index f5f28a3bffa1..b26399e0ae58 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -20,8 +20,10 @@ #include "VPlanDominatorTree.h" #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/PostOrderIterator.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/Twine.h" +#include "llvm/Analysis/IVDescriptors.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/CFG.h" @@ -56,13 +58,69 @@ raw_ostream &llvm::operator<<(raw_ostream &OS, const VPValue &V) { return OS; } +VPValue::VPValue(const unsigned char SC, Value *UV, VPDef *Def) + : SubclassID(SC), UnderlyingVal(UV), Def(Def) { + if (Def) + Def->addDefinedValue(this); +} + +VPValue::~VPValue() { + assert(Users.empty() && "trying to delete a VPValue with remaining users"); + if (Def) + Def->removeDefinedValue(this); +} + void VPValue::print(raw_ostream &OS, VPSlotTracker &SlotTracker) const { - if (const VPInstruction *Instr = dyn_cast(this)) - Instr->print(OS, SlotTracker); + if (const VPRecipeBase *R = dyn_cast_or_null(Def)) + R->print(OS, "", SlotTracker); else printAsOperand(OS, SlotTracker); } +void VPValue::dump() const { + const VPRecipeBase *Instr = dyn_cast_or_null(this->Def); + VPSlotTracker SlotTracker( + (Instr && Instr->getParent()) ? Instr->getParent()->getPlan() : nullptr); + print(dbgs(), SlotTracker); + dbgs() << "\n"; +} + +void VPDef::dump() const { + const VPRecipeBase *Instr = dyn_cast_or_null(this); + VPSlotTracker SlotTracker( + (Instr && Instr->getParent()) ? Instr->getParent()->getPlan() : nullptr); + print(dbgs(), "", SlotTracker); + dbgs() << "\n"; +} + +VPUser *VPRecipeBase::toVPUser() { + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + if (auto *U = dyn_cast(this)) + return U; + return nullptr; +} + // Get the top-most entry block of \p Start. This is the entry block of the // containing VPlan. This function is templated to support both const and non-const blocks template static T *getPlanEntry(T *Start) { @@ -142,14 +200,43 @@ VPBlockBase *VPBlockBase::getEnclosingBlockWithPredecessors() { } void VPBlockBase::deleteCFG(VPBlockBase *Entry) { - SmallVector Blocks; - for (VPBlockBase *Block : depth_first(Entry)) - Blocks.push_back(Block); + SmallVector Blocks(depth_first(Entry)); for (VPBlockBase *Block : Blocks) delete Block; } +VPBasicBlock::iterator VPBasicBlock::getFirstNonPhi() { + iterator It = begin(); + while (It != end() && (isa(&*It) || + isa(&*It) || + isa(&*It) || + isa(&*It))) + It++; + return It; +} + +Value *VPTransformState::get(VPValue *Def, const VPIteration &Instance) { + if (!Def->getDef() && OrigLoop->isLoopInvariant(Def->getLiveInIRValue())) + return Def->getLiveInIRValue(); + + if (hasScalarValue(Def, Instance)) + return Data.PerPartScalars[Def][Instance.Part][Instance.Lane]; + + if (hasVectorValue(Def, Instance.Part)) { + assert(Data.PerPartOutput.count(Def)); + auto *VecPart = Data.PerPartOutput[Def][Instance.Part]; + if (!VecPart->getType()->isVectorTy()) { + assert(Instance.Lane == 0 && "cannot get lane > 0 for scalar"); + return VecPart; + } + // TODO: Cache created scalar values. + return Builder.CreateExtractElement(VecPart, + Builder.getInt32(Instance.Lane)); + } + return Callback.getOrCreateScalarValue(VPValue2Value[Def], Instance); +} + BasicBlock * VPBasicBlock::createEmptyBasicBlock(VPTransformState::CFGState &CFG) { // BB stands for IR BasicBlocks. VPBB stands for VPlan VPBasicBlocks. @@ -267,6 +354,24 @@ void VPBasicBlock::execute(VPTransformState *State) { LLVM_DEBUG(dbgs() << "LV: filled BB:" << *NewBB); } +void VPBasicBlock::dropAllReferences(VPValue *NewValue) { + for (VPRecipeBase &R : Recipes) { + for (auto *Def : R.definedValues()) + Def->replaceAllUsesWith(NewValue); + + if (auto *User = R.toVPUser()) + for (unsigned I = 0, E = User->getNumOperands(); I != E; I++) + User->setOperand(I, NewValue); + } +} + +void VPRegionBlock::dropAllReferences(VPValue *NewValue) { + for (VPBlockBase *Block : depth_first(Entry)) + // Drop all references in VPBasicBlocks and replace all uses with + // DummyValue. + Block->dropAllReferences(NewValue); +} + void VPRegionBlock::execute(VPTransformState *State) { ReversePostOrderTraversal RPOT(Entry); @@ -300,7 +405,9 @@ void VPRegionBlock::execute(VPTransformState *State) { for (unsigned Part = 0, UF = State->UF; Part < UF; ++Part) { State->Instance->Part = Part; - for (unsigned Lane = 0, VF = State->VF; Lane < VF; ++Lane) { + assert(!State->VF.isScalable() && "VF is assumed to be non scalable."); + for (unsigned Lane = 0, VF = State->VF.getKnownMinValue(); Lane < VF; + ++Lane) { State->Instance->Lane = Lane; // Visit the VPBlocks connected to \p this, starting from it. for (VPBlockBase *Block : RPOT) { @@ -346,6 +453,14 @@ void VPRecipeBase::moveAfter(VPRecipeBase *InsertPos) { insertAfter(InsertPos); } +void VPRecipeBase::moveBefore(VPBasicBlock &BB, + iplist::iterator I) { + assert(I == BB.end() || I->getParent() == &BB); + removeFromParent(); + Parent = &BB; + BB.getRecipeList().insert(I, this); +} + void VPInstruction::generateInstruction(VPTransformState &State, unsigned Part) { IRBuilder<> &Builder = State.Builder; @@ -383,14 +498,14 @@ void VPInstruction::generateInstruction(VPTransformState &State, case VPInstruction::ActiveLaneMask: { // Get first lane of vector induction variable. Value *VIVElem0 = State.get(getOperand(0), {Part, 0}); - // Get first lane of backedge-taken-count. - Value *ScalarBTC = State.get(getOperand(1), {Part, 0}); + // Get the original loop tripcount. + Value *ScalarTC = State.TripCount; auto *Int1Ty = Type::getInt1Ty(Builder.getContext()); - auto *PredTy = FixedVectorType::get(Int1Ty, State.VF); + auto *PredTy = FixedVectorType::get(Int1Ty, State.VF.getKnownMinValue()); Instruction *Call = Builder.CreateIntrinsic( - Intrinsic::get_active_lane_mask, {PredTy, ScalarBTC->getType()}, - {VIVElem0, ScalarBTC}, nullptr, "active.lane.mask"); + Intrinsic::get_active_lane_mask, {PredTy, ScalarTC->getType()}, + {VIVElem0, ScalarTC}, nullptr, "active.lane.mask"); State.set(this, Call, Part); break; } @@ -405,18 +520,15 @@ void VPInstruction::execute(VPTransformState &State) { generateInstruction(State, Part); } -void VPInstruction::print(raw_ostream &O, const Twine &Indent, - VPSlotTracker &SlotTracker) const { - O << "\"EMIT "; - print(O, SlotTracker); -} - -void VPInstruction::print(raw_ostream &O) const { +void VPInstruction::dump() const { VPSlotTracker SlotTracker(getParent()->getPlan()); - print(O, SlotTracker); + print(dbgs(), "", SlotTracker); } -void VPInstruction::print(raw_ostream &O, VPSlotTracker &SlotTracker) const { +void VPInstruction::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { + O << "EMIT "; + if (hasResult()) { printAsOperand(O, SlotTracker); O << " = "; @@ -461,7 +573,7 @@ void VPlan::execute(VPTransformState *State) { "trip.count.minus.1"); auto VF = State->VF; Value *VTCMO = - VF == 1 ? TCMO : Builder.CreateVectorSplat(VF, TCMO, "broadcast"); + VF.isScalar() ? TCMO : Builder.CreateVectorSplat(VF, TCMO, "broadcast"); for (unsigned Part = 0, UF = State->UF; Part < UF; ++Part) State->set(BackedgeTakenCount, VTCMO, Part); } @@ -666,7 +778,7 @@ void VPlanPrinter::dumpBasicBlock(const VPBasicBlock *BasicBlock) { // Dump the block predicate. const VPValue *Pred = BasicBlock->getPredicate(); if (Pred) { - OS << " +\n" << Indent << " \"BlockPredicate: "; + OS << " +\n" << Indent << " \"BlockPredicate: \""; if (const VPInstruction *PredI = dyn_cast(Pred)) { PredI->printAsOperand(OS, SlotTracker); OS << " (" << DOT::EscapeString(PredI->getParent()->getName()) @@ -676,7 +788,7 @@ void VPlanPrinter::dumpBasicBlock(const VPBasicBlock *BasicBlock) { } for (const VPRecipeBase &Recipe : *BasicBlock) { - OS << " +\n" << Indent; + OS << " +\n" << Indent << "\""; Recipe.print(OS, Indent, SlotTracker); OS << "\\l\""; } @@ -715,7 +827,7 @@ void VPlanPrinter::dumpRegion(const VPRegionBlock *Region) { dumpEdges(Region); } -void VPlanPrinter::printAsIngredient(raw_ostream &O, Value *V) { +void VPlanPrinter::printAsIngredient(raw_ostream &O, const Value *V) { std::string IngredientString; raw_string_ostream RSO(IngredientString); if (auto *Inst = dyn_cast(V)) { @@ -738,24 +850,45 @@ void VPlanPrinter::printAsIngredient(raw_ostream &O, Value *V) { void VPWidenCallRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN-CALL " << VPlanIngredient(&Ingredient); + O << "WIDEN-CALL "; + + auto *CI = cast(getUnderlyingInstr()); + if (CI->getType()->isVoidTy()) + O << "void "; + else { + printAsOperand(O, SlotTracker); + O << " = "; + } + + O << "call @" << CI->getCalledFunction()->getName() << "("; + printOperands(O, SlotTracker); + O << ")"; } void VPWidenSelectRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN-SELECT" << VPlanIngredient(&Ingredient) - << (InvariantCond ? " (condition is loop invariant)" : ""); + O << "WIDEN-SELECT "; + printAsOperand(O, SlotTracker); + O << " = select "; + getOperand(0)->printAsOperand(O, SlotTracker); + O << ", "; + getOperand(1)->printAsOperand(O, SlotTracker); + O << ", "; + getOperand(2)->printAsOperand(O, SlotTracker); + O << (InvariantCond ? " (condition is loop invariant)" : ""); } void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN\\l\""; - O << "\" " << VPlanIngredient(&Ingredient); + O << "WIDEN "; + printAsOperand(O, SlotTracker); + O << " = " << getUnderlyingInstr()->getOpcodeName() << " "; + printOperands(O, SlotTracker); } void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN-INDUCTION"; + O << "WIDEN-INDUCTION"; if (Trunc) { O << "\\l\""; O << " +\n" << Indent << "\" " << VPlanIngredient(IV) << "\\l\""; @@ -766,23 +899,26 @@ void VPWidenIntOrFpInductionRecipe::print(raw_ostream &O, const Twine &Indent, void VPWidenGEPRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN-GEP "; + O << "WIDEN-GEP "; O << (IsPtrLoopInvariant ? "Inv" : "Var"); size_t IndicesNumber = IsIndexLoopInvariant.size(); for (size_t I = 0; I < IndicesNumber; ++I) O << "[" << (IsIndexLoopInvariant[I] ? "Inv" : "Var") << "]"; - O << "\\l\""; - O << " +\n" << Indent << "\" " << VPlanIngredient(GEP); + + O << " "; + printAsOperand(O, SlotTracker); + O << " = getelementptr "; + printOperands(O, SlotTracker); } void VPWidenPHIRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN-PHI " << VPlanIngredient(Phi); + O << "WIDEN-PHI " << VPlanIngredient(Phi); } void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"BLEND "; + O << "BLEND "; Phi->printAsOperand(O, false); O << " ="; if (getNumIncomingValues() == 1) { @@ -800,46 +936,75 @@ void VPBlendRecipe::print(raw_ostream &O, const Twine &Indent, } } +void VPReductionRecipe::print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const { + O << "REDUCE "; + printAsOperand(O, SlotTracker); + O << " = "; + getChainOp()->printAsOperand(O, SlotTracker); + O << " + reduce." << Instruction::getOpcodeName(RdxDesc->getOpcode()) + << " ("; + getVecOp()->printAsOperand(O, SlotTracker); + if (getCondOp()) { + O << ", "; + getCondOp()->printAsOperand(O, SlotTracker); + } + O << ")"; +} + void VPReplicateRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"" << (IsUniform ? "CLONE " : "REPLICATE ") - << VPlanIngredient(Ingredient); + O << (IsUniform ? "CLONE " : "REPLICATE "); + + if (!getUnderlyingInstr()->getType()->isVoidTy()) { + printAsOperand(O, SlotTracker); + O << " = "; + } + O << Instruction::getOpcodeName(getUnderlyingInstr()->getOpcode()) << " "; + printOperands(O, SlotTracker); + if (AlsoPack) O << " (S->V)"; } void VPPredInstPHIRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"PHI-PREDICATED-INSTRUCTION " << VPlanIngredient(PredInst); + O << "PHI-PREDICATED-INSTRUCTION "; + printOperands(O, SlotTracker); } void VPWidenMemoryInstructionRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"WIDEN " << VPlanIngredient(&Instr); - O << ", "; - getAddr()->printAsOperand(O, SlotTracker); - VPValue *Mask = getMask(); - if (Mask) { - O << ", "; - Mask->printAsOperand(O, SlotTracker); + O << "WIDEN "; + + if (!isStore()) { + getVPValue()->printAsOperand(O, SlotTracker); + O << " = "; } + O << Instruction::getOpcodeName(Ingredient.getOpcode()) << " "; + + printOperands(O, SlotTracker); } void VPWidenCanonicalIVRecipe::execute(VPTransformState &State) { Value *CanonicalIV = State.CanonicalIV; Type *STy = CanonicalIV->getType(); IRBuilder<> Builder(State.CFG.PrevBB->getTerminator()); - auto VF = State.VF; - Value *VStart = VF == 1 + ElementCount VF = State.VF; + assert(!VF.isScalable() && "the code following assumes non scalables ECs"); + Value *VStart = VF.isScalar() ? CanonicalIV - : Builder.CreateVectorSplat(VF, CanonicalIV, "broadcast"); + : Builder.CreateVectorSplat(VF.getKnownMinValue(), + CanonicalIV, "broadcast"); for (unsigned Part = 0, UF = State.UF; Part < UF; ++Part) { SmallVector Indices; - for (unsigned Lane = 0; Lane < VF; ++Lane) - Indices.push_back(ConstantInt::get(STy, Part * VF + Lane)); + for (unsigned Lane = 0; Lane < VF.getKnownMinValue(); ++Lane) + Indices.push_back( + ConstantInt::get(STy, Part * VF.getKnownMinValue() + Lane)); // If VF == 1, there is only one iteration in the loop above, thus the // element pushed back into Indices is ConstantInt::get(STy, Part) - Constant *VStep = VF == 1 ? Indices.back() : ConstantVector::get(Indices); + Constant *VStep = + VF.isScalar() ? Indices.back() : ConstantVector::get(Indices); // Add the consecutive indices to the vector value. Value *CanonicalVectorIV = Builder.CreateAdd(VStart, VStep, "vec.iv"); State.set(getVPValue(), CanonicalVectorIV, Part); @@ -848,7 +1013,7 @@ void VPWidenCanonicalIVRecipe::execute(VPTransformState &State) { void VPWidenCanonicalIVRecipe::print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const { - O << "\"EMIT "; + O << "EMIT "; getVPValue()->printAsOperand(O, SlotTracker); O << " = WIDEN-CANONICAL-INDUCTION"; } @@ -856,10 +1021,18 @@ void VPWidenCanonicalIVRecipe::print(raw_ostream &O, const Twine &Indent, template void DomTreeBuilder::Calculate(VPDominatorTree &DT); void VPValue::replaceAllUsesWith(VPValue *New) { - for (VPUser *User : users()) + for (unsigned J = 0; J < getNumUsers();) { + VPUser *User = Users[J]; + unsigned NumUsers = getNumUsers(); for (unsigned I = 0, E = User->getNumOperands(); I < E; ++I) if (User->getOperand(I) == this) User->setOperand(I, New); + // If a user got removed after updating the current user, the next user to + // update will be moved to the current position, so we only need to + // increment the index if the number of users did not change. + if (NumUsers == getNumUsers()) + J++; + } } void VPValue::printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const { @@ -877,6 +1050,12 @@ void VPValue::printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const { OS << "vp<%" << Tracker.getSlot(this) << ">"; } +void VPUser::printOperands(raw_ostream &O, VPSlotTracker &SlotTracker) const { + interleaveComma(operands(), O, [&O, &SlotTracker](VPValue *Op) { + Op->printAsOperand(O, SlotTracker); + }); +} + void VPInterleavedAccessInfo::visitRegion(VPRegionBlock *Region, Old2NewTy &Old2New, InterleavedAccessInfo &IAI) { @@ -925,13 +1104,6 @@ VPInterleavedAccessInfo::VPInterleavedAccessInfo(VPlan &Plan, void VPSlotTracker::assignSlot(const VPValue *V) { assert(Slots.find(V) == Slots.end() && "VPValue already has a slot!"); - const Value *UV = V->getUnderlyingValue(); - if (UV) - return; - const auto *VPI = dyn_cast(V); - if (VPI && !VPI->hasResult()) - return; - Slots[V] = NextSlot++; } @@ -950,10 +1122,8 @@ void VPSlotTracker::assignSlots(const VPRegionBlock *Region) { void VPSlotTracker::assignSlots(const VPBasicBlock *VPBB) { for (const VPRecipeBase &Recipe : *VPBB) { - if (const auto *VPI = dyn_cast(&Recipe)) - assignSlot(VPI); - else if (const auto *VPIV = dyn_cast(&Recipe)) - assignSlot(VPIV->getVPValue()); + for (VPValue *Def : Recipe.definedValues()) + assignSlot(Def); } } @@ -962,10 +1132,6 @@ void VPSlotTracker::assignSlots(const VPlan &Plan) { for (const VPValue *V : Plan.VPExternalDefs) assignSlot(V); - for (auto &E : Plan.Value2VPValue) - if (!isa(E.second)) - assignSlot(E.second); - for (const VPValue *V : Plan.VPCBVs) assignSlot(V); diff --git a/llvm/lib/Transforms/Vectorize/VPlan.h b/llvm/lib/Transforms/Vectorize/VPlan.h index f07c94e7a3c7..2cce127cd4ce 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.h +++ b/llvm/lib/Transforms/Vectorize/VPlan.h @@ -51,13 +51,12 @@ namespace llvm { class BasicBlock; class DominatorTree; class InnerLoopVectorizer; -template class InterleaveGroup; class LoopInfo; class raw_ostream; +class RecurrenceDescriptor; class Value; class VPBasicBlock; class VPRegionBlock; -class VPSlotTracker; class VPlan; class VPlanSlp; @@ -66,10 +65,22 @@ class VPlanSlp; /// [1, 9) = {1, 2, 4, 8} struct VFRange { // A power of 2. - const unsigned Start; + const ElementCount Start; // Need not be a power of 2. If End <= Start range is empty. - unsigned End; + ElementCount End; + + bool isEmpty() const { + return End.getKnownMinValue() <= Start.getKnownMinValue(); + } + + VFRange(const ElementCount &Start, const ElementCount &End) + : Start(Start), End(End) { + assert(Start.isScalable() == End.isScalable() && + "Both Start and End should have the same scalable flag"); + assert(isPowerOf2_32(Start.getKnownMinValue()) && + "Expected Start to be a power of 2"); + } }; using VPlanPtr = std::unique_ptr; @@ -114,7 +125,7 @@ private: /// The vectorization factor. Each entry in the scalar map contains UF x VF /// scalar values. - unsigned VF; + ElementCount VF; /// The vector and scalar map storage. We use std::map and not DenseMap /// because insertions to DenseMap invalidate its iterators. @@ -125,7 +136,7 @@ private: public: /// Construct an empty map with the given unroll and vectorization factors. - VectorizerValueMap(unsigned UF, unsigned VF) : UF(UF), VF(VF) {} + VectorizerValueMap(unsigned UF, ElementCount VF) : UF(UF), VF(VF) {} /// \return True if the map has any vector entry for \p Key. bool hasAnyVectorValue(Value *Key) const { @@ -150,12 +161,14 @@ public: /// \return True if the map has a scalar entry for \p Key and \p Instance. bool hasScalarValue(Value *Key, const VPIteration &Instance) const { assert(Instance.Part < UF && "Queried Scalar Part is too large."); - assert(Instance.Lane < VF && "Queried Scalar Lane is too large."); + assert(Instance.Lane < VF.getKnownMinValue() && + "Queried Scalar Lane is too large."); + if (!hasAnyScalarValue(Key)) return false; const ScalarParts &Entry = ScalarMapStorage.find(Key)->second; assert(Entry.size() == UF && "ScalarParts has wrong dimensions."); - assert(Entry[Instance.Part].size() == VF && + assert(Entry[Instance.Part].size() == VF.getKnownMinValue() && "ScalarParts has wrong dimensions."); return Entry[Instance.Part][Instance.Lane] != nullptr; } @@ -194,7 +207,7 @@ public: // TODO: Consider storing uniform values only per-part, as they occupy // lane 0 only, keeping the other VF-1 redundant entries null. for (unsigned Part = 0; Part < UF; ++Part) - Entry[Part].resize(VF, nullptr); + Entry[Part].resize(VF.getKnownMinValue(), nullptr); ScalarMapStorage[Key] = Entry; } ScalarMapStorage[Key][Instance.Part][Instance.Lane] = Scalar; @@ -233,14 +246,15 @@ struct VPCallback { /// VPTransformState holds information passed down when "executing" a VPlan, /// needed for generating the output IR. struct VPTransformState { - VPTransformState(unsigned VF, unsigned UF, LoopInfo *LI, DominatorTree *DT, - IRBuilder<> &Builder, VectorizerValueMap &ValueMap, - InnerLoopVectorizer *ILV, VPCallback &Callback) - : VF(VF), UF(UF), Instance(), LI(LI), DT(DT), Builder(Builder), - ValueMap(ValueMap), ILV(ILV), Callback(Callback) {} + VPTransformState(ElementCount VF, unsigned UF, Loop *OrigLoop, LoopInfo *LI, + DominatorTree *DT, IRBuilder<> &Builder, + VectorizerValueMap &ValueMap, InnerLoopVectorizer *ILV, + VPCallback &Callback) + : VF(VF), UF(UF), Instance(), OrigLoop(OrigLoop), LI(LI), DT(DT), + Builder(Builder), ValueMap(ValueMap), ILV(ILV), Callback(Callback) {} /// The chosen Vectorization and Unroll Factors of the loop being vectorized. - unsigned VF; + ElementCount VF; unsigned UF; /// Hold the indices to generate specific scalar instructions. Null indicates @@ -255,6 +269,9 @@ struct VPTransformState { typedef SmallVector PerPartValuesTy; DenseMap PerPartOutput; + + using ScalarsPerPartValuesTy = SmallVector, 2>; + DenseMap PerPartScalars; } Data; /// Get the generated Value for a given VPValue and a given Part. Note that @@ -271,20 +288,21 @@ struct VPTransformState { } /// Get the generated Value for a given VPValue and given Part and Lane. - Value *get(VPValue *Def, const VPIteration &Instance) { - // If the Def is managed directly by VPTransformState, extract the lane from - // the relevant part. Note that currently only VPInstructions and external - // defs are managed by VPTransformState. Other Defs are still created by ILV - // and managed in its ValueMap. For those this method currently just - // delegates the call to ILV below. - if (Data.PerPartOutput.count(Def)) { - auto *VecPart = Data.PerPartOutput[Def][Instance.Part]; - // TODO: Cache created scalar values. - return Builder.CreateExtractElement(VecPart, - Builder.getInt32(Instance.Lane)); - } + Value *get(VPValue *Def, const VPIteration &Instance); + + bool hasVectorValue(VPValue *Def, unsigned Part) { + auto I = Data.PerPartOutput.find(Def); + return I != Data.PerPartOutput.end() && Part < I->second.size() && + I->second[Part]; + } - return Callback.getOrCreateScalarValue(VPValue2Value[Def], Instance); + bool hasScalarValue(VPValue *Def, VPIteration Instance) { + auto I = Data.PerPartScalars.find(Def); + if (I == Data.PerPartScalars.end()) + return false; + return Instance.Part < I->second.size() && + Instance.Lane < I->second[Instance.Part].size() && + I->second[Instance.Part][Instance.Lane]; } /// Set the generated Value for a given VPValue and a given Part. @@ -295,6 +313,18 @@ struct VPTransformState { } Data.PerPartOutput[Def][Part] = V; } + void set(VPValue *Def, Value *IRDef, Value *V, unsigned Part); + + void set(VPValue *Def, Value *V, const VPIteration &Instance) { + auto Iter = Data.PerPartScalars.insert({Def, {}}); + auto &PerPartVec = Iter.first->second; + while (PerPartVec.size() <= Instance.Part) + PerPartVec.emplace_back(); + auto &Scalars = PerPartVec[Instance.Part]; + while (Scalars.size() <= Instance.Lane) + Scalars.push_back(nullptr); + Scalars[Instance.Lane] = V; + } /// Hold state information used when constructing the CFG of the output IR, /// traversing the VPBasicBlocks and generating corresponding IR BasicBlocks. @@ -321,6 +351,9 @@ struct VPTransformState { CFGState() = default; } CFG; + /// Hold a pointer to the original loop. + Loop *OrigLoop; + /// Hold a pointer to LoopInfo to register new basic blocks in the loop. LoopInfo *LI; @@ -394,14 +427,14 @@ class VPBlockBase { /// Remove \p Predecessor from the predecessors of this block. void removePredecessor(VPBlockBase *Predecessor) { - auto Pos = std::find(Predecessors.begin(), Predecessors.end(), Predecessor); + auto Pos = find(Predecessors, Predecessor); assert(Pos && "Predecessor does not exist"); Predecessors.erase(Pos); } /// Remove \p Successor from the successors of this block. void removeSuccessor(VPBlockBase *Successor) { - auto Pos = std::find(Successors.begin(), Successors.end(), Successor); + auto Pos = find(Successors, Successor); assert(Pos && "Successor does not exist"); Successors.erase(Pos); } @@ -594,49 +627,30 @@ public: // hoisted into a VPBlockBase. return true; } + + /// Replace all operands of VPUsers in the block with \p NewValue and also + /// replaces all uses of VPValues defined in the block with NewValue. + virtual void dropAllReferences(VPValue *NewValue) = 0; }; /// VPRecipeBase is a base class modeling a sequence of one or more output IR -/// instructions. -class VPRecipeBase : public ilist_node_with_parent { +/// instructions. VPRecipeBase owns the the VPValues it defines through VPDef +/// and is responsible for deleting its defined values. Single-value +/// VPRecipeBases that also inherit from VPValue must make sure to inherit from +/// VPRecipeBase before VPValue. +class VPRecipeBase : public ilist_node_with_parent, + public VPDef { friend VPBasicBlock; friend class VPBlockUtils; - const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). /// Each VPRecipe belongs to a single VPBasicBlock. VPBasicBlock *Parent = nullptr; public: - /// An enumeration for keeping track of the concrete subclass of VPRecipeBase - /// that is actually instantiated. Values of this enumeration are kept in the - /// SubclassID field of the VPRecipeBase objects. They are used for concrete - /// type identification. - using VPRecipeTy = enum { - VPBlendSC, - VPBranchOnMaskSC, - VPInstructionSC, - VPInterleaveSC, - VPPredInstPHISC, - VPReplicateSC, - VPWidenCallSC, - VPWidenCanonicalIVSC, - VPWidenGEPSC, - VPWidenIntOrFpInductionSC, - VPWidenMemoryInstructionSC, - VPWidenPHISC, - VPWidenSC, - VPWidenSelectSC - }; - - VPRecipeBase(const unsigned char SC) : SubclassID(SC) {} + VPRecipeBase(const unsigned char SC) : VPDef(SC) {} virtual ~VPRecipeBase() = default; - /// \return an ID for the concrete type of this object. - /// This is used to implement the classof checks. This should not be used - /// for any other purpose, as the values may change as LLVM evolves. - unsigned getVPRecipeID() const { return SubclassID; } - /// \return the VPBasicBlock which this VPRecipe belongs to. VPBasicBlock *getParent() { return Parent; } const VPBasicBlock *getParent() const { return Parent; } @@ -645,10 +659,6 @@ public: /// this VPRecipe, thereby "executing" the VPlan. virtual void execute(struct VPTransformState &State) = 0; - /// Each recipe prints itself. - virtual void print(raw_ostream &O, const Twine &Indent, - VPSlotTracker &SlotTracker) const = 0; - /// Insert an unlinked recipe into a basic block immediately before /// the specified recipe. void insertBefore(VPRecipeBase *InsertPos); @@ -661,6 +671,11 @@ public: /// the VPBasicBlock that MovePos lives in, right after MovePos. void moveAfter(VPRecipeBase *MovePos); + /// Unlink this recipe and insert into BB before I. + /// + /// \pre I is a valid iterator into BB. + void moveBefore(VPBasicBlock &BB, iplist::iterator I); + /// This method unlinks 'this' from the containing basic block, but does not /// delete it. void removeFromParent(); @@ -669,13 +684,46 @@ public: /// /// \returns an iterator pointing to the element after the erased one iplist::iterator eraseFromParent(); + + /// Returns a pointer to a VPUser, if the recipe inherits from VPUser or + /// nullptr otherwise. + VPUser *toVPUser(); + + /// Returns the underlying instruction, if the recipe is a VPValue or nullptr + /// otherwise. + Instruction *getUnderlyingInstr() { + return cast(getVPValue()->getUnderlyingValue()); + } + const Instruction *getUnderlyingInstr() const { + return cast(getVPValue()->getUnderlyingValue()); + } + + /// Method to support type inquiry through isa, cast, and dyn_cast. + static inline bool classof(const VPDef *D) { + // All VPDefs are also VPRecipeBases. + return true; + } }; +inline bool VPUser::classof(const VPDef *Def) { + return Def->getVPDefID() == VPRecipeBase::VPInstructionSC || + Def->getVPDefID() == VPRecipeBase::VPWidenSC || + Def->getVPDefID() == VPRecipeBase::VPWidenCallSC || + Def->getVPDefID() == VPRecipeBase::VPWidenSelectSC || + Def->getVPDefID() == VPRecipeBase::VPWidenGEPSC || + Def->getVPDefID() == VPRecipeBase::VPBlendSC || + Def->getVPDefID() == VPRecipeBase::VPInterleaveSC || + Def->getVPDefID() == VPRecipeBase::VPReplicateSC || + Def->getVPDefID() == VPRecipeBase::VPReductionSC || + Def->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC || + Def->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC; +} + /// This is a concrete Recipe that models a single VPlan-level instruction. /// While as any Recipe it may generate a sequence of IR instructions when /// executed, these instructions would always form a single-def expression as /// the VPInstruction is also a single def-use vertex. -class VPInstruction : public VPUser, public VPRecipeBase { +class VPInstruction : public VPRecipeBase, public VPUser, public VPValue { friend class VPlanSlp; public: @@ -697,23 +745,26 @@ private: void generateInstruction(VPTransformState &State, unsigned Part); protected: - Instruction *getUnderlyingInstr() { - return cast_or_null(getUnderlyingValue()); - } - void setUnderlyingInstr(Instruction *I) { setUnderlyingValue(I); } public: VPInstruction(unsigned Opcode, ArrayRef Operands) - : VPUser(VPValue::VPInstructionSC, Operands), - VPRecipeBase(VPRecipeBase::VPInstructionSC), Opcode(Opcode) {} + : VPRecipeBase(VPRecipeBase::VPInstructionSC), VPUser(Operands), + VPValue(VPValue::VPVInstructionSC, nullptr, this), Opcode(Opcode) {} + + VPInstruction(unsigned Opcode, ArrayRef Operands) + : VPRecipeBase(VPRecipeBase::VPInstructionSC), VPUser({}), + VPValue(VPValue::VPVInstructionSC, nullptr, this), Opcode(Opcode) { + for (auto *I : Operands) + addOperand(I->getVPValue()); + } VPInstruction(unsigned Opcode, std::initializer_list Operands) : VPInstruction(Opcode, ArrayRef(Operands)) {} /// Method to support type inquiry through isa, cast, and dyn_cast. static inline bool classof(const VPValue *V) { - return V->getVPValueID() == VPValue::VPInstructionSC; + return V->getVPValueID() == VPValue::VPVInstructionSC; } VPInstruction *clone() const { @@ -722,8 +773,8 @@ public: } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *R) { - return R->getVPRecipeID() == VPRecipeBase::VPInstructionSC; + static inline bool classof(const VPDef *R) { + return R->getVPDefID() == VPRecipeBase::VPInstructionSC; } unsigned getOpcode() const { return Opcode; } @@ -733,13 +784,12 @@ public: /// provided. void execute(VPTransformState &State) override; - /// Print the Recipe. + /// Print the VPInstruction to \p O. void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override; - /// Print the VPInstruction. - void print(raw_ostream &O) const; - void print(raw_ostream &O, VPSlotTracker &SlotTracker) const; + /// Print the VPInstruction to dbgs() (for debugging). + void dump() const; /// Return true if this instruction may modify memory. bool mayWriteToMemory() const { @@ -773,23 +823,21 @@ public: /// VPWidenRecipe is a recipe for producing a copy of vector type its /// ingredient. This recipe covers most of the traditional vectorization cases /// where each ingredient transforms into a vectorized version of itself. -class VPWidenRecipe : public VPRecipeBase { - /// Hold the instruction to be widened. - Instruction &Ingredient; - - /// Hold VPValues for the operands of the ingredient. - VPUser User; - +class VPWidenRecipe : public VPRecipeBase, public VPValue, public VPUser { public: template VPWidenRecipe(Instruction &I, iterator_range Operands) - : VPRecipeBase(VPWidenSC), Ingredient(I), User(Operands) {} + : VPRecipeBase(VPRecipeBase::VPWidenSC), + VPValue(VPValue::VPVWidenSC, &I, this), VPUser(Operands) {} ~VPWidenRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenSC; + } + static inline bool classof(const VPValue *V) { + return V->getVPValueID() == VPValue::VPVWidenSC; } /// Produce widened copies of all Ingredients. @@ -801,23 +849,19 @@ public: }; /// A recipe for widening Call instructions. -class VPWidenCallRecipe : public VPRecipeBase { - /// Hold the call to be widened. - CallInst &Ingredient; - - /// Hold VPValues for the arguments of the call. - VPUser User; +class VPWidenCallRecipe : public VPRecipeBase, public VPUser, public VPValue { public: template VPWidenCallRecipe(CallInst &I, iterator_range CallArguments) - : VPRecipeBase(VPWidenCallSC), Ingredient(I), User(CallArguments) {} + : VPRecipeBase(VPRecipeBase::VPWidenCallSC), VPUser(CallArguments), + VPValue(VPValue::VPVWidenCallSC, &I, this) {} ~VPWidenCallRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenCallSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenCallSC; } /// Produce a widened version of the call instruction. @@ -829,13 +873,7 @@ public: }; /// A recipe for widening select instructions. -class VPWidenSelectRecipe : public VPRecipeBase { -private: - /// Hold the select to be widened. - SelectInst &Ingredient; - - /// Hold VPValues for the operands of the select. - VPUser User; +class VPWidenSelectRecipe : public VPRecipeBase, public VPUser, public VPValue { /// Is the condition of the select loop invariant? bool InvariantCond; @@ -844,14 +882,15 @@ public: template VPWidenSelectRecipe(SelectInst &I, iterator_range Operands, bool InvariantCond) - : VPRecipeBase(VPWidenSelectSC), Ingredient(I), User(Operands), + : VPRecipeBase(VPRecipeBase::VPWidenSelectSC), VPUser(Operands), + VPValue(VPValue::VPVWidenSelectSC, &I, this), InvariantCond(InvariantCond) {} ~VPWidenSelectRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenSelectSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenSelectSC; } /// Produce a widened version of the select instruction. @@ -863,20 +902,24 @@ public: }; /// A recipe for handling GEP instructions. -class VPWidenGEPRecipe : public VPRecipeBase { - GetElementPtrInst *GEP; - - /// Hold VPValues for the base and indices of the GEP. - VPUser User; - +class VPWidenGEPRecipe : public VPRecipeBase, + public VPUser, + public VPValue { bool IsPtrLoopInvariant; SmallBitVector IsIndexLoopInvariant; public: + template + VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range Operands) + : VPRecipeBase(VPRecipeBase::VPWidenGEPSC), VPUser(Operands), + VPValue(VPWidenGEPSC, GEP, this), + IsIndexLoopInvariant(GEP->getNumIndices(), false) {} + template VPWidenGEPRecipe(GetElementPtrInst *GEP, iterator_range Operands, Loop *OrigLoop) - : VPRecipeBase(VPWidenGEPSC), GEP(GEP), User(Operands), + : VPRecipeBase(VPRecipeBase::VPWidenGEPSC), VPUser(Operands), + VPValue(VPValue::VPVWidenGEPSC, GEP, this), IsIndexLoopInvariant(GEP->getNumIndices(), false) { IsPtrLoopInvariant = OrigLoop->isLoopInvariant(GEP->getPointerOperand()); for (auto Index : enumerate(GEP->indices())) @@ -886,8 +929,8 @@ public: ~VPWidenGEPRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenGEPSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenGEPSC; } /// Generate the gep nodes. @@ -900,18 +943,25 @@ public: /// A recipe for handling phi nodes of integer and floating-point inductions, /// producing their vector and scalar values. -class VPWidenIntOrFpInductionRecipe : public VPRecipeBase { +class VPWidenIntOrFpInductionRecipe : public VPRecipeBase, public VPUser { PHINode *IV; TruncInst *Trunc; public: - VPWidenIntOrFpInductionRecipe(PHINode *IV, TruncInst *Trunc = nullptr) - : VPRecipeBase(VPWidenIntOrFpInductionSC), IV(IV), Trunc(Trunc) {} + VPWidenIntOrFpInductionRecipe(PHINode *IV, VPValue *Start, + TruncInst *Trunc = nullptr) + : VPRecipeBase(VPWidenIntOrFpInductionSC), VPUser({Start}), IV(IV), + Trunc(Trunc) { + if (Trunc) + new VPValue(Trunc, this); + else + new VPValue(IV, this); + } ~VPWidenIntOrFpInductionRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenIntOrFpInductionSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenIntOrFpInductionSC; } /// Generate the vectorized and scalarized versions of the phi node as @@ -921,19 +971,38 @@ public: /// Print the recipe. void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override; + + /// Returns the start value of the induction. + VPValue *getStartValue() { return getOperand(0); } }; /// A recipe for handling all phi nodes except for integer and FP inductions. -class VPWidenPHIRecipe : public VPRecipeBase { +/// For reduction PHIs, RdxDesc must point to the corresponding recurrence +/// descriptor and the start value is the first operand of the recipe. +class VPWidenPHIRecipe : public VPRecipeBase, public VPUser { PHINode *Phi; + /// Descriptor for a reduction PHI. + RecurrenceDescriptor *RdxDesc = nullptr; + public: - VPWidenPHIRecipe(PHINode *Phi) : VPRecipeBase(VPWidenPHISC), Phi(Phi) {} + /// Create a new VPWidenPHIRecipe for the reduction \p Phi described by \p + /// RdxDesc. + VPWidenPHIRecipe(PHINode *Phi, RecurrenceDescriptor &RdxDesc, VPValue &Start) + : VPWidenPHIRecipe(Phi) { + this->RdxDesc = &RdxDesc; + addOperand(&Start); + } + + /// Create a VPWidenPHIRecipe for \p Phi + VPWidenPHIRecipe(PHINode *Phi) : VPRecipeBase(VPWidenPHISC), Phi(Phi) { + new VPValue(Phi, this); + } ~VPWidenPHIRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenPHISC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenPHISC; } /// Generate the phi/select nodes. @@ -942,21 +1011,25 @@ public: /// Print the recipe. void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override; + + /// Returns the start value of the phi, if it is a reduction. + VPValue *getStartValue() { + return getNumOperands() == 0 ? nullptr : getOperand(0); + } }; /// A recipe for vectorizing a phi-node as a sequence of mask-based select /// instructions. -class VPBlendRecipe : public VPRecipeBase { +class VPBlendRecipe : public VPRecipeBase, public VPUser { PHINode *Phi; +public: /// The blend operation is a User of the incoming values and of their /// respective masks, ordered [I0, M0, I1, M1, ...]. Note that a single value /// might be incoming with a full mask for which there is no VPValue. - VPUser User; - -public: VPBlendRecipe(PHINode *Phi, ArrayRef Operands) - : VPRecipeBase(VPBlendSC), Phi(Phi), User(Operands) { + : VPRecipeBase(VPBlendSC), VPUser(Operands), Phi(Phi) { + new VPValue(Phi, this); assert(Operands.size() > 0 && ((Operands.size() == 1) || (Operands.size() % 2 == 0)) && "Expected either a single incoming value or a positive even number " @@ -964,23 +1037,19 @@ public: } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPBlendSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPBlendSC; } /// Return the number of incoming values, taking into account that a single /// incoming value has no mask. - unsigned getNumIncomingValues() const { - return (User.getNumOperands() + 1) / 2; - } + unsigned getNumIncomingValues() const { return (getNumOperands() + 1) / 2; } /// Return incoming value number \p Idx. - VPValue *getIncomingValue(unsigned Idx) const { - return User.getOperand(Idx * 2); - } + VPValue *getIncomingValue(unsigned Idx) const { return getOperand(Idx * 2); } /// Return mask number \p Idx. - VPValue *getMask(unsigned Idx) const { return User.getOperand(Idx * 2 + 1); } + VPValue *getMask(unsigned Idx) const { return getOperand(Idx * 2 + 1); } /// Generate the phi/select nodes. void execute(VPTransformState &State) override; @@ -991,35 +1060,58 @@ public: }; /// VPInterleaveRecipe is a recipe for transforming an interleave group of load -/// or stores into one wide load/store and shuffles. -class VPInterleaveRecipe : public VPRecipeBase { +/// or stores into one wide load/store and shuffles. The first operand of a +/// VPInterleave recipe is the address, followed by the stored values, followed +/// by an optional mask. +class VPInterleaveRecipe : public VPRecipeBase, public VPUser { const InterleaveGroup *IG; - VPUser User; + + bool HasMask = false; public: VPInterleaveRecipe(const InterleaveGroup *IG, VPValue *Addr, - VPValue *Mask) - : VPRecipeBase(VPInterleaveSC), IG(IG), User({Addr}) { - if (Mask) - User.addOperand(Mask); + ArrayRef StoredValues, VPValue *Mask) + : VPRecipeBase(VPInterleaveSC), VPUser(Addr), IG(IG) { + for (unsigned i = 0; i < IG->getFactor(); ++i) + if (Instruction *I = IG->getMember(i)) { + if (I->getType()->isVoidTy()) + continue; + new VPValue(I, this); + } + + for (auto *SV : StoredValues) + addOperand(SV); + if (Mask) { + HasMask = true; + addOperand(Mask); + } } ~VPInterleaveRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPInterleaveSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPInterleaveSC; } /// Return the address accessed by this recipe. VPValue *getAddr() const { - return User.getOperand(0); // Address is the 1st, mandatory operand. + return getOperand(0); // Address is the 1st, mandatory operand. } /// Return the mask used by this recipe. Note that a full mask is represented /// by a nullptr. VPValue *getMask() const { // Mask is optional and therefore the last, currently 2nd operand. - return User.getNumOperands() == 2 ? User.getOperand(1) : nullptr; + return HasMask ? getOperand(getNumOperands() - 1) : nullptr; + } + + /// Return the VPValues stored by this interleave group. If it is a load + /// interleave group, return an empty ArrayRef. + ArrayRef getStoredValues() const { + // The first operand is the address, followed by the stored values, followed + // by an optional mask. + return ArrayRef(op_begin(), getNumOperands()) + .slice(1, getNumOperands() - (HasMask ? 2 : 1)); } /// Generate the wide load or store, and shuffles. @@ -1032,17 +1124,61 @@ public: const InterleaveGroup *getInterleaveGroup() { return IG; } }; +/// A recipe to represent inloop reduction operations, performing a reduction on +/// a vector operand into a scalar value, and adding the result to a chain. +/// The Operands are {ChainOp, VecOp, [Condition]}. +class VPReductionRecipe : public VPRecipeBase, public VPUser, public VPValue { + /// The recurrence decriptor for the reduction in question. + RecurrenceDescriptor *RdxDesc; + /// Fast math flags to use for the resulting reduction operation. + bool NoNaN; + /// Pointer to the TTI, needed to create the target reduction + const TargetTransformInfo *TTI; + +public: + VPReductionRecipe(RecurrenceDescriptor *R, Instruction *I, VPValue *ChainOp, + VPValue *VecOp, VPValue *CondOp, bool NoNaN, + const TargetTransformInfo *TTI) + : VPRecipeBase(VPRecipeBase::VPReductionSC), VPUser({ChainOp, VecOp}), + VPValue(VPValue::VPVReductionSC, I, this), RdxDesc(R), NoNaN(NoNaN), + TTI(TTI) { + if (CondOp) + addOperand(CondOp); + } + + ~VPReductionRecipe() override = default; + + /// Method to support type inquiry through isa, cast, and dyn_cast. + static inline bool classof(const VPValue *V) { + return V->getVPValueID() == VPValue::VPVReductionSC; + } + + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPReductionSC; + } + + /// Generate the reduction in the loop + void execute(VPTransformState &State) override; + + /// Print the recipe. + void print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const override; + + /// The VPValue of the scalar Chain being accumulated. + VPValue *getChainOp() const { return getOperand(0); } + /// The VPValue of the vector value to be reduced. + VPValue *getVecOp() const { return getOperand(1); } + /// The VPValue of the condition for the block. + VPValue *getCondOp() const { + return getNumOperands() > 2 ? getOperand(2) : nullptr; + } +}; + /// VPReplicateRecipe replicates a given instruction producing multiple scalar /// copies of the original scalar type, one per lane, instead of producing a /// single copy of widened type for all lanes. If the instruction is known to be /// uniform only one copy, per lane zero, will be generated. -class VPReplicateRecipe : public VPRecipeBase { - /// The instruction being replicated. - Instruction *Ingredient; - - /// Hold VPValues for the operands of the ingredient. - VPUser User; - +class VPReplicateRecipe : public VPRecipeBase, public VPUser, public VPValue { /// Indicator if only a single replica per lane is needed. bool IsUniform; @@ -1056,8 +1192,9 @@ public: template VPReplicateRecipe(Instruction *I, iterator_range Operands, bool IsUniform, bool IsPredicated = false) - : VPRecipeBase(VPReplicateSC), Ingredient(I), User(Operands), - IsUniform(IsUniform), IsPredicated(IsPredicated) { + : VPRecipeBase(VPReplicateSC), VPUser(Operands), + VPValue(VPVReplicateSC, I, this), IsUniform(IsUniform), + IsPredicated(IsPredicated) { // Retain the previous behavior of predicateInstructions(), where an // insert-element of a predicated instruction got hoisted into the // predicated basic block iff it was its only user. This is achieved by @@ -1069,8 +1206,12 @@ public: ~VPReplicateRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPReplicateSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPReplicateSC; + } + + static inline bool classof(const VPValue *V) { + return V->getVPValueID() == VPValue::VPVReplicateSC; } /// Generate replicas of the desired Ingredient. Replicas will be generated @@ -1083,21 +1224,21 @@ public: /// Print the recipe. void print(raw_ostream &O, const Twine &Indent, VPSlotTracker &SlotTracker) const override; + + bool isUniform() const { return IsUniform; } }; /// A recipe for generating conditional branches on the bits of a mask. -class VPBranchOnMaskRecipe : public VPRecipeBase { - VPUser User; - +class VPBranchOnMaskRecipe : public VPRecipeBase, public VPUser { public: VPBranchOnMaskRecipe(VPValue *BlockInMask) : VPRecipeBase(VPBranchOnMaskSC) { if (BlockInMask) // nullptr means all-one mask. - User.addOperand(BlockInMask); + addOperand(BlockInMask); } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPBranchOnMaskSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPBranchOnMaskSC; } /// Generate the extraction of the appropriate bit from the block mask and the @@ -1109,7 +1250,7 @@ public: VPSlotTracker &SlotTracker) const override { O << " +\n" << Indent << "\"BRANCH-ON-MASK "; if (VPValue *Mask = getMask()) - Mask->print(O, SlotTracker); + Mask->printAsOperand(O, SlotTracker); else O << " All-One"; O << "\\l\""; @@ -1118,9 +1259,9 @@ public: /// Return the mask used by this recipe. Note that a full mask is represented /// by a nullptr. VPValue *getMask() const { - assert(User.getNumOperands() <= 1 && "should have either 0 or 1 operands"); + assert(getNumOperands() <= 1 && "should have either 0 or 1 operands"); // Mask is optional. - return User.getNumOperands() == 1 ? User.getOperand(0) : nullptr; + return getNumOperands() == 1 ? getOperand(0) : nullptr; } }; @@ -1129,19 +1270,20 @@ public: /// order to merge values that are set under such a branch and feed their uses. /// The phi nodes can be scalar or vector depending on the users of the value. /// This recipe works in concert with VPBranchOnMaskRecipe. -class VPPredInstPHIRecipe : public VPRecipeBase { - Instruction *PredInst; +class VPPredInstPHIRecipe : public VPRecipeBase, public VPUser { public: /// Construct a VPPredInstPHIRecipe given \p PredInst whose value needs a phi /// nodes after merging back from a Branch-on-Mask. - VPPredInstPHIRecipe(Instruction *PredInst) - : VPRecipeBase(VPPredInstPHISC), PredInst(PredInst) {} + VPPredInstPHIRecipe(VPValue *PredV) + : VPRecipeBase(VPPredInstPHISC), VPUser(PredV) { + new VPValue(PredV->getUnderlyingValue(), this); + } ~VPPredInstPHIRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPPredInstPHISC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPPredInstPHISC; } /// Generates phi nodes for live-outs as needed to retain SSA form. @@ -1158,56 +1300,59 @@ public: /// - For store: Address, stored value, optional mask /// TODO: We currently execute only per-part unless a specific instance is /// provided. -class VPWidenMemoryInstructionRecipe : public VPRecipeBase { - Instruction &Instr; - VPUser User; +class VPWidenMemoryInstructionRecipe : public VPRecipeBase, + public VPUser { + Instruction &Ingredient; void setMask(VPValue *Mask) { if (!Mask) return; - User.addOperand(Mask); + addOperand(Mask); } bool isMasked() const { - return (isa(Instr) && User.getNumOperands() == 2) || - (isa(Instr) && User.getNumOperands() == 3); + return isStore() ? getNumOperands() == 3 : getNumOperands() == 2; } public: VPWidenMemoryInstructionRecipe(LoadInst &Load, VPValue *Addr, VPValue *Mask) - : VPRecipeBase(VPWidenMemoryInstructionSC), Instr(Load), User({Addr}) { + : VPRecipeBase(VPWidenMemoryInstructionSC), VPUser({Addr}), + Ingredient(Load) { + new VPValue(VPValue::VPVMemoryInstructionSC, &Load, this); setMask(Mask); } VPWidenMemoryInstructionRecipe(StoreInst &Store, VPValue *Addr, VPValue *StoredValue, VPValue *Mask) - : VPRecipeBase(VPWidenMemoryInstructionSC), Instr(Store), - User({Addr, StoredValue}) { + : VPRecipeBase(VPWidenMemoryInstructionSC), VPUser({Addr, StoredValue}), + Ingredient(Store) { setMask(Mask); } /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenMemoryInstructionSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenMemoryInstructionSC; } /// Return the address accessed by this recipe. VPValue *getAddr() const { - return User.getOperand(0); // Address is the 1st, mandatory operand. + return getOperand(0); // Address is the 1st, mandatory operand. } /// Return the mask used by this recipe. Note that a full mask is represented /// by a nullptr. VPValue *getMask() const { // Mask is optional and therefore the last operand. - return isMasked() ? User.getOperand(User.getNumOperands() - 1) : nullptr; + return isMasked() ? getOperand(getNumOperands() - 1) : nullptr; } + /// Returns true if this recipe is a store. + bool isStore() const { return isa(Ingredient); } + /// Return the address accessed by this recipe. VPValue *getStoredValue() const { - assert(isa(Instr) && - "Stored value only available for store instructions"); - return User.getOperand(1); // Stored value is the 2nd, mandatory operand. + assert(isStore() && "Stored value only available for store instructions"); + return getOperand(1); // Stored value is the 2nd, mandatory operand. } /// Generate the wide load/store. @@ -1220,21 +1365,16 @@ public: /// A Recipe for widening the canonical induction variable of the vector loop. class VPWidenCanonicalIVRecipe : public VPRecipeBase { - /// A VPValue representing the canonical vector IV. - VPValue Val; - public: - VPWidenCanonicalIVRecipe() : VPRecipeBase(VPWidenCanonicalIVSC) {} - ~VPWidenCanonicalIVRecipe() override = default; + VPWidenCanonicalIVRecipe() : VPRecipeBase(VPWidenCanonicalIVSC) { + new VPValue(nullptr, this); + } - /// Return the VPValue representing the canonical vector induction variable of - /// the vector loop. - const VPValue *getVPValue() const { return &Val; } - VPValue *getVPValue() { return &Val; } + ~VPWidenCanonicalIVRecipe() override = default; /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPRecipeBase *V) { - return V->getVPRecipeID() == VPRecipeBase::VPWidenCanonicalIVSC; + static inline bool classof(const VPDef *D) { + return D->getVPDefID() == VPRecipeBase::VPWidenCanonicalIVSC; } /// Generate a canonical vector induction variable of the vector loop, with @@ -1321,6 +1461,11 @@ public: /// this VPBasicBlock, thereby "executing" the VPlan. void execute(struct VPTransformState *State) override; + /// Return the position of the first non-phi node recipe in the block. + iterator getFirstNonPhi(); + + void dropAllReferences(VPValue *NewValue) override; + private: /// Create an IR BasicBlock to hold the output instructions generated by this /// VPBasicBlock, and return it. Update the CFGState accordingly. @@ -1361,8 +1506,11 @@ public: IsReplicator(IsReplicator) {} ~VPRegionBlock() override { - if (Entry) + if (Entry) { + VPValue DummyValue; + Entry->dropAllReferences(&DummyValue); deleteCFG(Entry); + } } /// Method to support type inquiry through isa, cast, and dyn_cast. @@ -1407,6 +1555,8 @@ public: /// The method which generates the output IR instructions that correspond to /// this VPRegionBlock, thereby "executing" the VPlan. void execute(struct VPTransformState *State) override; + + void dropAllReferences(VPValue *NewValue) override; }; //===----------------------------------------------------------------------===// @@ -1544,7 +1694,7 @@ class VPlan { VPBlockBase *Entry; /// Holds the VFs applicable to this VPlan. - SmallSet VFs; + SmallSetVector VFs; /// Holds the name of the VPlan, for printing. std::string Name; @@ -1564,6 +1714,10 @@ class VPlan { /// VPlan. Value2VPValueTy Value2VPValue; + /// Contains all VPValues that been allocated by addVPValue directly and need + /// to be free when the plan's destructor is called. + SmallVector VPValuesToFree; + /// Holds the VPLoopInfo analysis for this VPlan. VPLoopInfo VPLInfo; @@ -1577,10 +1731,15 @@ public: } ~VPlan() { - if (Entry) + if (Entry) { + VPValue DummyValue; + for (VPBlockBase *Block : depth_first(Entry)) + Block->dropAllReferences(&DummyValue); + VPBlockBase::deleteCFG(Entry); - for (auto &MapEntry : Value2VPValue) - delete MapEntry.second; + } + for (VPValue *VPV : VPValuesToFree) + delete VPV; if (BackedgeTakenCount) delete BackedgeTakenCount; for (VPValue *Def : VPExternalDefs) @@ -1608,9 +1767,9 @@ public: return BackedgeTakenCount; } - void addVF(unsigned VF) { VFs.insert(VF); } + void addVF(ElementCount VF) { VFs.insert(VF); } - bool hasVF(unsigned VF) { return VFs.count(VF); } + bool hasVF(ElementCount VF) { return VFs.count(VF); } const std::string &getName() const { return Name; } @@ -1630,7 +1789,15 @@ public: void addVPValue(Value *V) { assert(V && "Trying to add a null Value to VPlan"); assert(!Value2VPValue.count(V) && "Value already exists in VPlan"); - Value2VPValue[V] = new VPValue(V); + VPValue *VPV = new VPValue(V); + Value2VPValue[V] = VPV; + VPValuesToFree.push_back(VPV); + } + + void addVPValue(Value *V, VPValue *VPV) { + assert(V && "Trying to add a null Value to VPlan"); + assert(!Value2VPValue.count(V) && "Value already exists in VPlan"); + Value2VPValue[V] = VPV; } VPValue *getVPValue(Value *V) { @@ -1646,6 +1813,8 @@ public: return getVPValue(V); } + void removeVPValueFor(Value *V) { Value2VPValue.erase(V); } + /// Return the VPLoopInfo analysis for this VPlan. VPLoopInfo &getVPLoopInfo() { return VPLInfo; } const VPLoopInfo &getVPLoopInfo() const { return VPLInfo; } @@ -1723,13 +1892,13 @@ private: void dump(); - static void printAsIngredient(raw_ostream &O, Value *V); + static void printAsIngredient(raw_ostream &O, const Value *V); }; struct VPlanIngredient { - Value *V; + const Value *V; - VPlanIngredient(Value *V) : V(V) {} + VPlanIngredient(const Value *V) : V(V) {} }; inline raw_ostream &operator<<(raw_ostream &OS, const VPlanIngredient &I) { @@ -1879,9 +2048,7 @@ public: /// \returns nullptr if doesn't have such group. InterleaveGroup * getInterleaveGroup(VPInstruction *Instr) const { - if (InterleaveGroupMap.count(Instr)) - return InterleaveGroupMap.find(Instr)->second; - return nullptr; + return InterleaveGroupMap.lookup(Instr); } }; @@ -1965,10 +2132,7 @@ class VPlanSlp { public: VPlanSlp(VPInterleavedAccessInfo &IAI, VPBasicBlock &BB) : IAI(IAI), BB(BB) {} - ~VPlanSlp() { - for (auto &KV : BundleToCombined) - delete KV.second; - } + ~VPlanSlp() = default; /// Tries to build an SLP tree rooted at \p Operands and returns a /// VPInstruction combining \p Operands, if they can be combined. diff --git a/llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp b/llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp index 7a80f3ff80a5..ac3b3505dc34 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanPredicator.cpp @@ -191,7 +191,7 @@ void VPlanPredicator::predicateRegionRec(VPRegionBlock *Region) { // Generate edge predicates and append them to the block predicate. RPO is // necessary since the predecessor blocks' block predicate needs to be set // before the current block's block predicate can be computed. - for (VPBlockBase *Block : make_range(RPOT.begin(), RPOT.end())) { + for (VPBlockBase *Block : RPOT) { // TODO: Handle nested regions once we start generating the same. assert(!isa(Block) && "Nested region not expected"); createOrPropagatePredicates(Block, Region); @@ -208,7 +208,7 @@ void VPlanPredicator::linearizeRegionRec(VPRegionBlock *Region) { ReversePostOrderTraversal RPOT(Region->getEntry()); VPBlockBase *PrevBlock = nullptr; - for (VPBlockBase *CurrBlock : make_range(RPOT.begin(), RPOT.end())) { + for (VPBlockBase *CurrBlock : RPOT) { // TODO: Handle nested regions once we start generating the same. assert(!isa(CurrBlock) && "Nested region not expected"); diff --git a/llvm/lib/Transforms/Vectorize/VPlanSLP.cpp b/llvm/lib/Transforms/Vectorize/VPlanSLP.cpp index 9019ed15ec5f..6f21bf44291a 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanSLP.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanSLP.cpp @@ -124,7 +124,7 @@ bool VPlanSlp::areVectorizable(ArrayRef Operands) const { for (auto &I : *Parent) { auto *VPI = cast(&I); if (VPI->getOpcode() == Instruction::Load && - std::find(Operands.begin(), Operands.end(), VPI) != Operands.end()) + llvm::is_contained(Operands, VPI)) LoadsSeen++; if (LoadsSeen == Operands.size()) @@ -161,7 +161,8 @@ static SmallVector getOperands(ArrayRef Values, unsigned OperandIndex) { SmallVector Operands; for (VPValue *V : Values) { - auto *U = cast(V); + // Currently we only support VPInstructions. + auto *U = cast(V); Operands.push_back(U->getOperand(OperandIndex)); } return Operands; @@ -222,18 +223,20 @@ static bool areConsecutiveOrMatch(VPInstruction *A, VPInstruction *B, /// Traverses and compares operands of V1 and V2 to MaxLevel. static unsigned getLAScore(VPValue *V1, VPValue *V2, unsigned MaxLevel, VPInterleavedAccessInfo &IAI) { - if (!isa(V1) || !isa(V2)) + auto *I1 = dyn_cast(V1); + auto *I2 = dyn_cast(V2); + // Currently we only support VPInstructions. + if (!I1 || !I2) return 0; if (MaxLevel == 0) - return (unsigned)areConsecutiveOrMatch(cast(V1), - cast(V2), IAI); + return (unsigned)areConsecutiveOrMatch(I1, I2, IAI); unsigned Score = 0; - for (unsigned I = 0, EV1 = cast(V1)->getNumOperands(); I < EV1; ++I) - for (unsigned J = 0, EV2 = cast(V2)->getNumOperands(); J < EV2; ++J) - Score += getLAScore(cast(V1)->getOperand(I), - cast(V2)->getOperand(J), MaxLevel - 1, IAI); + for (unsigned I = 0, EV1 = I1->getNumOperands(); I < EV1; ++I) + for (unsigned J = 0, EV2 = I2->getNumOperands(); J < EV2; ++J) + Score += + getLAScore(I1->getOperand(I), I2->getOperand(J), MaxLevel - 1, IAI); return Score; } @@ -463,8 +466,8 @@ VPInstruction *VPlanSlp::buildGraph(ArrayRef Values) { auto *VPI = new VPInstruction(Opcode, CombinedOperands); VPI->setUnderlyingInstr(cast(Values[0])->getUnderlyingInstr()); - LLVM_DEBUG(dbgs() << "Create VPInstruction "; VPI->print(dbgs()); - cast(Values[0])->print(dbgs()); dbgs() << "\n"); + LLVM_DEBUG(dbgs() << "Create VPInstruction " << *VPI << " " + << *cast(Values[0]) << "\n"); addCombined(Values, VPI); return VPI; } diff --git a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp index 3a4872a72122..1a54603faf22 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanTransforms.cpp @@ -48,6 +48,8 @@ void VPlanTransforms::VPInstructionsToVPRecipes( VPInstruction *VPInst = cast(Ingredient); Instruction *Inst = cast(VPInst->getUnderlyingValue()); if (DeadInstructions.count(Inst)) { + VPValue DummyValue; + VPInst->replaceAllUsesWith(&DummyValue); Ingredient->eraseFromParent(); continue; } @@ -66,7 +68,8 @@ void VPlanTransforms::VPInstructionsToVPRecipes( InductionDescriptor II = Inductions.lookup(Phi); if (II.getKind() == InductionDescriptor::IK_IntInduction || II.getKind() == InductionDescriptor::IK_FpInduction) { - NewRecipe = new VPWidenIntOrFpInductionRecipe(Phi); + VPValue *Start = Plan->getOrAddVPValue(II.getStartValue()); + NewRecipe = new VPWidenIntOrFpInductionRecipe(Phi, Start); } else NewRecipe = new VPWidenPHIRecipe(Phi); } else if (GetElementPtrInst *GEP = dyn_cast(Inst)) { @@ -77,6 +80,11 @@ void VPlanTransforms::VPInstructionsToVPRecipes( new VPWidenRecipe(*Inst, Plan->mapToVPValues(Inst->operands())); NewRecipe->insertBefore(Ingredient); + if (NewRecipe->getNumDefinedValues() == 1) + VPInst->replaceAllUsesWith(NewRecipe->getVPValue()); + else + assert(NewRecipe->getNumDefinedValues() == 0 && + "Only recpies with zero or one defined values expected"); Ingredient->eraseFromParent(); } } diff --git a/llvm/lib/Transforms/Vectorize/VPlanValue.h b/llvm/lib/Transforms/Vectorize/VPlanValue.h index f73505d0279a..ed572ca36627 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanValue.h +++ b/llvm/lib/Transforms/Vectorize/VPlanValue.h @@ -10,9 +10,9 @@ /// This file contains the declarations of the entities induced by Vectorization /// Plans, e.g. the instructions the VPlan intends to generate if executed. /// VPlan models the following entities: -/// VPValue -/// |-- VPUser -/// | |-- VPInstruction +/// VPValue VPUser VPDef +/// | | +/// VPInstruction /// These are documented in docs/VectorizationPlan.rst. /// //===----------------------------------------------------------------------===// @@ -21,7 +21,9 @@ #define LLVM_TRANSFORMS_VECTORIZE_VPLAN_VALUE_H #include "llvm/ADT/DenseMap.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/iterator_range.h" namespace llvm { @@ -29,8 +31,11 @@ namespace llvm { // Forward declarations. class raw_ostream; class Value; +class VPDef; class VPSlotTracker; class VPUser; +class VPRecipeBase; +class VPWidenMemoryInstructionRecipe; // This is the base class of the VPlan Def/Use graph, used for modeling the data // flow into, within and out of the VPlan. VPValues can stand for live-ins @@ -38,10 +43,14 @@ class VPUser; // and live-outs which the VPlan will need to fix accordingly. class VPValue { friend class VPBuilder; + friend class VPDef; + friend class VPInstruction; friend struct VPlanTransforms; friend class VPBasicBlock; friend class VPInterleavedAccessInfo; friend class VPSlotTracker; + friend class VPRecipeBase; + friend class VPWidenMemoryInstructionRecipe; const unsigned char SubclassID; ///< Subclass identifier (for isa/dyn_cast). @@ -51,8 +60,11 @@ protected: // Hold the underlying Value, if any, attached to this VPValue. Value *UnderlyingVal; - VPValue(const unsigned char SC, Value *UV = nullptr) - : SubclassID(SC), UnderlyingVal(UV) {} + /// Pointer to the VPDef that defines this VPValue. If it is nullptr, the + /// VPValue is not defined by any recipe modeled in VPlan. + VPDef *Def; + + VPValue(const unsigned char SC, Value *UV = nullptr, VPDef *Def = nullptr); // DESIGN PRINCIPLE: Access to the underlying IR must be strictly limited to // the front-end and back-end of VPlan so that the middle-end is as @@ -61,10 +73,6 @@ protected: // for multiple underlying IRs (Polly?) by providing a new VPlan front-end, // back-end and analysis information for the new IR. - /// Return the underlying Value attached to this VPValue. - Value *getUnderlyingValue() { return UnderlyingVal; } - const Value *getUnderlyingValue() const { return UnderlyingVal; } - // Set \p Val as the underlying Value of this VPValue. void setUnderlyingValue(Value *Val) { assert(!UnderlyingVal && "Underlying Value is already set."); @@ -72,16 +80,33 @@ protected: } public: + /// Return the underlying Value attached to this VPValue. + Value *getUnderlyingValue() { return UnderlyingVal; } + const Value *getUnderlyingValue() const { return UnderlyingVal; } + /// An enumeration for keeping track of the concrete subclass of VPValue that /// are actually instantiated. Values of this enumeration are kept in the /// SubclassID field of the VPValue objects. They are used for concrete /// type identification. - enum { VPValueSC, VPUserSC, VPInstructionSC }; - - VPValue(Value *UV = nullptr) : VPValue(VPValueSC, UV) {} + enum { + VPValueSC, + VPVInstructionSC, + VPVMemoryInstructionSC, + VPVReductionSC, + VPVReplicateSC, + VPVWidenSC, + VPVWidenCallSC, + VPVWidenGEPSC, + VPVWidenSelectSC, + }; + + VPValue(Value *UV = nullptr, VPDef *Def = nullptr) + : VPValue(VPValueSC, UV, Def) {} VPValue(const VPValue &) = delete; VPValue &operator=(const VPValue &) = delete; + virtual ~VPValue(); + /// \return an ID for the concrete type of this object. /// This is used to implement the classof checks. This should not be used /// for any other purpose, as the values may change as LLVM evolves. @@ -90,9 +115,28 @@ public: void printAsOperand(raw_ostream &OS, VPSlotTracker &Tracker) const; void print(raw_ostream &OS, VPSlotTracker &Tracker) const; + /// Dump the value to stderr (for debugging). + void dump() const; + unsigned getNumUsers() const { return Users.size(); } void addUser(VPUser &User) { Users.push_back(&User); } + /// Remove a single \p User from the list of users. + void removeUser(VPUser &User) { + bool Found = false; + // The same user can be added multiple times, e.g. because the same VPValue + // is used twice by the same VPUser. Remove a single one. + erase_if(Users, [&User, &Found](VPUser *Other) { + if (Found) + return false; + if (Other == &User) { + Found = true; + return true; + } + return false; + }); + } + typedef SmallVectorImpl::iterator user_iterator; typedef SmallVectorImpl::const_iterator const_user_iterator; typedef iterator_range user_range; @@ -120,6 +164,17 @@ public: } void replaceAllUsesWith(VPValue *New); + + VPDef *getDef() { return Def; } + + /// Returns the underlying IR value, if this VPValue is defined outside the + /// scope of VPlan. Returns nullptr if the VPValue is defined by a VPDef + /// inside a VPlan. + Value *getLiveInIRValue() { + assert(!getDef() && + "VPValue is not a live-in; it is defined by a VPDef inside a VPlan"); + return getUnderlyingValue(); + } }; typedef DenseMap Value2VPValueTy; @@ -129,34 +184,32 @@ raw_ostream &operator<<(raw_ostream &OS, const VPValue &V); /// This class augments VPValue with operands which provide the inverse def-use /// edges from VPValue's users to their defs. -class VPUser : public VPValue { +class VPUser { SmallVector Operands; protected: - VPUser(const unsigned char SC) : VPValue(SC) {} - VPUser(const unsigned char SC, ArrayRef Operands) : VPValue(SC) { + /// Print the operands to \p O. + void printOperands(raw_ostream &O, VPSlotTracker &SlotTracker) const; + +public: + VPUser() {} + VPUser(ArrayRef Operands) { for (VPValue *Operand : Operands) addOperand(Operand); } -public: - VPUser() : VPValue(VPValue::VPUserSC) {} - VPUser(ArrayRef Operands) : VPUser(VPValue::VPUserSC, Operands) {} VPUser(std::initializer_list Operands) : VPUser(ArrayRef(Operands)) {} - template - VPUser(iterator_range Operands) : VPValue(VPValue::VPUserSC) { + template VPUser(iterator_range Operands) { for (VPValue *Operand : Operands) addOperand(Operand); } VPUser(const VPUser &) = delete; VPUser &operator=(const VPUser &) = delete; - - /// Method to support type inquiry through isa, cast, and dyn_cast. - static inline bool classof(const VPValue *V) { - return V->getVPValueID() >= VPUserSC && - V->getVPValueID() <= VPInstructionSC; + virtual ~VPUser() { + for (VPValue *Op : operands()) + Op->removeUser(*this); } void addOperand(VPValue *Operand) { @@ -170,7 +223,11 @@ public: return Operands[N]; } - void setOperand(unsigned I, VPValue *New) { Operands[I] = New; } + void setOperand(unsigned I, VPValue *New) { + Operands[I]->removeUser(*this); + Operands[I] = New; + New->addUser(*this); + } typedef SmallVectorImpl::iterator operand_iterator; typedef SmallVectorImpl::const_iterator const_operand_iterator; @@ -185,7 +242,110 @@ public: const_operand_range operands() const { return const_operand_range(op_begin(), op_end()); } + + /// Method to support type inquiry through isa, cast, and dyn_cast. + static inline bool classof(const VPDef *Recipe); }; + +/// This class augments a recipe with a set of VPValues defined by the recipe. +/// It allows recipes to define zero, one or multiple VPValues. A VPDef owns +/// the VPValues it defines and is responsible for deleting its defined values. +/// Single-value VPDefs that also inherit from VPValue must make sure to inherit +/// from VPDef before VPValue. +class VPDef { + friend class VPValue; + + /// Subclass identifier (for isa/dyn_cast). + const unsigned char SubclassID; + + /// The VPValues defined by this VPDef. + TinyPtrVector DefinedValues; + + /// Add \p V as a defined value by this VPDef. + void addDefinedValue(VPValue *V) { + assert(V->getDef() == this && + "can only add VPValue already linked with this VPDef"); + DefinedValues.push_back(V); + } + + /// Remove \p V from the values defined by this VPDef. \p V must be a defined + /// value of this VPDef. + void removeDefinedValue(VPValue *V) { + assert(V->getDef() == this && + "can only remove VPValue linked with this VPDef"); + assert(is_contained(DefinedValues, V) && + "VPValue to remove must be in DefinedValues"); + erase_value(DefinedValues, V); + V->Def = nullptr; + } + +public: + /// An enumeration for keeping track of the concrete subclass of VPRecipeBase + /// that is actually instantiated. Values of this enumeration are kept in the + /// SubclassID field of the VPRecipeBase objects. They are used for concrete + /// type identification. + using VPRecipeTy = enum { + VPBlendSC, + VPBranchOnMaskSC, + VPInstructionSC, + VPInterleaveSC, + VPPredInstPHISC, + VPReductionSC, + VPReplicateSC, + VPWidenCallSC, + VPWidenCanonicalIVSC, + VPWidenGEPSC, + VPWidenIntOrFpInductionSC, + VPWidenMemoryInstructionSC, + VPWidenPHISC, + VPWidenSC, + VPWidenSelectSC + }; + + VPDef(const unsigned char SC) : SubclassID(SC) {} + + virtual ~VPDef() { + for (VPValue *D : make_early_inc_range(DefinedValues)) { + assert(D->Def == this && + "all defined VPValues should point to the containing VPDef"); + assert(D->getNumUsers() == 0 && + "all defined VPValues should have no more users"); + D->Def = nullptr; + delete D; + } + } + + /// Returns the VPValue with index \p I defined by the VPDef. + VPValue *getVPValue(unsigned I = 0) { + assert(DefinedValues[I] && "defined value must be non-null"); + return DefinedValues[I]; + } + const VPValue *getVPValue(unsigned I = 0) const { + assert(DefinedValues[I] && "defined value must be non-null"); + return DefinedValues[I]; + } + + /// Returns an ArrayRef of the values defined by the VPDef. + ArrayRef definedValues() { return DefinedValues; } + /// Returns an ArrayRef of the values defined by the VPDef. + ArrayRef definedValues() const { return DefinedValues; } + + /// Returns the number of values defined by the VPDef. + unsigned getNumDefinedValues() const { return DefinedValues.size(); } + + /// \return an ID for the concrete type of this object. + /// This is used to implement the classof checks. This should not be used + /// for any other purpose, as the values may change as LLVM evolves. + unsigned getVPDefID() const { return SubclassID; } + + /// Dump the VPDef to stderr (for debugging). + void dump() const; + + /// Each concrete VPDef prints itself. + virtual void print(raw_ostream &O, const Twine &Indent, + VPSlotTracker &SlotTracker) const = 0; +}; + class VPlan; class VPBasicBlock; class VPRegionBlock; @@ -205,7 +365,7 @@ class VPSlotTracker { void assignSlots(const VPlan &Plan); public: - VPSlotTracker(const VPlan *Plan) { + VPSlotTracker(const VPlan *Plan = nullptr) { if (Plan) assignSlots(*Plan); } diff --git a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp index b384c94121e9..6eec8d14de4a 100644 --- a/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlanVerifier.cpp @@ -65,9 +65,7 @@ static void verifyBlocksInRegion(const VPRegionBlock *Region) { for (const VPBlockBase *Succ : Successors) { // There must be a bi-directional link between block and successor. const auto &SuccPreds = Succ->getPredecessors(); - assert(std::find(SuccPreds.begin(), SuccPreds.end(), VPB) != - SuccPreds.end() && - "Missing predecessor link."); + assert(llvm::is_contained(SuccPreds, VPB) && "Missing predecessor link."); (void)SuccPreds; } @@ -86,9 +84,7 @@ static void verifyBlocksInRegion(const VPRegionBlock *Region) { // There must be a bi-directional link between block and predecessor. const auto &PredSuccs = Pred->getSuccessors(); - assert(std::find(PredSuccs.begin(), PredSuccs.end(), VPB) != - PredSuccs.end() && - "Missing successor link."); + assert(llvm::is_contained(PredSuccs, VPB) && "Missing successor link."); (void)PredSuccs; } } diff --git a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp index 64b41bf9cefa..787f146bdddc 100644 --- a/llvm/lib/Transforms/Vectorize/VectorCombine.cpp +++ b/llvm/lib/Transforms/Vectorize/VectorCombine.cpp @@ -16,6 +16,7 @@ #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/BasicAliasAnalysis.h" #include "llvm/Analysis/GlobalsModRef.h" +#include "llvm/Analysis/Loads.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/Analysis/VectorUtils.h" @@ -33,6 +34,7 @@ using namespace llvm; using namespace llvm::PatternMatch; #define DEBUG_TYPE "vector-combine" +STATISTIC(NumVecLoad, "Number of vector loads formed"); STATISTIC(NumVecCmp, "Number of vector compares formed"); STATISTIC(NumVecBO, "Number of vector binops formed"); STATISTIC(NumVecCmpBO, "Number of vector compare + binop formed"); @@ -65,6 +67,7 @@ private: const TargetTransformInfo &TTI; const DominatorTree &DT; + bool vectorizeLoadInsert(Instruction &I); ExtractElementInst *getShuffleExtract(ExtractElementInst *Ext0, ExtractElementInst *Ext1, unsigned PreferredExtractIndex) const; @@ -88,6 +91,138 @@ static void replaceValue(Value &Old, Value &New) { New.takeName(&Old); } +bool VectorCombine::vectorizeLoadInsert(Instruction &I) { + // Match insert into fixed vector of scalar value. + // TODO: Handle non-zero insert index. + auto *Ty = dyn_cast(I.getType()); + Value *Scalar; + if (!Ty || !match(&I, m_InsertElt(m_Undef(), m_Value(Scalar), m_ZeroInt())) || + !Scalar->hasOneUse()) + return false; + + // Optionally match an extract from another vector. + Value *X; + bool HasExtract = match(Scalar, m_ExtractElt(m_Value(X), m_ZeroInt())); + if (!HasExtract) + X = Scalar; + + // Match source value as load of scalar or vector. + // Do not vectorize scalar load (widening) if atomic/volatile or under + // asan/hwasan/memtag/tsan. The widened load may load data from dirty regions + // or create data races non-existent in the source. + auto *Load = dyn_cast(X); + if (!Load || !Load->isSimple() || !Load->hasOneUse() || + Load->getFunction()->hasFnAttribute(Attribute::SanitizeMemTag) || + mustSuppressSpeculation(*Load)) + return false; + + const DataLayout &DL = I.getModule()->getDataLayout(); + Value *SrcPtr = Load->getPointerOperand()->stripPointerCasts(); + assert(isa(SrcPtr->getType()) && "Expected a pointer type"); + + // If original AS != Load's AS, we can't bitcast the original pointer and have + // to use Load's operand instead. Ideally we would want to strip pointer casts + // without changing AS, but there's no API to do that ATM. + unsigned AS = Load->getPointerAddressSpace(); + if (AS != SrcPtr->getType()->getPointerAddressSpace()) + SrcPtr = Load->getPointerOperand(); + + // We are potentially transforming byte-sized (8-bit) memory accesses, so make + // sure we have all of our type-based constraints in place for this target. + Type *ScalarTy = Scalar->getType(); + uint64_t ScalarSize = ScalarTy->getPrimitiveSizeInBits(); + unsigned MinVectorSize = TTI.getMinVectorRegisterBitWidth(); + if (!ScalarSize || !MinVectorSize || MinVectorSize % ScalarSize != 0 || + ScalarSize % 8 != 0) + return false; + + // Check safety of replacing the scalar load with a larger vector load. + // We use minimal alignment (maximum flexibility) because we only care about + // the dereferenceable region. When calculating cost and creating a new op, + // we may use a larger value based on alignment attributes. + unsigned MinVecNumElts = MinVectorSize / ScalarSize; + auto *MinVecTy = VectorType::get(ScalarTy, MinVecNumElts, false); + unsigned OffsetEltIndex = 0; + Align Alignment = Load->getAlign(); + if (!isSafeToLoadUnconditionally(SrcPtr, MinVecTy, Align(1), DL, Load, &DT)) { + // It is not safe to load directly from the pointer, but we can still peek + // through gep offsets and check if it safe to load from a base address with + // updated alignment. If it is, we can shuffle the element(s) into place + // after loading. + unsigned OffsetBitWidth = DL.getIndexTypeSizeInBits(SrcPtr->getType()); + APInt Offset(OffsetBitWidth, 0); + SrcPtr = SrcPtr->stripAndAccumulateInBoundsConstantOffsets(DL, Offset); + + // We want to shuffle the result down from a high element of a vector, so + // the offset must be positive. + if (Offset.isNegative()) + return false; + + // The offset must be a multiple of the scalar element to shuffle cleanly + // in the element's size. + uint64_t ScalarSizeInBytes = ScalarSize / 8; + if (Offset.urem(ScalarSizeInBytes) != 0) + return false; + + // If we load MinVecNumElts, will our target element still be loaded? + OffsetEltIndex = Offset.udiv(ScalarSizeInBytes).getZExtValue(); + if (OffsetEltIndex >= MinVecNumElts) + return false; + + if (!isSafeToLoadUnconditionally(SrcPtr, MinVecTy, Align(1), DL, Load, &DT)) + return false; + + // Update alignment with offset value. Note that the offset could be negated + // to more accurately represent "(new) SrcPtr - Offset = (old) SrcPtr", but + // negation does not change the result of the alignment calculation. + Alignment = commonAlignment(Alignment, Offset.getZExtValue()); + } + + // Original pattern: insertelt undef, load [free casts of] PtrOp, 0 + // Use the greater of the alignment on the load or its source pointer. + Alignment = std::max(SrcPtr->getPointerAlignment(DL), Alignment); + Type *LoadTy = Load->getType(); + InstructionCost OldCost = + TTI.getMemoryOpCost(Instruction::Load, LoadTy, Alignment, AS); + APInt DemandedElts = APInt::getOneBitSet(MinVecNumElts, 0); + OldCost += TTI.getScalarizationOverhead(MinVecTy, DemandedElts, + /* Insert */ true, HasExtract); + + // New pattern: load VecPtr + InstructionCost NewCost = + TTI.getMemoryOpCost(Instruction::Load, MinVecTy, Alignment, AS); + // Optionally, we are shuffling the loaded vector element(s) into place. + if (OffsetEltIndex) + NewCost += TTI.getShuffleCost(TTI::SK_PermuteSingleSrc, MinVecTy); + + // We can aggressively convert to the vector form because the backend can + // invert this transform if it does not result in a performance win. + if (OldCost < NewCost || !NewCost.isValid()) + return false; + + // It is safe and potentially profitable to load a vector directly: + // inselt undef, load Scalar, 0 --> load VecPtr + IRBuilder<> Builder(Load); + Value *CastedPtr = Builder.CreateBitCast(SrcPtr, MinVecTy->getPointerTo(AS)); + Value *VecLd = Builder.CreateAlignedLoad(MinVecTy, CastedPtr, Alignment); + + // Set everything but element 0 to undef to prevent poison from propagating + // from the extra loaded memory. This will also optionally shrink/grow the + // vector from the loaded size to the output size. + // We assume this operation has no cost in codegen if there was no offset. + // Note that we could use freeze to avoid poison problems, but then we might + // still need a shuffle to change the vector size. + unsigned OutputNumElts = Ty->getNumElements(); + SmallVector Mask(OutputNumElts, UndefMaskElem); + assert(OffsetEltIndex < MinVecNumElts && "Address offset too big"); + Mask[0] = OffsetEltIndex; + VecLd = Builder.CreateShuffleVector(VecLd, Mask); + + replaceValue(I, *VecLd); + ++NumVecLoad; + return true; +} + /// Determine which, if any, of the inputs should be replaced by a shuffle /// followed by extract from a different index. ExtractElementInst *VectorCombine::getShuffleExtract( @@ -106,8 +241,14 @@ ExtractElementInst *VectorCombine::getShuffleExtract( Type *VecTy = Ext0->getVectorOperand()->getType(); assert(VecTy == Ext1->getVectorOperand()->getType() && "Need matching types"); - int Cost0 = TTI.getVectorInstrCost(Ext0->getOpcode(), VecTy, Index0); - int Cost1 = TTI.getVectorInstrCost(Ext1->getOpcode(), VecTy, Index1); + InstructionCost Cost0 = + TTI.getVectorInstrCost(Ext0->getOpcode(), VecTy, Index0); + InstructionCost Cost1 = + TTI.getVectorInstrCost(Ext1->getOpcode(), VecTy, Index1); + + // If both costs are invalid no shuffle is needed + if (!Cost0.isValid() && !Cost1.isValid()) + return nullptr; // We are extracting from 2 different indexes, so one operand must be shuffled // before performing a vector operation and/or extract. The more expensive @@ -143,7 +284,7 @@ bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0, "Expected constant extract indexes"); Type *ScalarTy = Ext0->getType(); auto *VecTy = cast(Ext0->getOperand(0)->getType()); - int ScalarOpCost, VectorOpCost; + InstructionCost ScalarOpCost, VectorOpCost; // Get cost estimates for scalar and vector versions of the operation. bool IsBinOp = Instruction::isBinaryOp(Opcode); @@ -164,9 +305,9 @@ bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0, unsigned Ext0Index = cast(Ext0->getOperand(1))->getZExtValue(); unsigned Ext1Index = cast(Ext1->getOperand(1))->getZExtValue(); - int Extract0Cost = + InstructionCost Extract0Cost = TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, Ext0Index); - int Extract1Cost = + InstructionCost Extract1Cost = TTI.getVectorInstrCost(Instruction::ExtractElement, VecTy, Ext1Index); // A more expensive extract will always be replaced by a splat shuffle. @@ -176,11 +317,11 @@ bool VectorCombine::isExtractExtractCheap(ExtractElementInst *Ext0, // TODO: Evaluate whether that always results in lowest cost. Alternatively, // check the cost of creating a broadcast shuffle and shuffling both // operands to element 0. - int CheapExtractCost = std::min(Extract0Cost, Extract1Cost); + InstructionCost CheapExtractCost = std::min(Extract0Cost, Extract1Cost); // Extra uses of the extracts mean that we include those costs in the // vector total because those instructions will not be eliminated. - int OldCost, NewCost; + InstructionCost OldCost, NewCost; if (Ext0->getOperand(0) == Ext1->getOperand(0) && Ext0Index == Ext1Index) { // Handle a special case. If the 2 extracts are identical, adjust the // formulas to account for that. The extra use charge allows for either the @@ -231,8 +372,7 @@ static Value *createShiftShuffle(Value *Vec, unsigned OldIndex, auto *VecTy = cast(Vec->getType()); SmallVector ShufMask(VecTy->getNumElements(), UndefMaskElem); ShufMask[NewIndex] = OldIndex; - Value *Undef = UndefValue::get(VecTy); - return Builder.CreateShuffleVector(Vec, Undef, ShufMask, "shift"); + return Builder.CreateShuffleVector(Vec, ShufMask, "shift"); } /// Given an extract element instruction with constant index operand, shuffle @@ -366,17 +506,23 @@ bool VectorCombine::foldBitcastShuf(Instruction &I) { m_OneUse(m_Shuffle(m_Value(V), m_Undef(), m_Mask(Mask)))))) return false; - // Disallow non-vector casts and length-changing shuffles. + // 1) Do not fold bitcast shuffle for scalable type. First, shuffle cost for + // scalable type is unknown; Second, we cannot reason if the narrowed shuffle + // mask for scalable type is a splat or not. + // 2) Disallow non-vector casts and length-changing shuffles. // TODO: We could allow any shuffle. - auto *DestTy = dyn_cast(I.getType()); - auto *SrcTy = cast(V->getType()); - if (!DestTy || I.getOperand(0)->getType() != SrcTy) + auto *DestTy = dyn_cast(I.getType()); + auto *SrcTy = dyn_cast(V->getType()); + if (!SrcTy || !DestTy || I.getOperand(0)->getType() != SrcTy) return false; // The new shuffle must not cost more than the old shuffle. The bitcast is // moved ahead of the shuffle, so assume that it has the same cost as before. - if (TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, DestTy) > - TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, SrcTy)) + InstructionCost DestCost = + TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, DestTy); + InstructionCost SrcCost = + TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, SrcTy); + if (DestCost > SrcCost || !DestCost.isValid()) return false; unsigned DestNumElts = DestTy->getNumElements(); @@ -399,8 +545,7 @@ bool VectorCombine::foldBitcastShuf(Instruction &I) { // bitcast (shuf V, MaskC) --> shuf (bitcast V), MaskC' ++NumShufOfBitcast; Value *CastV = Builder.CreateBitCast(V, DestTy); - Value *Shuf = - Builder.CreateShuffleVector(CastV, UndefValue::get(DestTy), NewMask); + Value *Shuf = Builder.CreateShuffleVector(CastV, NewMask); replaceValue(I, *Shuf); return true; } @@ -467,7 +612,7 @@ bool VectorCombine::scalarizeBinopOrCmp(Instruction &I) { "Unexpected types for insert element into binop or cmp"); unsigned Opcode = I.getOpcode(); - int ScalarOpCost, VectorOpCost; + InstructionCost ScalarOpCost, VectorOpCost; if (IsCmp) { ScalarOpCost = TTI.getCmpSelInstrCost(Opcode, ScalarTy); VectorOpCost = TTI.getCmpSelInstrCost(Opcode, VecTy); @@ -478,16 +623,16 @@ bool VectorCombine::scalarizeBinopOrCmp(Instruction &I) { // Get cost estimate for the insert element. This cost will factor into // both sequences. - int InsertCost = + InstructionCost InsertCost = TTI.getVectorInstrCost(Instruction::InsertElement, VecTy, Index); - int OldCost = (IsConst0 ? 0 : InsertCost) + (IsConst1 ? 0 : InsertCost) + - VectorOpCost; - int NewCost = ScalarOpCost + InsertCost + - (IsConst0 ? 0 : !Ins0->hasOneUse() * InsertCost) + - (IsConst1 ? 0 : !Ins1->hasOneUse() * InsertCost); + InstructionCost OldCost = + (IsConst0 ? 0 : InsertCost) + (IsConst1 ? 0 : InsertCost) + VectorOpCost; + InstructionCost NewCost = ScalarOpCost + InsertCost + + (IsConst0 ? 0 : !Ins0->hasOneUse() * InsertCost) + + (IsConst1 ? 0 : !Ins1->hasOneUse() * InsertCost); // We want to scalarize unless the vector variant actually has lower cost. - if (OldCost < NewCost) + if (OldCost < NewCost || !NewCost.isValid()) return false; // vec_op (inselt VecC0, V0, Index), (inselt VecC1, V1, Index) --> @@ -567,7 +712,8 @@ bool VectorCombine::foldExtractedCmps(Instruction &I) { if (!VecTy) return false; - int OldCost = TTI.getVectorInstrCost(Ext0->getOpcode(), VecTy, Index0); + InstructionCost OldCost = + TTI.getVectorInstrCost(Ext0->getOpcode(), VecTy, Index0); OldCost += TTI.getVectorInstrCost(Ext1->getOpcode(), VecTy, Index1); OldCost += TTI.getCmpSelInstrCost(CmpOpcode, I0->getType()) * 2; OldCost += TTI.getArithmeticInstrCost(I.getOpcode(), I.getType()); @@ -578,7 +724,7 @@ bool VectorCombine::foldExtractedCmps(Instruction &I) { int CheapIndex = ConvertToShuf == Ext0 ? Index1 : Index0; int ExpensiveIndex = ConvertToShuf == Ext0 ? Index0 : Index1; auto *CmpTy = cast(CmpInst::makeCmpResultType(X->getType())); - int NewCost = TTI.getCmpSelInstrCost(CmpOpcode, X->getType()); + InstructionCost NewCost = TTI.getCmpSelInstrCost(CmpOpcode, X->getType()); NewCost += TTI.getShuffleCost(TargetTransformInfo::SK_PermuteSingleSrc, CmpTy); NewCost += TTI.getArithmeticInstrCost(I.getOpcode(), CmpTy); @@ -587,7 +733,7 @@ bool VectorCombine::foldExtractedCmps(Instruction &I) { // Aggressively form vector ops if the cost is equal because the transform // may enable further optimization. // Codegen can reverse this transform (scalarize) if it was not profitable. - if (OldCost < NewCost) + if (OldCost < NewCost || !NewCost.isValid()) return false; // Create a vector constant from the 2 scalar constants. @@ -612,6 +758,10 @@ bool VectorCombine::run() { if (DisableVectorCombine) return false; + // Don't attempt vectorization if the target does not support vectors. + if (!TTI.getNumberOfRegisters(TTI.getRegisterClassForType(/*Vector*/ true))) + return false; + bool MadeChange = false; for (BasicBlock &BB : F) { // Ignore unreachable basic blocks. @@ -625,6 +775,7 @@ bool VectorCombine::run() { if (isa(I)) continue; Builder.SetInsertPoint(&I); + MadeChange |= vectorizeLoadInsert(I); MadeChange |= foldExtractExtract(I); MadeChange |= foldBitcastShuf(I); MadeChange |= scalarizeBinopOrCmp(I); -- cgit v1.3