[StructurizeCFG][NewPM] Port -structurizecfg to NPM

This doesn't support -structurizecfg-skip-uniform-regions since that
would require porting LegacyDivergenceAnalysis.

The NPM doesn't support adding a non-analysis pass as a dependency of
another, so I had to add -lowerswitch to some tests or pin them to the
legacy PM.

This is the only RegionPass in tree, so I simply copied the logic for
finding all Regions from the legacy PM's RGManager into
StructurizeCFG::run().

Reviewed By: arsenm

Differential Revision: https://reviews.llvm.org/D89026
This commit is contained in:
Arthur Eubanks 2020-10-07 22:07:30 -07:00
parent ba22c403b2
commit baffd052b0
10 changed files with 133 additions and 63 deletions

View File

@ -418,7 +418,7 @@ void initializeStripGCRelocatesLegacyPass(PassRegistry &);
void initializeStripNonDebugSymbolsPass(PassRegistry&);
void initializeStripNonLineTableDebugLegacyPassPass(PassRegistry &);
void initializeStripSymbolsPass(PassRegistry&);
void initializeStructurizeCFGPass(PassRegistry&);
void initializeStructurizeCFGLegacyPassPass(PassRegistry &);
void initializeTailCallElimPass(PassRegistry&);
void initializeTailDuplicatePass(PassRegistry&);
void initializeTargetLibraryInfoWrapperPassPass(PassRegistry&);

View File

@ -0,0 +1,20 @@
//===- StructurizeCFG.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_STRUCTURIZECFG_H
#define LLVM_TRANSFORMS_SCALAR_STRUCTURIZECFG_H
#include "llvm/IR/PassManager.h"
namespace llvm {
struct StructurizeCFGPass : PassInfoMixin<StructurizeCFGPass> {
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
};
} // namespace llvm
#endif // LLVM_TRANSFORMS_SCALAR_STRUCTURIZECFG_H

View File

@ -191,6 +191,7 @@
#include "llvm/Transforms/Scalar/Sink.h"
#include "llvm/Transforms/Scalar/SpeculateAroundPHIs.h"
#include "llvm/Transforms/Scalar/SpeculativeExecution.h"
#include "llvm/Transforms/Scalar/StructurizeCFG.h"
#include "llvm/Transforms/Scalar/TailRecursionElimination.h"
#include "llvm/Transforms/Scalar/WarnMissedTransforms.h"
#include "llvm/Transforms/Utils/AddDiscriminators.h"

View File

@ -287,6 +287,7 @@ FUNCTION_PASS("speculative-execution", SpeculativeExecutionPass())
FUNCTION_PASS("spec-phis", SpeculateAroundPHIsPass())
FUNCTION_PASS("sroa", SROA())
FUNCTION_PASS("strip-gc-relocates", StripGCRelocates())
FUNCTION_PASS("structurizecfg", StructurizeCFGPass())
FUNCTION_PASS("tailcallelim", TailCallElimPass())
FUNCTION_PASS("unify-loop-exits", UnifyLoopExitsPass())
FUNCTION_PASS("vector-combine", VectorCombinePass())

View File

@ -97,7 +97,7 @@ void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeSCCPLegacyPassPass(Registry);
initializeSROALegacyPassPass(Registry);
initializeCFGSimplifyPassPass(Registry);
initializeStructurizeCFGPass(Registry);
initializeStructurizeCFGLegacyPassPass(Registry);
initializeSimpleLoopUnswitchLegacyPassPass(Registry);
initializeSinkingLegacyPassPass(Registry);
initializeTailCallElimPass(Registry);

View File

@ -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"
@ -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<RegionNode *, 8> 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<LegacyDivergenceAnalysis>();
if (SCFG.makeUniformRegion(R, DA))
return false;
}
DominatorTree *DT = &getAnalysis<DominatorTreeWrapperPass>().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(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,21 +1008,29 @@ 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) {
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");
DA = &getAnalysis<LegacyDivergenceAnalysis>();
if (hasOnlyUniformBranches(R, UniformMDKindID, *DA)) {
LLVM_DEBUG(dbgs() << "Skipping region with uniform control flow: " << *R
@ -1036,15 +1049,21 @@ bool StructurizeCFG::runOnRegion(Region *R, RGPassManager &RGM) {
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<DominatorTreeWrapperPass>().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<Region *> &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<DominatorTreeAnalysis>(F);
auto &RI = AM.getResult<RegionInfoAnalysis>(F);
std::vector<Region *> 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<DominatorTreeAnalysis>();
return PA;
}

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -mtriple=amdgcn-- -S -o - -structurizecfg -structurizecfg-skip-uniform-regions -structurizecfg-relaxed-uniform-regions < %s | FileCheck %s
; RUN: opt -mtriple=amdgcn-- -S -o - -structurizecfg -structurizecfg-skip-uniform-regions -structurizecfg-relaxed-uniform-regions -enable-new-pm=0 < %s | FileCheck %s
define amdgpu_cs void @uniform(i32 inreg %v) {
; CHECK-LABEL: @uniform(

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -S -structurizecfg %s -o - | FileCheck %s
; RUN: opt -S -lowerswitch -structurizecfg %s -o - | FileCheck %s
; This test have an outer loop containing an inner loop,
; for which there is an interleaved post-order traversal.

View File

@ -1,4 +1,5 @@
; RUN: opt -S -structurizecfg %s -o - | FileCheck %s
; RUN: opt -S -passes=structurizecfg %s -o - | FileCheck %s
define void @main(float addrspace(1)* %out) {

View File

@ -1,4 +1,4 @@
; RUN: opt -S -structurizecfg %s -o - | FileCheck %s
; RUN: opt -S -structurizecfg %s -o - -enable-new-pm=0 | FileCheck %s
; The structurizecfg pass cannot handle switch instructions, so we need to
; make sure the lower switch pass is always run before structurizecfg.