Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions llvm/include/llvm/InitializePasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ LLVM_ABI void initializeScavengerTestPass(PassRegistry &);
LLVM_ABI void initializeScopedNoAliasAAWrapperPassPass(PassRegistry &);
LLVM_ABI void
initializeSeparateConstOffsetFromGEPLegacyPassPass(PassRegistry &);
LLVM_ABI void initializeSinkGEPConstOffsetLegacyPassPass(PassRegistry &);
LLVM_ABI void initializeShadowStackGCLoweringPass(PassRegistry &);
LLVM_ABI void initializeShrinkWrapLegacyPass(PassRegistry &);
LLVM_ABI void initializeSingleLoopExtractorPass(PassRegistry &);
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/LinkAllPasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ struct ForcePassLinking {
(void)llvm::createPartiallyInlineLibCallsPass();
(void)llvm::createScalarizerPass();
(void)llvm::createSeparateConstOffsetFromGEPPass();
(void)llvm::createSinkGEPConstOffsetPass();
(void)llvm::createSpeculativeExecutionPass();
(void)llvm::createSpeculativeExecutionIfHasBranchDivergencePass();
(void)llvm::createStraightLineStrengthReducePass();
Expand Down
7 changes: 7 additions & 0 deletions llvm/include/llvm/Transforms/Scalar.h
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,13 @@ LLVM_ABI FunctionPass *createPartiallyInlineLibCallsPass();
LLVM_ABI FunctionPass *
createSeparateConstOffsetFromGEPPass(bool LowerGEP = false);

//===----------------------------------------------------------------------===//
//
// SinkGEPConstOffset - Sink constant offsets down the GEP chain to the tail for
// reduction of register usage.
//
FunctionPass *createSinkGEPConstOffsetPass();

//===----------------------------------------------------------------------===//
//
// SpeculativeExecution - Aggressively hoist instructions to enable
Expand Down
27 changes: 27 additions & 0 deletions llvm/include/llvm/Transforms/Scalar/SinkGEPConstOffset.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//===- SinkGEPConstOffset.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_SINKGEPCONSTOFFSET_H
#define LLVM_TRANSFORMS_SCALAR_SINKGEPCONSTOFFSET_H

#include "llvm/IR/PassManager.h"

namespace llvm {

class SinkGEPConstOffsetPass
: public PassInfoMixin<SinkGEPConstOffsetPass> {
public:
SinkGEPConstOffsetPass() {}
void printPipeline(raw_ostream &OS,
function_ref<StringRef(StringRef)> MapClassName2PassName);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &);
};

} // end namespace llvm

#endif // LLVM_TRANSFORMS_SCALAR_SINKGEPCONSTOFFSET_H
1 change: 1 addition & 0 deletions llvm/lib/Passes/PassBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@
#include "llvm/Transforms/Scalar/ScalarizeMaskedMemIntrin.h"
#include "llvm/Transforms/Scalar/Scalarizer.h"
#include "llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h"
#include "llvm/Transforms/Scalar/SinkGEPConstOffset.h"
#include "llvm/Transforms/Scalar/SimpleLoopUnswitch.h"
#include "llvm/Transforms/Scalar/SimplifyCFG.h"
#include "llvm/Transforms/Scalar/Sink.h"
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Passes/PassRegistry.def
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ FUNCTION_PASS("sccp", SCCPPass())
FUNCTION_PASS("select-optimize", SelectOptimizePass(TM))
FUNCTION_PASS("separate-const-offset-from-gep",
SeparateConstOffsetFromGEPPass())
FUNCTION_PASS("sink-gep-const-offset",
SinkGEPConstOffsetPass())
FUNCTION_PASS("sink", SinkingPass())
FUNCTION_PASS("sjlj-eh-prepare", SjLjEHPreparePass(TM))
FUNCTION_PASS("slp-vectorizer", SLPVectorizerPass())
Expand Down
4 changes: 4 additions & 0 deletions llvm/lib/Target/AMDGPU/AMDGPUTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#include "llvm/Transforms/Scalar/LoopDataPrefetch.h"
#include "llvm/Transforms/Scalar/NaryReassociate.h"
#include "llvm/Transforms/Scalar/SeparateConstOffsetFromGEP.h"
#include "llvm/Transforms/Scalar/SinkGEPConstOffset.h"
#include "llvm/Transforms/Scalar/Sink.h"
#include "llvm/Transforms/Scalar/StraightLineStrengthReduce.h"
#include "llvm/Transforms/Scalar/StructurizeCFG.h"
Expand Down Expand Up @@ -1241,6 +1242,7 @@ void AMDGPUPassConfig::addStraightLineScalarOptimizationPasses() {
if (isPassEnabled(EnableLoopPrefetch, CodeGenOptLevel::Aggressive))
addPass(createLoopDataPrefetchPass());
addPass(createSeparateConstOffsetFromGEPPass());
addPass(createSinkGEPConstOffsetPass());
// ReassociateGEPs exposes more opportunities for SLSR. See
// the example in reassociate-geps-and-slsr.ll.
addPass(createStraightLineStrengthReducePass());
Expand Down Expand Up @@ -2366,6 +2368,8 @@ void AMDGPUCodeGenPassBuilder::addStraightLineScalarOptimizationPasses(

addPass(SeparateConstOffsetFromGEPPass());

addPass(SinkGEPConstOffsetPass());

// ReassociateGEPs exposes more opportunities for SLSR. See
// the example in reassociate-geps-and-slsr.ll.
addPass(StraightLineStrengthReducePass());
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ add_llvm_component_library(LLVMScalarOpts
Scalarizer.cpp
ScalarizeMaskedMemIntrin.cpp
SeparateConstOffsetFromGEP.cpp
SinkGEPConstOffset.cpp
SimpleLoopUnswitch.cpp
SimplifyCFGPass.cpp
Sink.cpp
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Transforms/Scalar/Scalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeSinkingLegacyPassPass(Registry);
initializeTailCallElimPass(Registry);
initializeSeparateConstOffsetFromGEPLegacyPassPass(Registry);
initializeSinkGEPConstOffsetLegacyPassPass(Registry);
initializeSpeculativeExecutionLegacyPassPass(Registry);
initializeStraightLineStrengthReduceLegacyPassPass(Registry);
initializePlaceBackedgeSafepointsLegacyPassPass(Registry);
Expand Down
216 changes: 216 additions & 0 deletions llvm/lib/Transforms/Scalar/SinkGEPConstOffset.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
//===- SinkGEPConstOffset.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
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Scalar/SinkGEPConstOffset.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryBuiltins.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
#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"
#include "llvm/IR/Value.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
#include <cstdint>
#include <string>

using namespace llvm;
using namespace llvm::PatternMatch;

namespace {

/// A pass that tries to sink const offset in GEP chain to tail.
/// It is a FunctionPass because searching for the constant offset may inspect
/// other basic blocks.
class SinkGEPConstOffsetLegacyPass : public FunctionPass {
public:
static char ID;

SinkGEPConstOffsetLegacyPass() : FunctionPass(ID) {
initializeSinkGEPConstOffsetLegacyPassPass(
*PassRegistry::getPassRegistry());
}

void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
}

bool runOnFunction(Function &F) override;
};

} // end anonymous namespace

char SinkGEPConstOffsetLegacyPass::ID = 0;

INITIALIZE_PASS_BEGIN(
SinkGEPConstOffsetLegacyPass, "sink-gep-const-offset",
"Sink const offsets down the GEP chain to the tail for reduction of "
"register usage", false, false)
INITIALIZE_PASS_DEPENDENCY(ScalarEvolutionWrapperPass)
INITIALIZE_PASS_END(
SinkGEPConstOffsetLegacyPass, "sink-gep-const-offset",
"Sink const offsets down the GEP chain to the tail for reduction of "
"register usage", false, false)

FunctionPass *llvm::createSinkGEPConstOffsetPass() {
return new SinkGEPConstOffsetLegacyPass();
}

/// The purpose of this function is to sink the constant offsets in the base
/// GEP to current GEP.
///
/// A simple example is given:
///
/// %gep0 = getelementptr half, ptr addrspace(3) %ptr, i32 512
/// %gep1 = getelementptr half, ptr addrspace(3) %gep0, i32 %ofst0
/// %data = load half, ptr addrspace(3) %gep1, align 2
/// ==>
/// %gep0 = getelementptr half, ptr addrspace(3) %ptr, i32 %ofst0
/// %gep1 = getelementptr half, ptr addrspace(3) %gep0, i32 512
/// %data = load half, ptr addrspace(3) %gep1, align 2
static bool sinkGEPConstantOffset(Value *Ptr, const DataLayout *DL) {
GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(Ptr);
if (!GEP)
return false;

if (GEP->getNumIndices() != 1)
return false;

GetElementPtrInst *BaseGEP =
dyn_cast<GetElementPtrInst>(GEP->getPointerOperand());
if (!BaseGEP)
return false;

if (BaseGEP->getNumIndices() != 1)
return false;

Value *Idx = GEP->getOperand(1);
Value *BaseIdx = BaseGEP->getOperand(1);

ConstantInt *BaseIdxAsCI = dyn_cast<ConstantInt>(BaseIdx);
if (!BaseIdxAsCI)
return false;

Type *ResTy = GEP->getResultElementType();
Type *BaseResTy = BaseGEP->getResultElementType();

ConstantInt *IdxAsCI = dyn_cast<ConstantInt>(Idx);
if (IdxAsCI) {
// %gep0 = getelementptr half, ptr addrspace(3) %ptr, i32 8
// %gep1 = getelementptr half, ptr addrspace(3) %gep0, i32 4
// as:
// %gep1 = getelementptr half, ptr addrspace(3) %ptr, i32 12
Type *NewResTy = nullptr;
int64_t NewIdxValue = 0;
if (ResTy == BaseResTy) {
NewResTy = ResTy;
NewIdxValue = BaseIdxAsCI->getSExtValue() + IdxAsCI->getSExtValue();
} else {
NewResTy = Type::getInt8Ty(GEP->getContext());
NewIdxValue = (BaseIdxAsCI->getSExtValue() *
DL->getTypeAllocSize(BaseResTy)) +
(IdxAsCI->getSExtValue() *
DL->getTypeAllocSize(ResTy));
}
assert(NewResTy);
Type *NewIdxType = (Idx->getType()->getPrimitiveSizeInBits() >
BaseIdx->getType()->getPrimitiveSizeInBits())
? Idx->getType() : BaseIdx->getType();
Constant *NewIdx = ConstantInt::get(NewIdxType, NewIdxValue);
auto *NewGEP = GetElementPtrInst::Create(
NewResTy, BaseGEP->getPointerOperand(), NewIdx);
NewGEP->setIsInBounds(GEP->isInBounds());
NewGEP->insertBefore(GEP->getIterator());
NewGEP->takeName(GEP);

GEP->replaceAllUsesWith(NewGEP);
RecursivelyDeleteTriviallyDeadInstructions(GEP);

return true;
}

// %gep0 = getelementptr half, ptr addrspace(3) %ptr, i32 8
// %gep1 = getelementptr half, ptr addrspace(3) %gep0, i32 %idx
// as:
// %gepx0 = getelementptr half, ptr addrspace(3) %ptr, i32 %idx
// %gepx1 = getelementptr half, ptr addrspace(3) %gepx0, i32 8
auto *GEPX0 =
GetElementPtrInst::Create(ResTy, BaseGEP->getPointerOperand(), Idx);
GEPX0->insertBefore(GEP->getIterator());
auto *GEPX1 = GetElementPtrInst::Create(BaseResTy, GEPX0, BaseIdx);
GEPX1->setIsInBounds(GEP->isInBounds());
GEPX1->insertBefore(GEP->getIterator());
GEPX1->takeName(GEP);

GEP->replaceAllUsesWith(GEPX1);
RecursivelyDeleteTriviallyDeadInstructions(GEP);

return true;
}

static bool sinkGEPConstantOffset(Function &F) {
const DataLayout *DL = &F.getDataLayout();
ReversePostOrderTraversal<Function*> RPOT(&F);
bool Changed = false;
for (auto *BB : RPOT)
for (Instruction &I : llvm::make_early_inc_range(*BB))
if (GetElementPtrInst *GEP = dyn_cast<GetElementPtrInst>(&I))
Changed |= sinkGEPConstantOffset(GEP, DL);

return Changed;
}

bool SinkGEPConstOffsetLegacyPass::runOnFunction(Function &F) {
if (skipFunction(F))
return false;

return sinkGEPConstantOffset(F);
}

void SinkGEPConstOffsetPass::printPipeline(
raw_ostream &OS, function_ref<StringRef(StringRef)> MapClassName2PassName) {
static_cast<PassInfoMixin<SinkGEPConstOffsetPass> *>(this)
->printPipeline(OS, MapClassName2PassName);
}

PreservedAnalyses
SinkGEPConstOffsetPass::run(Function &F, FunctionAnalysisManager &AM) {
if (!sinkGEPConstantOffset(F))
return PreservedAnalyses::all();

PreservedAnalyses PA;
PA.preserveSet<CFGAnalyses>();
return PA;
}
3 changes: 3 additions & 0 deletions llvm/test/CodeGen/AMDGPU/llc-pipeline.ll
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@
; GCN-O1-OPTS-NEXT: Scalar Evolution Analysis
; GCN-O1-OPTS-NEXT: Loop Data Prefetch
; GCN-O1-OPTS-NEXT: Split GEPs to a variadic base and a constant offset for better CSE
; GCN-O1-OPTS-NEXT: Sink const offsets down the GEP chain to the tail for reduction of register usage
; GCN-O1-OPTS-NEXT: Scalar Evolution Analysis
; GCN-O1-OPTS-NEXT: Straight line strength reduction
; GCN-O1-OPTS-NEXT: Early CSE
Expand Down Expand Up @@ -795,6 +796,7 @@
; GCN-O2-NEXT: Natural Loop Information
; GCN-O2-NEXT: AMDGPU Promote Alloca
; GCN-O2-NEXT: Split GEPs to a variadic base and a constant offset for better CSE
; GCN-O2-NEXT: Sink const offsets down the GEP chain to the tail for reduction of register usage
; GCN-O2-NEXT: Scalar Evolution Analysis
; GCN-O2-NEXT: Straight line strength reduction
; GCN-O2-NEXT: Early CSE
Expand Down Expand Up @@ -1113,6 +1115,7 @@
; GCN-O3-NEXT: Natural Loop Information
; GCN-O3-NEXT: AMDGPU Promote Alloca
; GCN-O3-NEXT: Split GEPs to a variadic base and a constant offset for better CSE
; GCN-O3-NEXT: Sink const offsets down the GEP chain to the tail for reduction of register usage
; GCN-O3-NEXT: Scalar Evolution Analysis
; GCN-O3-NEXT: Straight line strength reduction
; GCN-O3-NEXT: Basic Alias Analysis (stateless AA impl)
Expand Down
Loading