diff --git a/llvm/include/llvm/InitializePasses.h b/llvm/include/llvm/InitializePasses.h --- a/llvm/include/llvm/InitializePasses.h +++ b/llvm/include/llvm/InitializePasses.h @@ -392,7 +392,7 @@ void initializeScalarizerLegacyPassPass(PassRegistry&); void initializeScavengerTestPass(PassRegistry&); void initializeScopedNoAliasAAWrapperPassPass(PassRegistry&); -void initializeSeparateConstOffsetFromGEPPass(PassRegistry&); +void initializeSeparateConstOffsetFromGEPLegacyPassPass(PassRegistry &); void initializeShadowStackGCLoweringPass(PassRegistry&); void initializeShrinkWrapPass(PassRegistry&); void initializeSimpleInlinerPass(PassRegistry&); diff --git a/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h b/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h @@ -0,0 +1,27 @@ +//===- SeparateConstOffsetFromGEP.h ---------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_SCALAR_SEPARATECONSTOFFSETFROMGEP_H +#define LLVM_TRANSFORMS_SCALAR_SEPARATECONSTOFFSETFROMGEP_H + +#include "llvm/IR/PassManager.h" + +namespace llvm { + +class SeparateConstOffsetFromGEPPass + : public PassInfoMixin { + bool LowerGEP; + +public: + SeparateConstOffsetFromGEPPass(bool LowerGEP = false) : LowerGEP(LowerGEP) {} + PreservedAnalyses run(Function &F, FunctionAnalysisManager &); +}; + +} // end namespace llvm + +#endif // LLVM_TRANSFORMS_SCALAR_SEPARATECONSTOFFSETFROMGEP_H diff --git a/llvm/lib/Passes/PassBuilder.cpp b/llvm/lib/Passes/PassBuilder.cpp --- a/llvm/lib/Passes/PassBuilder.cpp +++ b/llvm/lib/Passes/PassBuilder.cpp @@ -189,6 +189,7 @@ #include "llvm/Transforms/Scalar/SCCP.h" #include "llvm/Transforms/Scalar/SROA.h" #include "llvm/Transforms/Scalar/Scalarizer.h" +#include "llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h" #include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h" #include "llvm/Transforms/Scalar/SimplifyCFG.h" #include "llvm/Transforms/Scalar/Sink.h" diff --git a/llvm/lib/Passes/PassRegistry.def b/llvm/lib/Passes/PassRegistry.def --- a/llvm/lib/Passes/PassRegistry.def +++ b/llvm/lib/Passes/PassRegistry.def @@ -285,6 +285,7 @@ FUNCTION_PASS("reassociate", ReassociatePass()) FUNCTION_PASS("reg2mem", RegToMemPass()) FUNCTION_PASS("scalarizer", ScalarizerPass()) +FUNCTION_PASS("separate-const-offset-from-gep", SeparateConstOffsetFromGEPPass()) FUNCTION_PASS("sccp", SCCPPass()) FUNCTION_PASS("simplifycfg", SimplifyCFGPass()) FUNCTION_PASS("sink", SinkingPass()) diff --git a/llvm/lib/Transforms/Scalar/Scalar.cpp b/llvm/lib/Transforms/Scalar/Scalar.cpp --- a/llvm/lib/Transforms/Scalar/Scalar.cpp +++ b/llvm/lib/Transforms/Scalar/Scalar.cpp @@ -101,7 +101,7 @@ initializeSimpleLoopUnswitchLegacyPassPass(Registry); initializeSinkingLegacyPassPass(Registry); initializeTailCallElimPass(Registry); - initializeSeparateConstOffsetFromGEPPass(Registry); + initializeSeparateConstOffsetFromGEPLegacyPassPass(Registry); initializeSpeculativeExecutionLegacyPassPass(Registry); initializeStraightLineStrengthReduceLegacyPassPass(Registry); initializePlaceBackedgeSafepointsImplPass(Registry); diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp --- 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 @@ /// 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 @@ 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 @@ 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 @@ } // 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(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, @@ -962,8 +978,7 @@ 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 @@ 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 @@ } 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/test/Transforms/SeparateConstOffsetFromGEP/test-add-sub-separation.ll b/llvm/test/Transforms/SeparateConstOffsetFromGEP/test-add-sub-separation.ll --- a/llvm/test/Transforms/SeparateConstOffsetFromGEP/test-add-sub-separation.ll +++ b/llvm/test/Transforms/SeparateConstOffsetFromGEP/test-add-sub-separation.ll @@ -1,5 +1,6 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -separate-const-offset-from-gep < %s | FileCheck %s +; RUN: opt -S -passes=separate-const-offset-from-gep < %s | FileCheck %s define void @matchingExtensions(i32* %ap, i32* %bp, i64* %result) { ; CHECK-LABEL: @matchingExtensions(