Files
revng-revng/lib/Decompiler/AddSCEVBarrierPass.cpp
T
Pietro Fezzardi 4767fa63c3 Fixed emission for local_sp and scev_barrier
This commit fixes a bug due to interacting behaviors between
MarkForSerialization, AddSCEVBarrierPass, and the emission in C of calls
to revng_init_local_sp.

These interacting behaviors caused the following quirks:
- At the beginning of Functions that contained a call to
  `revng_init_local_sp()`, that call was actually emitted twice.
  The first time was due to the actual call to `revng_init_local_sp()`,
  while the second was due to the first call being wrapped from a call
  to `revng_scev_barrier_*`.
  Now we properly emit only one call.
- The original call to `revng_init_local_sp()` was supposed to generate
  a local variable, to be used in various places across the function.
  However, due to the fact that the call was not properly labeled by
  MarkForSerialization, there was no local variable, causing calls to
  `revng_init_local_sp()` to be scattered around the body of the
  functions, follwed by various arithmetic operations.
  This behavior has been fixed as well, and we now emit the local
  variable correctly.
2021-02-02 11:23:53 +01:00

99 lines
3.0 KiB
C++

//
// Copyright (c) rev.ng Srls. See LICENSE.md for details.
//
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/Casting.h"
#include "revng-c/Decompiler/MarkForSerialization.h"
struct AddSCEVBarrierPass : public llvm::FunctionPass {
static char ID;
AddSCEVBarrierPass() : llvm::FunctionPass(ID) {}
bool runOnFunction(llvm::Function &F) override;
void getAnalysisUsage(llvm::AnalysisUsage &AU) const override {
AU.addUsedIfAvailable<MarkForSerializationPass>();
AU.setPreservesAll(); // Only the CFG is preserved, because we insert calls.
}
};
char AddSCEVBarrierPass::ID = 0;
using Pass = AddSCEVBarrierPass;
using llvm::RegisterPass;
static RegisterPass<Pass> X("add-scev-barrier", "Pass to add SCEV barriers");
static std::string makeTypeName(const llvm::Type *Ty) {
std::string Name;
if (auto *PtrTy = llvm::dyn_cast<llvm::PointerType>(Ty)) {
Name = "ptr_to_" + makeTypeName(PtrTy->getElementType());
} else if (auto *IntTy = llvm::dyn_cast<llvm::IntegerType>(Ty)) {
Name = "i" + std::to_string(IntTy->getBitWidth());
} else {
revng_unreachable("cannot build Type name");
}
return Name;
}
std::string makeSCEVBarrierName(const llvm::Type *Ty) {
return "revng_scev_barrier_" + makeTypeName(Ty);
}
bool AddSCEVBarrierPass::runOnFunction(llvm::Function &F) {
// Skip non-isolated functions
if (not F.hasMetadata("revng.func.entry"))
return false;
// If the MarkForSerializationPass was not executed, we have nothing to do.
auto *MarkPass = getAnalysisIfAvailable<MarkForSerializationPass>();
if (not MarkPass)
return false;
const auto &MarkMap = MarkPass->getMap();
llvm::Module *M = F.getParent();
llvm::IRBuilder<> Builder(M->getContext());
bool Changed = false;
for (auto &I : llvm::instructions(&F)) {
// Check if I was marked for serialization, and skip it if it wasn't marked.
auto MarkIt = MarkMap.find(&I);
if (MarkIt == MarkMap.end())
continue;
// If it was marked for serialization, see how.
const SerializationFlags &Flags = MarkIt->second;
auto *IType = I.getType();
if (SerializationFlags::mustBeSerialized(Flags) and IType->isIntOrPtrTy()) {
// Get the SCEV barrier function associated with IType
auto BarrierName = makeSCEVBarrierName(IType);
auto SCEVBarrierF = M->getOrInsertFunction(BarrierName, IType, IType);
// Insert a call to the SCEV barrier right after I. For now the call to
// barrier has an undef argument, that will be fixed later.
Builder.SetInsertPoint(I.getParent(), std::next(I.getIterator()));
auto *Undef = llvm::UndefValue::get(IType);
auto *Call = Builder.CreateCall(SCEVBarrierF, Undef);
// Replace all uses of I with the new call.
I.replaceAllUsesWith(Call);
// Now Fix the call to use I as argument.
Call->setArgOperand(0, &I);
Changed = true;
}
}
return Changed;
}