mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
138 lines
4.2 KiB
C++
138 lines
4.2 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "revng/EarlyFunctionAnalysis/CallHandler.h"
|
|
#include "revng/EarlyFunctionAnalysis/Outliner.h"
|
|
#include "revng/EarlyFunctionAnalysis/TemporaryOpaqueFunction.h"
|
|
#include "revng/Model/Binary.h"
|
|
#include "revng/Support/OpaqueFunctionsPool.h"
|
|
#include "revng/Support/OpaqueRegisterUser.h"
|
|
|
|
class GeneratedCodeBasicInfo;
|
|
class ProgramCounterHandler;
|
|
class FunctionSummaryOracle;
|
|
|
|
namespace llvm {
|
|
class Module;
|
|
class GlobalVariable;
|
|
class Function;
|
|
} // namespace llvm
|
|
|
|
namespace efa {
|
|
|
|
class CallSummarizer : public CallHandler {
|
|
private:
|
|
llvm::Module *M = nullptr;
|
|
llvm::Function *PreCallHook = nullptr;
|
|
llvm::Function *PostCallHook = nullptr;
|
|
llvm::Function *RetHook = nullptr;
|
|
llvm::GlobalVariable *SPCSV = nullptr;
|
|
llvm::SmallSet<MetaAddress, 4> *ReturnBlocks = nullptr;
|
|
OpaqueRegisterUser Clobberer;
|
|
|
|
public:
|
|
CallSummarizer(llvm::Module *M,
|
|
llvm::Function *PreCallHook,
|
|
llvm::Function *PostCallHook,
|
|
llvm::Function *RetHook,
|
|
llvm::GlobalVariable *SPCSV,
|
|
llvm::SmallSet<MetaAddress, 4> *ReturnBlocks);
|
|
|
|
public:
|
|
void handleCall(MetaAddress CallerBlock,
|
|
llvm::IRBuilder<> &Builder,
|
|
MetaAddress Callee,
|
|
const CSVSet &ClobberedRegisters,
|
|
const std::optional<int64_t> &MaybeFSO,
|
|
bool IsNoReturn,
|
|
bool IsTailCall,
|
|
llvm::Value *SymbolNamePointer) final;
|
|
|
|
void handlePostNoReturn(llvm::IRBuilder<> &Builder) final;
|
|
|
|
void handleIndirectJump(llvm::IRBuilder<> &Builder,
|
|
MetaAddress Block,
|
|
const CSVSet &ClobberedRegisters,
|
|
llvm::Value *SymbolNamePointer) final;
|
|
};
|
|
|
|
/// This class, given an Oracle, analyzes a function returning its CFG, the set
|
|
/// of callee saved registers, whether it's noreturn or not and its final stack
|
|
/// offset
|
|
class CFGAnalyzer {
|
|
private:
|
|
llvm::Module &M;
|
|
GeneratedCodeBasicInfo &GCBI;
|
|
const ProgramCounterHandler *PCH = nullptr;
|
|
FunctionSummaryOracle &Oracle;
|
|
const TupleTree<model::Binary> &Binary;
|
|
|
|
llvm::SmallVector<llvm::GlobalVariable *, 16> ABICSVs;
|
|
|
|
/// PreCallHook and PostCallHook mark the presence of an original function
|
|
/// call, and surround a basic block containing the registers clobbered by the
|
|
/// function called. They take the MetaAddress of the callee and the
|
|
/// call-site.
|
|
TemporaryOpaqueFunction PreCallHook;
|
|
TemporaryOpaqueFunction PostCallHook;
|
|
TemporaryOpaqueFunction RetHook;
|
|
|
|
Outliner Outliner;
|
|
|
|
OpaqueFunctionsPool<llvm::Type *> OpaqueBranchConditionsPool;
|
|
std::unique_ptr<llvm::raw_ostream> OutputAAWriter;
|
|
std::unique_ptr<llvm::raw_ostream> OutputIBI;
|
|
|
|
public:
|
|
CFGAnalyzer(llvm::Module &M,
|
|
GeneratedCodeBasicInfo &GCBI,
|
|
const TupleTree<model::Binary> &Binary,
|
|
FunctionSummaryOracle &Oracle);
|
|
|
|
public:
|
|
llvm::Function *preCallHook() const { return PreCallHook.get(); }
|
|
llvm::Function *postCallHook() const { return PostCallHook.get(); }
|
|
llvm::Function *retHook() const { return RetHook.get(); }
|
|
const auto &abiCSVs() const { return ABICSVs; }
|
|
|
|
public:
|
|
FunctionSummary analyze(const MetaAddress &Entry);
|
|
|
|
OutlinedFunction outline(const MetaAddress &Entry);
|
|
|
|
private:
|
|
static llvm::FunctionType *createCallMarkerType(llvm::Module &M);
|
|
static llvm::FunctionType *createRetMarkerType(llvm::Module &M);
|
|
|
|
private:
|
|
std::optional<UpcastablePointer<efa::FunctionEdgeBase>>
|
|
handleCall(llvm::CallInst *PreCallHookCall);
|
|
|
|
SortedVector<efa::BasicBlock> collectDirectCFG(OutlinedFunction *F);
|
|
|
|
void createIBIMarker(OutlinedFunction *F);
|
|
|
|
void opaqueBranchConditions(llvm::Function *F, llvm::IRBuilder<> &);
|
|
|
|
void materializePCValues(llvm::Function *F, llvm::IRBuilder<> &);
|
|
|
|
void runOptimizationPipeline(llvm::Function *F);
|
|
|
|
FunctionSummary milkInfo(OutlinedFunction *F,
|
|
SortedVector<efa::BasicBlock> &&CFG);
|
|
|
|
struct State {
|
|
llvm::Value *StackPointer;
|
|
llvm::Value *ReturnPC;
|
|
llvm::SmallVector<llvm::Value *, 16> CSVs;
|
|
};
|
|
State loadState(llvm::IRBuilder<> &Builder) const;
|
|
};
|
|
|
|
} // namespace efa
|