mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
195 lines
6.2 KiB
C++
195 lines
6.2 KiB
C++
#pragma once
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#include <cstdint>
|
|
#include <map>
|
|
#include <string>
|
|
|
|
#include "llvm/IR/IRBuilder.h"
|
|
#include "llvm/Pass.h"
|
|
|
|
#include "revng/Support/CommandLine.h"
|
|
#include "revng/Support/IRHelpers.h"
|
|
|
|
#include "CPUStateAccessAnalysisPass.h"
|
|
#include "PTCDump.h"
|
|
|
|
namespace llvm {
|
|
class AllocaInst;
|
|
class BasicBlock;
|
|
class DataLayout;
|
|
class GlobalVariable;
|
|
class Module;
|
|
class StructType;
|
|
class Value;
|
|
} // namespace llvm
|
|
|
|
class VariableManager;
|
|
|
|
// TODO: rename
|
|
extern llvm::cl::opt<bool> External;
|
|
|
|
/// Maintain the list of variables required by PTC
|
|
///
|
|
/// It can be queried for a variable, which, if not already existing, will be
|
|
/// created on the fly.
|
|
class VariableManager {
|
|
public:
|
|
VariableManager(llvm::Module &M,
|
|
bool TargetIsLittleEndian,
|
|
llvm::StructType *CPUStruct,
|
|
unsigned EnvOffset);
|
|
|
|
void setAllocaInsertPoint(llvm::Instruction *I) {
|
|
AllocaBuilder.SetInsertPoint(I);
|
|
}
|
|
|
|
llvm::Instruction *load(llvm::IRBuilder<> &Builder, unsigned TemporaryId) {
|
|
using namespace llvm;
|
|
|
|
auto &&[IsNew, V] = getOrCreate(TemporaryId, true);
|
|
|
|
if (V == nullptr)
|
|
return nullptr;
|
|
|
|
if (IsNew) {
|
|
auto *Undef = UndefValue::get(getVariableType(V));
|
|
Builder.CreateStore(Undef, V);
|
|
}
|
|
|
|
return createLoadVariable(Builder, V);
|
|
}
|
|
|
|
/// Get or create the LLVM value associated to a PTC temporary
|
|
///
|
|
/// Given a PTC temporary identifier, checks if it already exists in the
|
|
/// generated LLVM IR, and, if not, it creates it.
|
|
///
|
|
/// \param TemporaryId the PTC temporary identifier.
|
|
///
|
|
/// \return a `Value` wrapping the requested global or local variable.
|
|
llvm::Value *getOrCreate(unsigned TemporaryId) {
|
|
return getOrCreate(TemporaryId, false).second;
|
|
}
|
|
|
|
/// Return the global variable corresponding to \p Offset in the CPU state.
|
|
///
|
|
/// \param Offset the offset in the CPU state (the `env` PTC variable).
|
|
/// \param Name an optional name to force for the associate global variable.
|
|
///
|
|
/// \return a pair composed by the request global variable and the offset in
|
|
/// it corresponding to \p Offset. For instance, if you're accessing
|
|
/// the third byte of a 32-bit integer it will 2.
|
|
std::pair<llvm::GlobalVariable *, unsigned>
|
|
getByEnvOffset(intptr_t Offset, std::string Name = "") {
|
|
return getByCPUStateOffsetInternal(EnvOffset + Offset, Name);
|
|
}
|
|
|
|
/// Notify VariableManager to reset all the "function"-specific information
|
|
///
|
|
/// Informs the VariableManager that a new function has begun, so it can
|
|
/// discard function- and basic block-level variables.
|
|
///
|
|
/// Note: by "function" here we mean a function in PTC terms, i.e. a run of
|
|
/// code translated in a single shot by the TCG. Do not confuse this
|
|
/// function concept with other meanings.
|
|
///
|
|
/// \param Instructions the new PTCInstructionList to use from now on.
|
|
void newFunction(PTCInstructionList *Instructions);
|
|
|
|
/// Informs the VariableManager that a new basic block has begun, so it can
|
|
/// discard basic block-level variables.
|
|
void newBasicBlock() { Temporaries.clear(); }
|
|
|
|
/// Returns true if the given variable is the env variable
|
|
bool isEnv(llvm::Value *TheValue);
|
|
|
|
llvm::Value *computeEnvAddress(llvm::Type *TargetType,
|
|
llvm::Instruction *InsertBefore,
|
|
unsigned Offset = 0);
|
|
|
|
void setDataLayout(const llvm::DataLayout *NewLayout) {
|
|
ModuleLayout = NewLayout;
|
|
}
|
|
|
|
std::vector<llvm::AllocaInst *> locals() {
|
|
std::vector<llvm::AllocaInst *> Locals;
|
|
for (auto Pair : LocalTemporaries)
|
|
Locals.push_back(Pair.second);
|
|
return Locals;
|
|
}
|
|
|
|
llvm::Value *loadFromEnvOffset(llvm::IRBuilder<> &Builder,
|
|
unsigned LoadSize,
|
|
unsigned Offset) {
|
|
return loadFromCPUStateOffset(Builder, LoadSize, EnvOffset + Offset);
|
|
}
|
|
|
|
std::optional<llvm::StoreInst *> storeToEnvOffset(llvm::IRBuilder<> &Builder,
|
|
unsigned StoreSize,
|
|
unsigned Offset,
|
|
llvm::Value *ToStore) {
|
|
unsigned ActualOffset = EnvOffset + Offset;
|
|
return storeToCPUStateOffset(Builder, StoreSize, ActualOffset, ToStore);
|
|
}
|
|
|
|
bool memcpyAtEnvOffset(llvm::IRBuilder<> &Builder,
|
|
llvm::CallInst *CallMemcpy,
|
|
unsigned Offset,
|
|
bool EnvIsSrc);
|
|
|
|
/// Perform finalization steps on variables
|
|
void finalize();
|
|
|
|
void rebuildCSVList();
|
|
|
|
/// Gets the CPUStateType
|
|
llvm::StructType *getCPUStateType() const { return CPUStateType; }
|
|
|
|
bool hasEnv() const { return Env != nullptr; }
|
|
|
|
llvm::Value *cpuStateToEnv(llvm::Value *CPUState,
|
|
llvm::Instruction *InsertBefore) const;
|
|
|
|
private:
|
|
std::pair<bool, llvm::Value *> getOrCreate(unsigned TemporaryId,
|
|
bool Reading);
|
|
|
|
llvm::Value *loadFromCPUStateOffset(llvm::IRBuilder<> &Builder,
|
|
unsigned LoadSize,
|
|
unsigned Offset);
|
|
|
|
std::optional<llvm::StoreInst *>
|
|
storeToCPUStateOffset(llvm::IRBuilder<> &Builder,
|
|
unsigned StoreSize,
|
|
unsigned Offset,
|
|
llvm::Value *ToStore);
|
|
|
|
llvm::GlobalVariable *getByCPUStateOffset(intptr_t Offset,
|
|
std::string Name = "");
|
|
|
|
std::pair<llvm::GlobalVariable *, unsigned>
|
|
getByCPUStateOffsetInternal(intptr_t Offset, std::string Name = "");
|
|
|
|
private:
|
|
llvm::Module &TheModule;
|
|
llvm::IRBuilder<> AllocaBuilder;
|
|
using TemporariesMap = std::map<unsigned int, llvm::AllocaInst *>;
|
|
using GlobalsMap = std::map<intptr_t, llvm::GlobalVariable *>;
|
|
GlobalsMap CPUStateGlobals;
|
|
GlobalsMap OtherGlobals;
|
|
TemporariesMap Temporaries;
|
|
TemporariesMap LocalTemporaries;
|
|
PTCInstructionList *Instructions = nullptr;
|
|
|
|
llvm::StructType *CPUStateType;
|
|
const llvm::DataLayout *ModuleLayout;
|
|
unsigned EnvOffset;
|
|
|
|
llvm::GlobalVariable *Env;
|
|
bool TargetIsLittleEndian;
|
|
};
|