Skip to content

Commit

Permalink
ValueDominanceValidation: forbid crossblock liveness
Browse files Browse the repository at this point in the history
Now that we have successfully eliminated crossblock liveness from the IR we
generate, validate as much to ensure it doesn't come back. We will take
advantage of this new invariant in RA in the future.

Signed-off-by: Alyssa Rosenzweig <[email protected]>
  • Loading branch information
alyssarosenzweig committed Apr 8, 2024
1 parent a775e47 commit 7b3e031
Showing 1 changed file with 21 additions and 87 deletions.
108 changes: 21 additions & 87 deletions FEXCore/Source/Interface/IR/Passes/ValueDominanceValidation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,95 +106,29 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) {

OrderedNodeWrapper Arg = IROp->Args[i];

// We must ensure domininance of all SSA arguments
if (Arg.ID() >= BlockIROp->Begin.ID() &&
Arg.ID() < BlockIROp->Last.ID()) {
// If the SSA argument is defined INSIDE this block
// then it must only be declared prior to this instruction
// Eg: Valid
// CodeBlock_1:
// %_1 = Load
// %_2 = Load
// %_3 = <Op> %_1, %_2
//
// Eg: Invalid
// CodeBlock_1:
// %_1 = Load
// %_2 = <Op> %_1, %_3
// %_3 = Load
if (Arg.ID() > CodeID) {
HadError |= true;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition does not dominate this use!" << std::endl;
}
// If the SSA argument is not defined INSIDE the block, we have
// cross-block liveness, which we forbid in the IR to simplify RA.
if (!(Arg.ID() >= BlockIROp->Begin.ID() &&
Arg.ID() < BlockIROp->Last.ID())) {
HadError |= true;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition not local!" << std::endl;
continue;
}
else if (Arg.ID() < BlockIROp->Begin.ID()) {
// If the SSA argument is defined BEFORE this block
// then THIS block needs to be dominated by the flow of blocks up until this point

// Eg: Valid
// CodeBlock_1:
// %_1 = Load
// %_2 = Load
// Jump %CodeBlock_2
//
// CodeBlock_2:
// %_3 = <Op> %_1, %_2
//
// Eg: Invalid
// CodeBlock_1:
// %_1 = Load
// %_2 = Load
// Jump %CodeBlock_3
//
// CodeBlock_2:
// %_3 = <Op> %_1, %_2
//
// CodeBlock_3:
// ...

// We need to walk the predecessors to see if the value comes from there
fextl::set<IR::OrderedNode *> Predecessors { BlockNode };
// Recursively gather all predecessors of BlockNode
for (auto NodeIt = Predecessors.begin(); NodeIt != Predecessors.end();) {
auto PredBlock = &OffsetToBlockMap.try_emplace(CurrentIR.GetID(*NodeIt)).first->second;
++NodeIt;

for (auto *Pred : PredBlock->Predecessors) {
if (Predecessors.insert(Pred).second) {
// New blocks added, so repeat from the beginning to pull in their predecessors
NodeIt = Predecessors.begin();
}
}
}

bool FoundPredDefine = false;

for (auto* Pred : Predecessors) {
auto PredIROp = CurrentIR.GetOp<FEXCore::IR::IROp_CodeBlock>(Pred);

if (Arg.ID() >= PredIROp->Begin.ID() &&
Arg.ID() < PredIROp->Last.ID()) {
FoundPredDefine = true;
break;
}
Errors << "\tChecking Pred %" << CurrentIR.GetID(Pred) << std::endl;
}

if (!FoundPredDefine) {
HadError |= true;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition does not dominate this use! But was defined before this block!" << std::endl;
}
}
else if (Arg.ID() > BlockIROp->Last.ID()) {
// If this SSA argument is defined AFTER this block then it is just completely broken
// Eg: Invalid
// CodeBlock_1:
// %_1 = Load
// %_2 = <Op> %_1, %_3
// Jump %CodeBlock_2
//
// CodeBlock_2:
// %_3 = Load
// The SSA argument is defined INSIDE this block.
// It must only be declared prior to this instruction
// Eg: Valid
// CodeBlock_1:
// %_1 = Load
// %_2 = Load
// %_3 = <Op> %_1, %_2
//
// Eg: Invalid
// CodeBlock_1:
// %_1 = Load
// %_2 = <Op> %_1, %_3
// %_3 = Load
if (Arg.ID() > CodeID) {
HadError |= true;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition does not dominate this use!" << std::endl;
}
Expand Down

0 comments on commit 7b3e031

Please sign in to comment.