Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AIE NFC] Postpipeliner cleanups and refactorings #253

Open
wants to merge 9 commits into
base: aie-public
Choose a base branch
from
115 changes: 61 additions & 54 deletions llvm/lib/Target/AIE/AIEPostPipeliner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,7 @@ bool PostPipeliner::computeLoopCarriedParameters() {
}

// Save the static values for ease of reset
for (auto &N : Info) {
for (auto &N : Info.Nodes) {
N.StaticEarliest = N.Earliest;
N.StaticLatest = N.Latest;
}
Expand All @@ -343,24 +343,23 @@ int PostPipeliner::computeMinScheduleLength() const {
return MinLength;
}

void dumpGraph(int NInstr, const std::vector<NodeInfo> &Info,
ScheduleDAGInstrs *DAG) {
void dumpGraph(const ScheduleInfo &Info, ScheduleDAGInstrs *DAG) {
dbgs() << "digraph {\n";

for (int K = 0; K < NInstr; K++) {
for (int K = 0; K < Info.NInstr; K++) {
auto &SU = DAG->SUnits[K];
for (auto &Dep : SU.Succs) {
auto *Succ = Dep.getSUnit();
int S = Succ->NodeNum;
if (S % NInstr == K) {
if (S % Info.NInstr == K) {
continue;
}

dbgs() << "\tSU" << K << " -> "
<< "SU" << S;

if (S >= NInstr) {
dbgs() << "_" << S % NInstr;
if (S >= Info.NInstr) {
dbgs() << "_" << S % Info.NInstr;
}
if (Dep.getKind() == SDep::Data) {
dbgs() << " [color=red] ";
Expand Down Expand Up @@ -476,7 +475,7 @@ bool PostPipeliner::scheduleFirstIteration(PostPipelinerStrategy &Strategy) {
}

namespace {
void dumpEarliestChain(const std::vector<NodeInfo> &Info, int N) {
void dumpEarliestChain(const ScheduleInfo &Info, int N) {
auto Prev = Info[N].LastEarliestPusher;
if (Prev) {
dumpEarliestChain(Info, *Prev);
Expand Down Expand Up @@ -515,8 +514,7 @@ bool PostPipeliner::scheduleOtherIterations() {

class DefaultStrategy : public PostPipelinerStrategy {
public:
DefaultStrategy(ScheduleDAGMI &DAG, std::vector<NodeInfo> &Info,
int LatestBias)
DefaultStrategy(ScheduleDAGMI &DAG, ScheduleInfo &Info, int LatestBias)
: PostPipelinerStrategy(DAG, Info, LatestBias) {}
bool better(const SUnit &A, const SUnit &B) override {
return Info[A.NodeNum].Latest < Info[B.NodeNum].Latest;
Expand All @@ -525,6 +523,7 @@ class DefaultStrategy : public PostPipelinerStrategy {

class ConfigStrategy : public PostPipelinerStrategy {
bool TopDown = true;
bool Alternate = false;

public:
enum PriorityComponent {
Expand Down Expand Up @@ -552,6 +551,13 @@ class ConfigStrategy : public PostPipelinerStrategy {
}
return "Size - Illegal";
}
struct Configuration {
int ExtraStages = 0;
bool TopDown = true;
bool Alternate = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to document those fields, especially Alternate

int Runs = 0;
ArrayRef<PriorityComponent> Components;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not own the list of components? Does that help a lot with memory usage?

};

private:
std::string Name;
Expand Down Expand Up @@ -597,6 +603,12 @@ class ConfigStrategy : public PostPipelinerStrategy {
return false;
}

int earliest(const SUnit &N) override { return Info[N.NodeNum].Earliest; }

int latest(const SUnit &N) override {
return Info[N.NodeNum].Latest + LatestBias;
}

void selected(const SUnit &N) override {
// Promote the critical path
NodeInfo *Pushed = &Info[N.NodeNum];
Expand Down Expand Up @@ -628,75 +640,71 @@ class ConfigStrategy : public PostPipelinerStrategy {
PredSiblingScheduled.insert(PDep.getSUnit()->NodeNum);
}
}
if (Alternate) {
TopDown = !TopDown;
}
}

public:
std::string name() override { return Name; }
ConfigStrategy(ScheduleDAGInstrs &DAG, std::vector<NodeInfo> &Info,
int Length, bool TopDown,
ConfigStrategy(ScheduleDAGInstrs &DAG, ScheduleInfo &Info, int Length,
bool TopDown, bool Alternate,
ArrayRef<PriorityComponent> Components)
: PostPipelinerStrategy(DAG, Info, Length), TopDown(TopDown) {
Name = "Config_" + std::to_string(Length) + "_" + std::to_string(TopDown);
: PostPipelinerStrategy(DAG, Info, Length), TopDown(TopDown),
Alternate(Alternate) {
Name = "Config_" + std::to_string(Length) + "_" + std::to_string(TopDown) +
"_" + std::to_string(Alternate);
for (auto Comp : Components) {
Name += "_" + getPriorityName(Comp);
Priority.emplace_back(Comp);
}
}
};

static const struct {
int ExtraStages;
bool TopDown;
bool Rerun;
ConfigStrategy::PriorityComponent Components[3];
} Strategies[] = {
static const ConfigStrategy::PriorityComponent
NodeNum[] = {ConfigStrategy::NodeNum},
Latest[] = {ConfigStrategy::Latest},
Critical[] = {ConfigStrategy::Critical},
CriticalLCDLatest[] = {ConfigStrategy::Critical, ConfigStrategy::LCDLatest};

static const ConfigStrategy::Configuration Strategies[] = {
// Loosely speaking, a lower value of the first parameter targets
// a lower stage count, which benefits code size.
// Rerurn is only useful for heuristics that use it, e.g. Critical
{1, true, false, {ConfigStrategy::NodeNum}},
{1, true, false, {ConfigStrategy::Latest}},
{1, true, true, {ConfigStrategy::Critical}},
{1, true, true, {ConfigStrategy::Critical, ConfigStrategy::LCDLatest}},
{0, false, true, {ConfigStrategy::Critical, ConfigStrategy::LCDLatest}},
{1, false, true, {ConfigStrategy::Critical, ConfigStrategy::LCDLatest}},
// Runs>1 is only useful for heuristics that use it, e.g. Critical
// {ExtraStages, TopDown, Alternate, Runs, Components}
{1, true, false, 1, NodeNum},
{1, true, false, 1, Latest},
{1, true, false, 2, Critical},
{1, true, false, 2, CriticalLCDLatest},
{0, false, false, 2, CriticalLCDLatest},
{1, false, false, 2, CriticalLCDLatest},
// This is pure bottom up
{1, false, false, {ConfigStrategy::NodeNum}},
{1, false, false, 1, NodeNum},
};

bool PostPipeliner::tryHeuristics() {
int MinLength = computeMinScheduleLength();

DEBUG_SUMMARY(dbgs() << "-- MinLength=" << MinLength << "\n");

int HeuristicIndex = 0;
for (auto &[ExtraStages, TopDown, Rerun, Components] : Strategies) {
for (const auto &Config : Strategies) {
if (Heuristic >= 0 && Heuristic != HeuristicIndex++) {
continue;
}
ConfigStrategy S(*DAG, Info, MinLength + ExtraStages * II, TopDown,
Components);
ConfigStrategy S(*DAG, Info, MinLength + Config.ExtraStages * II,
Config.TopDown, Config.Alternate, Config.Components);
resetSchedule(/*FullReset=*/true);
DEBUG_SUMMARY(dbgs() << "--- Strategy " << S.name() << "\n");
if (scheduleFirstIteration(S) && scheduleOtherIterations()) {
DEBUG_SUMMARY(dbgs() << " Strategy " << S.name() << " found II=" << II
for (int Run = 0; Run < Config.Runs; Run++) {
DEBUG_SUMMARY(dbgs() << "--- Strategy " << S.name() << " run=" << Run
<< "\n");
return true;
}

DEBUG_SUMMARY(dbgs() << " failed\n");
if (!Rerun) {
continue;
}

// Rerun with dynamic information retained
resetSchedule(/*FullReset=*/false);
DEBUG_SUMMARY(dbgs() << "--- Strategy " << S.name()
<< " with critical path");
if (scheduleFirstIteration(S) && scheduleOtherIterations()) {
DEBUG_SUMMARY(dbgs() << " found II=" << II << "\n");
return true;
if (scheduleFirstIteration(S) && scheduleOtherIterations()) {
DEBUG_SUMMARY(dbgs() << " Strategy " << S.name() << " run=" << Run
<< " found II=" << II << "\n");
return true;
}
resetSchedule(/*FullReset=*/false);
}
DEBUG_SUMMARY(dbgs() << " failed\n");
DEBUG_SUMMARY(dbgs() << " Strategy " << S.name() << " failed\n");
}
DEBUG_SUMMARY(dbgs() << "=== II=" << II << " Failed ===\n");
return false;
Expand All @@ -718,12 +726,11 @@ bool PostPipeliner::schedule(ScheduleDAGMI &TheDAG, int InitiationInterval) {
Depth = NCopies * II + HR.getPipelineDepth();
Scoreboard.reset(Depth);

Info.clear();
Info.resize(NTotalInstrs);
Info.init(NInstr, NCopies);

LLVM_DEBUG(for (int I = 0; I < NInstr;
I++) { dbgs() << I << " " << *DAG->SUnits[I].getInstr(); });
LLVM_DEBUG(dumpGraph(NInstr, Info, DAG));
LLVM_DEBUG(dumpGraph(Info, DAG));

computeLoopCarriedParameters();

Expand Down
22 changes: 18 additions & 4 deletions llvm/lib/Target/AIE/AIEPostPipeliner.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,27 @@ class NodeInfo {
void reset(bool FullReset);
};

class ScheduleInfo {
public:
std::vector<NodeInfo> Nodes;
int NInstr;
void init(int NOrig, int NCopies) {
NInstr = NOrig;
Nodes.clear();
Nodes.resize(NInstr * NCopies);
}
NodeInfo &operator[](int N) { return Nodes[N]; }
const NodeInfo &operator[](int N) const { return Nodes[N]; }
};

class PostPipelinerStrategy {
protected:
ScheduleDAGInstrs &DAG;
std::vector<NodeInfo> &Info;
ScheduleInfo &Info;
int LatestBias = 0;

public:
PostPipelinerStrategy(ScheduleDAGInstrs &DAG, std::vector<NodeInfo> &Info,
PostPipelinerStrategy(ScheduleDAGInstrs &DAG, ScheduleInfo &Info,
int LatestBias)
: DAG(DAG), Info(Info), LatestBias(LatestBias) {};
virtual ~PostPipelinerStrategy() {};
Expand Down Expand Up @@ -139,9 +152,10 @@ class PostPipeliner {
int FirstUnscheduled = 0;
int LastUnscheduled = -1;

/// Holds the cycle of each SUnit. The following should hold:
/// Holds the schuling information for each instruction. The following
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

schuling -> scheduling

/// should hold:
/// Cycle(N) mod II == Cycle(N % NInstr) mod II
std::vector<NodeInfo> Info;
ScheduleInfo Info;

// The scoreboard and its depth
ResourceScoreboard<FuncUnitWrapper> Scoreboard;
Expand Down