Files
ROCm/lib/Target/LLVMIR/LLVMIRBreakPhiStruct.cpp
Thomas Raoux d3956a21f3 [BACKEND] Add LLVM pre-processing pass to break struct types (#2285)
Add infrastructure to be able to add and test custom LLVM passes in the
backend. This will allow use to apply some low level optimizations and
cleanup on LLVM IR.
Add a first pass that breaks up phi of struct created by lowering to
LLVM. Those can often pessimise the optimizer as it would block
optimizations going through phi nodes.
2023-09-13 10:03:29 -07:00

61 lines
2.2 KiB
C++

//===----------------------------------------------------------------------===//
/// Implements a trivial pass breaking up 1 level deep structure in phi nodes.
/// This handles the common case generated by Triton and allow better
/// optimizations down the compiler pipeline.
//===----------------------------------------------------------------------===//
#include "LLVMPasses.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
using namespace llvm;
static bool processPhiStruct(PHINode *phiNode) {
StructType *STy = dyn_cast<StructType>(phiNode->getType());
if (!STy)
return false;
IRBuilder<> builder(phiNode);
unsigned numOperands = phiNode->getNumIncomingValues();
unsigned numScalarEl = STy->getNumElements();
Value *newStruct = UndefValue::get(STy);
builder.SetInsertPoint(phiNode->getParent()->getFirstNonPHI());
llvm::IRBuilderBase::InsertPoint insertInsertPt = builder.saveIP();
for (unsigned i = 0; i < numScalarEl; i++) {
builder.SetInsertPoint(phiNode);
PHINode *newPhiNode =
builder.CreatePHI(STy->getElementType(i), numOperands);
for (unsigned j = 0; j < numOperands; ++j) {
Value *operand = phiNode->getIncomingValue(j);
builder.SetInsertPoint(phiNode->getIncomingBlock(j)->getTerminator());
newPhiNode->addIncoming(builder.CreateExtractValue(operand, i),
phiNode->getIncomingBlock(j));
}
builder.restoreIP(insertInsertPt);
newStruct = builder.CreateInsertValue(newStruct, newPhiNode, i);
insertInsertPt = builder.saveIP();
}
phiNode->replaceAllUsesWith(newStruct);
return true;
}
static bool runOnFunction(Function &F) {
bool Changed = false;
SmallVector<PHINode *> PhiNodes;
for (BasicBlock &BB : F) {
for (Instruction &inst : BB) {
if (PHINode *phiNode = dyn_cast<PHINode>(&inst)) {
Changed |= processPhiStruct(phiNode);
continue;
}
break;
}
}
return Changed;
}
PreservedAnalyses BreakStructPhiNodesPass::run(Function &F,
FunctionAnalysisManager &AM) {
bool b = runOnFunction(F);
return b ? PreservedAnalyses::none() : PreservedAnalyses::all();
}