mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
508719ad97
This commit is a hack, that removes an assertion on NDuplicates. For now we can remove this check, because we declare all the local variables at the beginning of the function body. Whenever we start emitting the declarations of local variables as-late-as-possible, we'll need to take care of this.
125 lines
3.6 KiB
C++
125 lines
3.6 KiB
C++
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
/// \brief Dataflow analysis to identify which Instructions must be serialized
|
|
|
|
// LLVM includes
|
|
#include <llvm/IR/BasicBlock.h>
|
|
#include <llvm/IR/Instructions.h>
|
|
|
|
// local libraries includes
|
|
#include "revng-c/RestructureCFGPass/BasicBlockNode.h"
|
|
#include "revng-c/RestructureCFGPass/RegionCFGTree.h"
|
|
|
|
// local includes
|
|
#include "MarkForSerialization.h"
|
|
|
|
static Logger<> MarkLog("mark-serialization");
|
|
|
|
using namespace llvm;
|
|
|
|
namespace MarkForSerialization {
|
|
|
|
static bool isPure(const Instruction & /*Call*/) {
|
|
return false;
|
|
}
|
|
|
|
void Analysis::initialize() {
|
|
Base::initialize();
|
|
ToSerialize.clear();
|
|
|
|
{
|
|
// one empty set for each BB
|
|
using InstrSet = std::set<Instruction *>;
|
|
ToSerializeInBB = std::vector<InstrSet>(F.size(), InstrSet{});
|
|
}
|
|
|
|
size_t I = 0;
|
|
for (BasicBlock &BB : F) {
|
|
// map BasicBlock pointer to the position in ToSerializeInBB
|
|
BBToIdMap[&BB] = I++;
|
|
}
|
|
}
|
|
|
|
Analysis::InterruptType Analysis::transfer(BasicBlock *BB) {
|
|
revng_log(MarkLog,
|
|
"transfer: BB in Function: " << BB->getParent()->getName() << '\n'
|
|
<< BB);
|
|
|
|
LatticeElement Pending = this->State[BB].copy();
|
|
|
|
size_t NBBDuplicates = NDuplicates.at(BB);
|
|
for (Instruction &I : *BB) {
|
|
revng_log(MarkLog, "Analyzing: '" << &I << "': " << dumpToString(&I));
|
|
// PHINodes are never serialized
|
|
if (isa<PHINode>(I))
|
|
continue;
|
|
|
|
// Skip branching instructions.
|
|
// Branch instructions are never serialized directly, because it's only
|
|
// after building an AST and matching ifs, loops, switches and others that
|
|
// we really know what kind of C statement we want to emit for a given
|
|
// branch.
|
|
if (isa<BranchInst>(I) or isa<SwitchInst>(I))
|
|
continue;
|
|
|
|
Pending.insert(&I);
|
|
revng_log(MarkLog, "Add to pending: '" << &I << "': " << dumpToString(&I));
|
|
revng_log(MarkLog, "Operands:");
|
|
MarkLog.indent();
|
|
for (auto &TheUse : I.operands()) {
|
|
Value *V = TheUse.get();
|
|
revng_log(MarkLog, "Op: '" << V << "': " << dumpToString(V));
|
|
MarkLog.indent();
|
|
if (auto *UseInstr = dyn_cast<Instruction>(V)) {
|
|
revng_log(MarkLog, "Op is Instruction");
|
|
Pending.erase(UseInstr);
|
|
} else {
|
|
revng_log(MarkLog, "Op is NOT Instruction");
|
|
revng_assert(isa<Argument>(V) or isa<Constant>(V) or isa<BasicBlock>(V)
|
|
or isa<MetadataAsValue>(V));
|
|
}
|
|
MarkLog.unindent();
|
|
}
|
|
MarkLog.unindent();
|
|
|
|
bool HasSideEffects = isa<AllocaInst>(&I) or isa<StoreInst>(&I)
|
|
or isa<InsertValueInst>(&I)
|
|
or (isa<CallInst>(&I) and not isPure(I));
|
|
if (HasSideEffects) {
|
|
revng_log(MarkLog, "Serialize Pending");
|
|
markSetToSerialize(Pending);
|
|
Pending = LatticeElement::top(); // empty set
|
|
markValueToSerialize(&I);
|
|
} else {
|
|
switch (I.getNumUses()) {
|
|
case 1: {
|
|
User *U = I.uses().begin()->getUser();
|
|
if (not isa<Instruction>(U)) {
|
|
Pending.insert(&I);
|
|
continue;
|
|
}
|
|
Instruction *UserI = cast<Instruction>(U);
|
|
auto *UserBB = UserI->getParent();
|
|
auto NUserDuplicates = NDuplicates.at(UserBB);
|
|
if (NBBDuplicates < NUserDuplicates) {
|
|
markValueToSerialize(&I);
|
|
} else {
|
|
Pending.insert(&I);
|
|
}
|
|
|
|
} break;
|
|
default:
|
|
revng_log(MarkLog, "Mark this to serialize");
|
|
markValueToSerialize(&I);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return InterruptType::createInterrupt(std::move(Pending));
|
|
}
|
|
|
|
} // namespace MarkForSerialization
|