IR: Print SSA values as %123 instead of %ssa123

This is less noisy with no loss of clarity, and follows the notation
used by both LLVM IR and NIR. (So, it should be familiar.)

Change done with:

    sed -i -e 's/%ssa/%/g' $(git grep -l '%ssa')

Signed-off-by: Alyssa Rosenzweig <alyssa@rosenzweig.io>
This commit is contained in:
Alyssa Rosenzweig committed 2023-07-13 11:52:36 -04:00
1 parent 9722c4c5a4
commit 491e4e2c23
20 files changed
+144 -144

No files matched your search

@@ -211,7 +211,7 @@ DEF_OP(Vector_FToF) {
// Little bit tricky here
// Sometimes is used to convert from a 128bit vector register
// in to a 64bit vector register with different sized elements
// eg: %ssa5 i32v2 = Vector_FToF %ssa4 i128, #0x8
// eg: %5 i32v2 = Vector_FToF %4 i128, #0x8
uint8_t Elements = OpSize == 8 ? 2 : OpSize / Op->SrcElementSize;
DO_VECTOR_1SRC_2TYPE_OP_NOSIZE(float, double, Func, 0, 0)
break;
+8 -8
View File
@@ -103,7 +103,7 @@ static void PrintArg(fextl::stringstream *out, IRListView const* IR, OrderedNode
if (ArgID.IsInvalid()) {
*out << "%Invalid";
} else {
*out << "%ssa" << std::dec << ArgID;
*out << "%" << std::dec << ArgID;
if (RAData) {
auto PhyReg = RAData->GetNodeRegister(ArgID);
@@ -202,8 +202,8 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation
++CurrentIndent;
AddIndent();
*out << "(%ssa0) " << "IRHeader ";
*out << "%ssa" << HeaderOp->Blocks.ID() << ", ";
*out << "(%0) " << "IRHeader ";
*out << "%" << HeaderOp->Blocks.ID() << ", ";
*out << "#" << std::dec << HeaderOp->BlockCount << std::endl;
for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) {
@@ -211,10 +211,10 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation
auto BlockIROp = BlockHeader->C<FEXCore::IR::IROp_CodeBlock>();
AddIndent();
*out << "(%ssa" << IR->GetID(BlockNode) << ") " << "CodeBlock ";
*out << "(%" << IR->GetID(BlockNode) << ") " << "CodeBlock ";
*out << "%ssa" << BlockIROp->Begin.ID() << ", ";
*out << "%ssa" << BlockIROp->Last.ID() << std::endl;
*out << "%" << BlockIROp->Begin.ID() << ", ";
*out << "%" << BlockIROp->Last.ID() << std::endl;
}
++CurrentIndent;
@@ -244,7 +244,7 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation
NumElements /= ElementSize;
}
*out << "%ssa" << std::dec << ID;
*out << "%" << std::dec << ID;
if (RAData) {
auto PhyReg = RAData->GetNodeRegister(ID);
@@ -284,7 +284,7 @@ void Dump(fextl::stringstream *out, IRListView const* IR, IR::RegisterAllocation
NumElements = IROp->Size / ElementSize;
}
*out << "(%ssa" << std::dec << ID << ' ';
*out << "(%" << std::dec << ID << ' ';
*out << 'i' << std::dec << (ElementSize * 8);
if (NumElements > 1) {
*out << 'v' << std::dec << NumElements;
+1 -1
View File
@@ -413,7 +413,7 @@ class IRParser: public FEXCore::IR::IREmitter {
}
// Check if we are pulling in some IR from the IR Printer
// Prints (%ssa%d) at the start of lines without a definition
// Prints (%%d) at the start of lines without a definition
if (Line[0] == '(') {
size_t DefinitionEnd = fextl::string::npos;
if ((DefinitionEnd = Line.find_first_of(')', CurrentPos)) != fextl::string::npos) {
@@ -546,32 +546,32 @@ void RCLSE::CalculateControlFlowInfo(FEXCore::IR::IREmitter *IREmit) {
* @brief This pass removes redundant pairs of storecontext and loadcontext ops
*
* eg.
* %ssa26 i128 = LoadMem %ssa25 i64, 0x10
* (%%ssa27) StoreContext %ssa26 i128, 0x10, 0xb0
* %ssa28 i128 = LoadContext 0x10, 0x90
* %ssa29 i128 = LoadContext 0x10, 0xb0
* %26 i128 = LoadMem %25 i64, 0x10
* (%%27) StoreContext %26 i128, 0x10, 0xb0
* %28 i128 = LoadContext 0x10, 0x90
* %29 i128 = LoadContext 0x10, 0xb0
* Converts to
* %ssa26 i128 = LoadMem %ssa25 i64, 0x10
* (%%ssa27) StoreContext %ssa26 i128, 0x10, 0xb0
* %ssa28 i128 = LoadContext 0x10, 0x90
* %26 i128 = LoadMem %25 i64, 0x10
* (%%27) StoreContext %26 i128, 0x10, 0xb0
* %28 i128 = LoadContext 0x10, 0x90
*
* eg.
* %ssa6 i128 = LoadContext 0x10, 0x90
* %ssa7 i128 = LoadContext 0x10, 0x90
* %ssa8 i128 = VXor %ssa7 i128, %ssa6 i128
* %6 i128 = LoadContext 0x10, 0x90
* %7 i128 = LoadContext 0x10, 0x90
* %8 i128 = VXor %7 i128, %6 i128
* Converts to
* %ssa6 i128 = LoadContext 0x10, 0x90
* %ssa7 i128 = VXor %ssa6 i128, %ssa6 i128
* %6 i128 = LoadContext 0x10, 0x90
* %7 i128 = VXor %6 i128, %6 i128
*
* eg.
* (%%ssa189) StoreContext %ssa188 i128, 0x10, 0xa0
* %ssa190 i128 = LoadContext 0x10, 0x90
* %ssa192 i128 = VAdd %ssa188 i128, %ssa190 i128, 0x10, 0x4
* (%%ssa193) StoreContext %ssa192 i128, 0x10, 0xa0
* (%%189) StoreContext %188 i128, 0x10, 0xa0
* %190 i128 = LoadContext 0x10, 0x90
* %192 i128 = VAdd %188 i128, %190 i128, 0x10, 0x4
* (%%193) StoreContext %192 i128, 0x10, 0xa0
* Converts to
* %ssa173 i128 = LoadContext 0x10, 0x90
* %ssa175 i128 = VAdd %ssa172 i128, %ssa173 i128, 0x10, 0x4
* (%%ssa176) StoreContext %ssa175 i128, 0x10, 0xa0
* %173 i128 = LoadContext 0x10, 0x90
* %175 i128 = VAdd %172 i128, %173 i128, 0x10, 0x4
* (%%176) StoreContext %175 i128, 0x10, 0xa0
*/
bool RCLSE::RedundantStoreLoadElimination(FEXCore::IR::IREmitter *IREmit) {
@@ -183,7 +183,7 @@ bool IRCompaction::Run(IREmitter *IREmit) {
#ifndef NDEBUG
LOGMAN_THROW_A_FMT(NewArg.Value != UINT32_MAX,
"Tried remapping unfound node %ssa{}", OldArg);
"Tried remapping unfound node %{}", OldArg);
#endif
LocalIROp->Args[i].NodeOffset = NewArg.Value * sizeof(OrderedNode);
+14 -14
View File
@@ -82,13 +82,13 @@ bool IRValidation::Run(IREmitter *IREmit) {
HadError |= OpSize == 0;
// Does the op have a destination of size 0?
if (OpSize == 0) {
Errors << "%ssa" << ID << ": Had destination but with no size" << std::endl;
Errors << "%" << ID << ": Had destination but with no size" << std::endl;
}
// Does the node have zero uses? Should have been DCE'd
if (CodeNode->GetUses() == 0) {
HadWarning |= true;
Warnings << "%ssa" << ID << ": Destination created but had no uses" << std::endl;
Warnings << "%" << ID << ": Destination created but had no uses" << std::endl;
}
if (RAData) {
@@ -101,20 +101,20 @@ bool IRValidation::Run(IREmitter *IREmit) {
// If no register class was assigned
if (AssignedClass == IR::InvalidClass) {
HadError |= true;
Errors << "%ssa" << ID << ": Had destination but with no register class assigned" << std::endl;
Errors << "%" << ID << ": Had destination but with no register class assigned" << std::endl;
}
// If no physical register was assigned
if (PhyReg.Reg == IR::InvalidReg) {
HadError |= true;
Errors << "%ssa" << ID << ": Had destination but with no register assigned" << std::endl;
Errors << "%" << ID << ": Had destination but with no register assigned" << std::endl;
}
// Assigned class wasn't the expected class and it is a non-complex op
if (AssignedClass != ExpectedClass &&
ExpectedClass != IR::ComplexClass) {
HadWarning |= true;
Warnings << "%ssa" << ID << ": Destination had register class " << AssignedClass.Val << " When register class " << ExpectedClass.Val << " Was expected" << std::endl;
Warnings << "%" << ID << ": Destination had register class " << AssignedClass.Val << " When register class " << ExpectedClass.Val << " Was expected" << std::endl;
}
}
}
@@ -128,12 +128,12 @@ bool IRValidation::Run(IREmitter *IREmit) {
// Was an argument defined after this node?
if (ArgID >= ID) {
HadError |= true;
Errors << "%ssa" << ID << ": Arg[" << i << "] has definition after use at %ssa" << ArgID << std::endl;
Errors << "%" << ID << ": Arg[" << i << "] has definition after use at %" << ArgID << std::endl;
}
if (ArgID.IsValid() && !NodeIsLive.Get(ArgID.Value)) {
HadError |= true;
Errors << "%ssa" << ID << ": Arg[" << i << "] references dead %ssa" << ArgID << std::endl;
Errors << "%" << ID << ": Arg[" << i << "] references dead %" << ArgID << std::endl;
}
if (ArgID.IsValid()) {
@@ -162,7 +162,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
if (TrueTargetOp->Op != OP_CODEBLOCK) {
HadError |= true;
Errors << "CondJump %ssa" << ID << ": True Target Jumps to Op that isn't the begining of a block" << std::endl;
Errors << "CondJump %" << ID << ": True Target Jumps to Op that isn't the begining of a block" << std::endl;
}
else {
auto Block = OffsetToBlockMap.try_emplace(Op->TrueBlock.ID()).first;
@@ -171,7 +171,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
if (FalseTargetOp->Op != OP_CODEBLOCK) {
HadError |= true;
Errors << "CondJump %ssa" << ID << ": False Target Jumps to Op that isn't the begining of a block" << std::endl;
Errors << "CondJump %" << ID << ": False Target Jumps to Op that isn't the begining of a block" << std::endl;
}
else {
auto Block = OffsetToBlockMap.try_emplace(Op->FalseBlock.ID()).first;
@@ -188,7 +188,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
FEXCore::IR::IROp_Header const *TargetOp = CurrentIR.GetOp<IROp_Header>(TargetNode);
if (TargetOp->Op != OP_CODEBLOCK) {
HadError |= true;
Errors << "Jump %ssa" << ID << ": Jump to Op that isn't the begining of a block" << std::endl;
Errors << "Jump %" << ID << ": Jump to Op that isn't the begining of a block" << std::endl;
}
else {
auto Block = OffsetToBlockMap.try_emplace(Op->Header.Args[0].ID()).first;
@@ -206,7 +206,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
size_t NumSuccessors = CurrentBlock->Successors.size();
if (NumSuccessors > 2) {
HadError |= true;
Errors << "%ssa" << BlockID << " Has " << NumSuccessors << " successors which is too many" << std::endl;
Errors << "%" << BlockID << " Has " << NumSuccessors << " successors which is too many" << std::endl;
}
{
@@ -222,7 +222,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
auto Op = GetOp(CodeCurrent);
if (Op != IR::OP_ENDBLOCK) {
HadError |= true;
Errors << "%ssa" << BlockID << " Failed to end block with EndBlock" << std::endl;
Errors << "%" << BlockID << " Failed to end block with EndBlock" << std::endl;
}
}
@@ -233,7 +233,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
auto Op = GetOp(CodeCurrent);
if (!IsBlockExit(Op)) {
HadError |= true;
Errors << "%ssa" << BlockID << " Didn't have a block exit IR op as its last instruction" << std::endl;
Errors << "%" << BlockID << " Didn't have a block exit IR op as its last instruction" << std::endl;
}
}
}
@@ -243,7 +243,7 @@ bool IRValidation::Run(IREmitter *IREmit) {
auto [Node, IROp] = CurrentIR.at(IR::NodeID{i})();
if (Node->NumUses != Uses[i] && IROp->Op != OP_CODEBLOCK && IROp->Op != OP_IRHEADER) {
HadError |= true;
Errors << "%ssa" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl;
Errors << "%" << i << " Has " << Uses[i] << " Uses, but reports " << Node->NumUses << std::endl;
}
}
@@ -47,7 +47,7 @@ bool PhiValidation::Run(IREmitter *IREmit) {
// If we have found a non-phi IR op and then had a Phi or PhiValue value then this is a programming mistake
// PHI values MUST be defined at the top of the block only
HadError |= true;
Errors << "Phi %ssa" << CurrentIR.GetID(CodeNode) << ": Was defined after non-phi operations. Which is invalid!" << std::endl;
Errors << "Phi %" << CurrentIR.GetID(CodeNode) << ": Was defined after non-phi operations. Which is invalid!" << std::endl;
}
// Check all the phi values to ensure they have the same type
@@ -297,28 +297,28 @@ bool RAValidation::Run(IREmitter *IREmit) {
auto CurrentSSAAtReg = BlockRegState.Get(PhyReg);
if (CurrentSSAAtReg == RegState::InvalidReg) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: Arg[{}] unknown Reg: {}, class: {}\n", ID, i, PhyReg.Reg, PhyReg.Class);
Errors << fextl::fmt::format("%{}: Arg[{}] unknown Reg: {}, class: {}\n", ID, i, PhyReg.Reg, PhyReg.Class);
} else if (CurrentSSAAtReg == RegState::CorruptedPair) {
HadError |= true;
auto Lower = BlockRegState.Get(PhysicalRegister(GPRClass, uint8_t(PhyReg.Reg*2) + 1));
auto Upper = BlockRegState.Get(PhysicalRegister(GPRClass, PhyReg.Reg*2 + 1));
Errors << fextl::fmt::format("%ssa{}: Arg[{}] expects paired reg{} to contain %ssa{}, but it actually contains {{%ssa{}, %ssa{}}}\n",
Errors << fextl::fmt::format("%{}: Arg[{}] expects paired reg{} to contain %{}, but it actually contains {{%{}, %{}}}\n",
ID, i, PhyReg.Reg, ArgID, Lower, Upper);
} else if (CurrentSSAAtReg == RegState::UninitializedValue) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: Arg[{}] expects reg{} to contain %ssa{}, but it is uninitialized\n",
Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it is uninitialized\n",
ID, i, PhyReg.Reg, ArgID);
} else if (CurrentSSAAtReg == RegState::ClobberedValue) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: Arg[{}] expects reg{} to contain %ssa{}, but contents vary depending on control flow\n",
Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but contents vary depending on control flow\n",
ID, i, PhyReg.Reg, ArgID);
} else if (CurrentSSAAtReg != ArgID) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: Arg[{}] expects reg{} to contain %ssa{}, but it actually contains %ssa{}\n",
Errors << fextl::fmt::format("%{}: Arg[{}] expects reg{} to contain %{}, but it actually contains %{}\n",
ID, i, PhyReg.Reg, ArgID, CurrentSSAAtReg);
}
};
@@ -343,15 +343,15 @@ bool RAValidation::Run(IREmitter *IREmit) {
if (Value == RegState::UninitializedValue) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: FillRegister expected %ssa{} in Slot {}, but was undefined in at least one control flow path\n",
Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but was undefined in at least one control flow path\n",
ID, ExpectedValue, FillRegister->Slot);
} else if (Value == RegState::ClobberedValue) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: FillRegister expected %ssa{} in Slot {}, but contents vary depending on control flow\n",
Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but contents vary depending on control flow\n",
ID, ExpectedValue, FillRegister->Slot);
} else if (Value != ExpectedValue) {
HadError |= true;
Errors << fextl::fmt::format("%ssa{}: FillRegister expected %ssa{} in Slot {}, but it actually contains %ssa{}\n",
Errors << fextl::fmt::format("%{}: FillRegister expected %{} in Slot {}, but it actually contains %{}\n",
ID, ExpectedValue, FillRegister->Slot, Value);
}
break;
@@ -494,7 +494,7 @@ namespace {
const auto ArgNode = Arg.ID();
auto& ArgNodeLiveRange = LiveRanges[ArgNode.Value];
LOGMAN_THROW_AA_FMT(ArgNodeLiveRange.Begin.Value != UINT32_MAX,
"%ssa{} used by %ssa{} before defined?", ArgNode, Node);
"%{} used by %{} before defined?", ArgNode, Node);
const auto ArgNodeBlockID = Graph->Nodes[ArgNode.Value].Head.BlockID;
if (ArgNodeBlockID == BlockNodeID) {
@@ -1311,7 +1311,7 @@ namespace {
if (!CurrentNodes.contains(InterferenceNode)) {
InterferenceIdToSpill = InterferenceNode;
LogMan::Msg::DFmt("Panic spilling %ssa{}, Live Range[{}, {})", InterferenceIdToSpill, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
LogMan::Msg::DFmt("Panic spilling %{}, Live Range[{}, {})", InterferenceIdToSpill, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
return true;
}
return false;
@@ -1320,14 +1320,14 @@ namespace {
if (InterferenceIdToSpill.IsInvalid()) {
int j = 0;
LogMan::Msg::DFmt("node %ssa{}, was dumped in to virtual reg {}. Live Range[{}, {})",
LogMan::Msg::DFmt("node %{}, was dumped in to virtual reg {}. Live Range[{}, {})",
CurrentLocation, -1,
OpLiveRange->Begin, OpLiveRange->End);
RegisterNode->Interferences.Iterate([&](IR::NodeID InterferenceNode) {
auto *InterferenceLiveRange = &LiveRanges[InterferenceNode.Value];
LogMan::Msg::DFmt("\tInt{}: %ssa{} Remat: {} [{}, {})", j++, InterferenceNode, InterferenceLiveRange->RematCost, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
LogMan::Msg::DFmt("\tInt{}: %{} Remat: {} [{}, {})", j++, InterferenceNode, InterferenceLiveRange->RematCost, InterferenceLiveRange->Begin, InterferenceLiveRange->End);
});
}
LOGMAN_THROW_A_FMT(InterferenceIdToSpill.IsValid(), "Couldn't find Node to spill");
@@ -1395,7 +1395,7 @@ namespace {
auto FirstUseLocation = FindFirstUse(IREmit, ConstantNode, NextIter, NodeIterator::Invalid());
LOGMAN_THROW_A_FMT(FirstUseLocation != IR::NodeIterator::Invalid(),
"At %ssa{} Spilling Op %ssa{} but Failure to find op use",
"At %{} Spilling Op %{} but Failure to find op use",
Node, *InterferenceNode);
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
@@ -1454,7 +1454,7 @@ namespace {
auto FirstUseLocation = FindFirstUse(IREmit, InterferenceOrderedNode, FirstIter, NodeIterator::Invalid());
LOGMAN_THROW_A_FMT(FirstUseLocation != NodeIterator::Invalid(),
"At %ssa{} Spilling Op %ssa{} but Failure to find op use",
"At %{} Spilling Op %{} but Failure to find op use",
Node, *InterferenceNode);
if (FirstUseLocation != IR::NodeIterator::Invalid()) {
@@ -107,18 +107,18 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) {
// then it must only be declared prior to this instruction
// Eg: Valid
// CodeBlock_1:
// %ssa_1 = Load
// %ssa_2 = Load
// %ssa_3 = <Op> %ssa_1, %ssa_2
// %_1 = Load
// %_2 = Load
// %_3 = <Op> %_1, %_2
//
// Eg: Invalid
// CodeBlock_1:
// %ssa_1 = Load
// %ssa_2 = <Op> %ssa_1, %ssa_3
// %ssa_3 = Load
// %_1 = Load
// %_2 = <Op> %_1, %_3
// %_3 = Load
if (Arg.ID() > CodeID) {
HadError |= true;
Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition does not dominate this use!" << std::endl;
}
}
else if (Arg.ID() < BlockIROp->Begin.ID()) {
@@ -127,21 +127,21 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) {
// Eg: Valid
// CodeBlock_1:
// %ssa_1 = Load
// %ssa_2 = Load
// %_1 = Load
// %_2 = Load
// Jump %CodeBlock_2
//
// CodeBlock_2:
// %ssa_3 = <Op> %ssa_1, %ssa_2
// %_3 = <Op> %_1, %_2
//
// Eg: Invalid
// CodeBlock_1:
// %ssa_1 = Load
// %ssa_2 = Load
// %_1 = Load
// %_2 = Load
// Jump %CodeBlock_3
//
// CodeBlock_2:
// %ssa_3 = <Op> %ssa_1, %ssa_2
// %_3 = <Op> %_1, %_2
//
// CodeBlock_3:
// ...
@@ -171,26 +171,26 @@ bool ValueDominanceValidation::Run(IREmitter *IREmit) {
FoundPredDefine = true;
break;
}
Errors << "\tChecking Pred %ssa" << CurrentIR.GetID(Pred) << std::endl;
Errors << "\tChecking Pred %" << CurrentIR.GetID(Pred) << std::endl;
}
if (!FoundPredDefine) {
HadError |= true;
Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use! But was defined before this block!" << std::endl;
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:
// %ssa_1 = Load
// %ssa_2 = <Op> %ssa_1, %ssa_3
// %_1 = Load
// %_2 = <Op> %_1, %_3
// Jump %CodeBlock_2
//
// CodeBlock_2:
// %ssa_3 = Load
// %_3 = Load
HadError |= true;
Errors << "Inst %ssa" << CodeID << ": Arg[" << i << "] %ssa" << Arg.ID() << " definition does not dominate this use!" << std::endl;
Errors << "Inst %" << CodeID << ": Arg[" << i << "] %" << Arg.ID() << " definition does not dominate this use!" << std::endl;
}
}
}
+10 -10
View File
@@ -32,17 +32,17 @@ SSA is quite nice to work with when translating the x86-64 code to the IR, when
* Read the python generation file to determine the extent of what it can do
## IR function considerations
The first SSA node is a special case node that is considered invalid. This means %ssa0 will always be invalid for "null" node checks
The first real SSA node also has to be a IRHeader node. This means it is safe to assume that %ssa1 will always be an IRHeader.
The first SSA node is a special case node that is considered invalid. This means %0 will always be invalid for "null" node checks
The first real SSA node also has to be a IRHeader node. This means it is safe to assume that %1 will always be an IRHeader.
```(%%ssa1) IRHeader 0x41a9a0, %%ssa2, 5```
```(%%1) IRHeader 0x41a9a0, %%2, 5```
The header provides information about that function like the entry point address.
Additionally it also points to the first `CodeBlock` IROp
```(%%ssa2) CodeBlock %%ssa7, %%ssa168, %%ssa3```
```(%%2) CodeBlock %%7, %%168, %%3```
* The `CodeBlock` Op is a jump target and must be treated as if it'll be jumped to from other blocks
@@ -54,12 +54,12 @@ Additionally it also points to the first `CodeBlock` IROp
### Example code block
```
(%%ssa3) CodeBlock %%ssa169, %%ssa173, %%ssa4
(%%ssa169) BeginBlock %ssa3
%ssa170 i64 = Constant 0x41a9e1
(%%ssa171) StoreContext %ssa170 i64, 0x8, 0x0
(%%ssa172) ExitFunction
(%%ssa173) EndBlock %ssa3
(%%3) CodeBlock %%169, %%173, %%4
(%%169) BeginBlock %3
%170 i64 = Constant 0x41a9e1
(%%171) StoreContext %170 i64, 0x8, 0x0
(%%172) ExitFunction
(%%173) EndBlock %3
```
* BeginBlock points back to the CodeBlock SSA which helps with iterating across multiple blocks
+17 -17
View File
@@ -17,23 +17,23 @@ Ex:
Translates to the IR of:
```
BeginBlock
%ssa8 i32 = Constant 0x1
StoreContext 0x8, 0x8, %ssa8
%ssa64 i32 = Constant 0x1
StoreContext 0x8, 0x30, %ssa64
%ssa120 i32 = Constant 0x1f
StoreContext 0x8, 0x28, %ssa120
%ssa176 i32 = Constant 0x1
StoreContext 0x8, 0x20, %ssa176
%ssa232 i64 = LoadContext 0x8, 0x8
%ssa264 i64 = LoadContext 0x8, 0x30
%ssa296 i64 = LoadContext 0x8, 0x28
%ssa328 i64 = LoadContext 0x8, 0x20
%ssa360 i64 = LoadContext 0x8, 0x58
%ssa392 i64 = LoadContext 0x8, 0x48
%ssa424 i64 = LoadContext 0x8, 0x50
%ssa456 i64 = Syscall%ssa232, %ssa264, %ssa296, %ssa328, %ssa360, %ssa392, %ssa424
StoreContext 0x8, 0x8, %ssa456
%8 i32 = Constant 0x1
StoreContext 0x8, 0x8, %8
%64 i32 = Constant 0x1
StoreContext 0x8, 0x30, %64
%120 i32 = Constant 0x1f
StoreContext 0x8, 0x28, %120
%176 i32 = Constant 0x1
StoreContext 0x8, 0x20, %176
%232 i64 = LoadContext 0x8, 0x8
%264 i64 = LoadContext 0x8, 0x30
%296 i64 = LoadContext 0x8, 0x28
%328 i64 = LoadContext 0x8, 0x20
%360 i64 = LoadContext 0x8, 0x58
%392 i64 = LoadContext 0x8, 0x48
%424 i64 = LoadContext 0x8, 0x50
%456 i64 = Syscall%232, %264, %296, %328, %360, %392, %424
StoreContext 0x8, 0x8, %456
BeginBlock
EndBlock 0x1e
ExitFunction
+6 -6
View File
@@ -124,7 +124,7 @@ friend class FEXCore::IR::PassManager;
void SetJumpTarget(IR::IROp_Jump *Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting Jump target to %ssa{} {}",
"Tried setting Jump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
@@ -132,7 +132,7 @@ friend class FEXCore::IR::PassManager;
}
void SetTrueJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %ssa{} {}",
"Tried setting CondJump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
@@ -140,7 +140,7 @@ friend class FEXCore::IR::PassManager;
}
void SetFalseJumpTarget(IR::IROp_CondJump *Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %ssa{} {}",
"Tried setting CondJump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
@@ -149,7 +149,7 @@ friend class FEXCore::IR::PassManager;
void SetJumpTarget(IRPair<IROp_Jump> Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting Jump target to %ssa{} {}",
"Tried setting Jump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
@@ -157,14 +157,14 @@ friend class FEXCore::IR::PassManager;
}
void SetTrueJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %ssa{} {}",
"Tried setting CondJump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
Op.first->TrueBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
}
void SetFalseJumpTarget(IRPair<IROp_CondJump> Op, OrderedNode *Target) {
LOGMAN_THROW_A_FMT(Target->Op(DualListData.DataBegin())->Op == OP_CODEBLOCK,
"Tried setting CondJump target to %ssa{} {}",
"Tried setting CondJump target to %{} {}",
Target->Wrapped(DualListData.ListBegin()).ID(),
IR::GetName(Target->Op(DualListData.DataBegin())->Op));
Op.first->FalseBlock.NodeOffset = Target->Wrapped(DualListData.ListBegin()).NodeOffset;
+4 -4
View File
@@ -12,12 +12,12 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %start, %end, %ssa1
(%start i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %start, %end, %1
(%start i0) BeginBlock %2
%Addr i64 = Constant #0x100000
%Val i32 = LoadMem GPR, #8, %Addr i64, %Invalid, #8, SXTX, #1
(%Store i64) StoreRegister %Val i64, #0, #8, GPR, GPRFixed, #8
(%brk i0) Break {0.11.0.128}
(%end i0) EndBlock %ssa2
(%end i0) EndBlock %2
+4 -4
View File
@@ -17,9 +17,9 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %start, %end, %ssa1
(%start i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %start, %end, %1
(%start i0) BeginBlock %2
%Addr1 i64 = Constant #0x1000000
%Val i64 = LoadMem GPR, #8, %Addr1 i64, %Invalid, #8, SXTX, #1
; Test aligned special cases
@@ -39,4 +39,4 @@
%Res5 i64 = Sbfe #0x4, #0x2, %Val2
(%Store5 i64) StoreRegister %Res5 i64, #0, #0x38, GPR, GPRFixed, #8
(%brk i0) Break {0.11.0.128}
(%end i0) EndBlock %ssa2
(%end i0) EndBlock %2
+5 -5
View File
@@ -6,10 +6,10 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %ssa6, %ssa8, %ssa3
(%ssa6 i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %6, %8, %3
(%6 i0) BeginBlock %2
%Value i64 = Constant #0x4142434445464748
(%Store i64) StoreRegister %Value i64, #0, #0x8, GPR, GPRFixed, #8
(%ssa7 i0) Break {0.11.0.128}
(%ssa8 i0) EndBlock %ssa2
(%7 i0) Break {0.11.0.128}
(%8 i0) EndBlock %2
+5 -5
View File
@@ -16,9 +16,9 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %ssa6, %ssa12, %ssa1
(%ssa6 i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %6, %12, %1
(%6 i0) BeginBlock %2
%AddrA i64 = Constant #0x1000000
%MemValueA i64 = LoadMem GPR, #8, %AddrA i64, %Invalid, #8, SXTX, #1
%AddrB i64 = Constant #0x1000010
@@ -35,5 +35,5 @@
%ResultD i64 = Add %ValueC, %ValueD
(%Store i64) StoreRegister %ResultC i64, #0, #0x10, GPR, GPRFixed, #8
(%Store i64) StoreRegister %ResultD i64, #0, #0x18, GPR, GPRFixed, #8
(%ssa7 i0) Break {0.11.0.128}
(%ssa12 i0) EndBlock %ssa2
(%7 i0) Break {0.11.0.128}
(%12 i0) EndBlock %2
+5 -5
View File
@@ -19,9 +19,9 @@
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %ssa6, %end, %begin
(%begin i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %6, %end, %begin
(%begin i0) BeginBlock %2
; Clear registers
%AddrB i64 = Constant #0x1000010
@@ -61,5 +61,5 @@
(%Store8 i128) StoreRegister %Truncated8 i128, #0, #0x1a0, FPR, FPRFixed, #0x10
(%Store9 i128) StoreRegister %MemValueA i128, #0, #0x1c0, FPR, FPRFixed, #0x10
(%ssa7 i0) Break {0.11.0.128}
(%end i0) EndBlock %ssa2
(%7 i0) Break {0.11.0.128}
(%end i0) EndBlock %2
@@ -16,9 +16,9 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %ssa6, %ssa12, %ssa1
(%ssa6 i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %6, %12, %1
(%6 i0) BeginBlock %2
%AddrA i64 = Constant #0x1000000
%MemValueA i32 = LoadMem GPR, #4, %AddrA i64, %Invalid, #4, SXTX, #1
%Shift i64 = Constant #0x1
@@ -32,5 +32,5 @@
%ResultD i64 = Lshl #8, %ValueB, %Shift
(%Store i64) StoreRegister %ResultC i64, #0, #0x10, GPR, GPRFixed, #8
(%Store i64) StoreRegister %ResultD i64, #0, #0x18, GPR, GPRFixed, #8
(%ssa7 i0) Break {0.11.0.128}
(%ssa12 i0) EndBlock %ssa2
(%7 i0) Break {0.11.0.128}
(%12 i0) EndBlock %2
+5 -5
View File
@@ -16,9 +16,9 @@
;}
;%endif
(%ssa1) IRHeader %ssa2, #0
(%ssa2) CodeBlock %ssa6, %ssa12, %ssa1
(%ssaStart i0) BeginBlock %ssa2
(%1) IRHeader %2, #0
(%2) CodeBlock %6, %12, %1
(%Start i0) BeginBlock %2
%AddrA i64 = Constant #0x1000000
%MemValueA i64 = LoadMem GPR, #8, %AddrA i64, %Invalid, #8, SXTX, #1
%AddrB i64 = Constant #0x1000010
@@ -34,5 +34,5 @@
%ResultD i64 = Sub %ValueC, %ValueD
(%Store i64) StoreRegister %ResultC i64, #0, #0x10, GPR, GPRFixed, #8
(%Store i64) StoreRegister %ResultD i64, #0, #0x18, GPR, GPRFixed, #8
(%ssa7 i0) Break {0.11.0.128}
(%ssa12 i0) EndBlock %ssa2
(%7 i0) Break {0.11.0.128}
(%12 i0) EndBlock %2