mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
e9d84264ff
This commit does various things oriented at reducing the number of local variables emitted in C: - MarkAssignments now know that @Copy and @Assign involving @LocalVariable only have side effects that affect the local variable itself; this enables to reduce the number of times we're forced to emit a local variable due to interfering side effects - Drop the @AssignmentMarker FunctionTag; AddAssignmentMarkerPass now doesn't emit @AssignmentMarker anymore; instead it emits groups of @LocalVariable, @Copy, and @Assign, which benefit from the previous point - Drop 2 MarkAssignments::Reasons: HasManyUses and HasUsesOutsideOfBB; both these have now been aggregated into the AlwaysAssign reason for simplicity, representing all reasons non involving side effects - Update BeautifyGHAST and how it reasons about side effects when beautifying; before this commit it used @AssignmentMarker, now it looks at @Assign - Simplify ExitSSA; before this commit it was trying hard to be smart on where it emitted the store instructions representing the incoming values of the PHI that was being destroyed; this seemed smart when we originally did it but it generated C code that was not really better to read, so this useless complexity is finally gone
100 lines
2.7 KiB
C++
100 lines
2.7 KiB
C++
//
|
|
// Copyright rev.ng Labs Srl. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/IR/BasicBlock.h"
|
|
#include "llvm/IR/Function.h"
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/IR/Instruction.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/Pass.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "revng/ADT/SmallMap.h"
|
|
#include "revng/Support/Debug.h"
|
|
#include "revng/Support/FunctionTags.h"
|
|
#include "revng/Support/IRHelpers.h"
|
|
|
|
using llvm::AllocaInst;
|
|
using llvm::AnalysisUsage;
|
|
using llvm::BasicBlock;
|
|
using llvm::Function;
|
|
using llvm::FunctionPass;
|
|
using llvm::Instruction;
|
|
using llvm::IRBuilder;
|
|
using llvm::PHINode;
|
|
using llvm::RegisterPass;
|
|
using llvm::Value;
|
|
|
|
static Logger<> Log{ "exit-ssa" };
|
|
|
|
struct ExitSSAPass : public FunctionPass {
|
|
public:
|
|
static char ID;
|
|
|
|
ExitSSAPass() : FunctionPass(ID) {}
|
|
|
|
bool runOnFunction(Function &F) override;
|
|
|
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
|
AU.setPreservesCFG();
|
|
}
|
|
};
|
|
|
|
bool ExitSSAPass::runOnFunction(Function &F) {
|
|
|
|
// Skip non-isolated functions
|
|
if (not FunctionTags::Isolated.isTagOf(&F))
|
|
return false;
|
|
|
|
IRBuilder<> Builder(F.getContext());
|
|
Builder.SetInsertPoint(&F.getEntryBlock().front());
|
|
|
|
SmallMap<PHINode *, AllocaInst *, 8> PHIToAlloca;
|
|
for (BasicBlock &BB : F)
|
|
for (PHINode &PHI : BB.phis())
|
|
PHIToAlloca[&PHI] = Builder.CreateAlloca(PHI.getType());
|
|
|
|
if (PHIToAlloca.empty())
|
|
return false;
|
|
|
|
for (auto &[PHI, Alloca] : PHIToAlloca) {
|
|
for (auto &IncomingUse : PHI->incoming_values()) {
|
|
llvm::BasicBlock *BB = PHI->getIncomingBlock(IncomingUse);
|
|
Builder.SetInsertPoint(BB->getTerminator());
|
|
Value *Incoming = IncomingUse.get();
|
|
|
|
BasicBlock *IncomingDefBB = &F.getEntryBlock();
|
|
if (auto *I = dyn_cast<Instruction>(Incoming))
|
|
IncomingDefBB = I->getParent();
|
|
revng_assert(IncomingDefBB);
|
|
|
|
revng_log(Log, "Incoming: " << dumpToString(Incoming));
|
|
auto *S = Builder.CreateStore(Incoming, PHIToAlloca.at(PHI));
|
|
revng_log(Log, dumpToString(S));
|
|
}
|
|
}
|
|
|
|
for (auto &[PHI, Alloca] : PHIToAlloca) {
|
|
Builder.SetInsertPoint(PHI);
|
|
auto *Load = Builder.CreateLoad(Alloca);
|
|
PHI->replaceAllUsesWith(Load);
|
|
PHI->eraseFromParent();
|
|
}
|
|
|
|
for (BasicBlock &BB : F)
|
|
for (Instruction &I : BB)
|
|
revng_assert(not llvm::isa<PHINode>(I));
|
|
|
|
return not PHIToAlloca.empty();
|
|
}
|
|
|
|
char ExitSSAPass::ID = 0;
|
|
|
|
static RegisterPass<ExitSSAPass> X("exit-ssa",
|
|
"Transformation pass that exits from Static "
|
|
"Single Assignment form, promoting PHINodes "
|
|
"to sets of Allocas, Load and Stores",
|
|
false,
|
|
false);
|