Files
revng-revng/lib/IRCanonicalization/ExitSSAPass.cpp
T
Pietro Fezzardi e9d84264ff Reduce the number of emitted local variables in C
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
2022-12-24 02:47:10 +01:00

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);