//===- DivRemPairs.cpp - Hoist/[dr]ecompose division and remainder --------===// // // 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 hoists and/or decomposes/recomposes integer division and remainder // instructions to enable CFG improvements and better codegen. // //===----------------------------------------------------------------------===// #include "llvm/Transforms/Scalar/DivRemPairs.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/MapVector.h" #include "llvm/ADT/Statistic.h" #include "llvm/Analysis/GlobalsModRef.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/PatternMatch.h" #include "llvm/Support/DebugCounter.h" #include "llvm/Transforms/Utils/BypassSlowDivision.h" #include <optional> usingnamespacellvm; usingnamespacellvm::PatternMatch; #define DEBUG_TYPE … STATISTIC(NumPairs, "Number of div/rem pairs"); STATISTIC(NumRecomposed, "Number of instructions recomposed"); STATISTIC(NumHoisted, "Number of instructions hoisted"); STATISTIC(NumDecomposed, "Number of instructions decomposed"); DEBUG_COUNTER(DRPCounter, "div-rem-pairs-transform", "Controls transformations in div-rem-pairs pass"); namespace { struct ExpandedMatch { … }; } // namespace /// See if we can match: (which is the form we expand into) /// X - ((X ?/ Y) * Y) /// which is equivalent to: /// X ?% Y static std::optional<ExpandedMatch> matchExpandedRem(Instruction &I) { … } namespace { /// A thin wrapper to store two values that we matched as div-rem pair. /// We want this extra indirection to avoid dealing with RAUW'ing the map keys. struct DivRemPairWorklistEntry { … }; } // namespace DivRemWorklistTy; /// Find matching pairs of integer div/rem ops (they have the same numerator, /// denominator, and signedness). Place those pairs into a worklist for further /// processing. This indirection is needed because we have to use TrackingVH<> /// because we will be doing RAUW, and if one of the rem instructions we change /// happens to be an input to another div/rem in the maps, we'd have problems. static DivRemWorklistTy getWorklist(Function &F) { … } /// Find matching pairs of integer div/rem ops (they have the same numerator, /// denominator, and signedness). If they exist in different basic blocks, bring /// them together by hoisting or replace the common division operation that is /// implicit in the remainder: /// X % Y <--> X - ((X / Y) * Y). /// /// We can largely ignore the normal safety and cost constraints on speculation /// of these ops when we find a matching pair. This is because we are already /// guaranteed that any exceptions and most cost are already incurred by the /// first member of the pair. /// /// Note: This transform could be an oddball enhancement to EarlyCSE, GVN, or /// SimplifyCFG, but it's split off on its own because it's different enough /// that it doesn't quite match the stated objectives of those passes. static bool optimizeDivRem(Function &F, const TargetTransformInfo &TTI, const DominatorTree &DT) { … } // Pass manager boilerplate below here. PreservedAnalyses DivRemPairsPass::run(Function &F, FunctionAnalysisManager &FAM) { … }