mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
Split ptctollvmir.cpp into multiple files
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
/// \file
|
||||
/// \brief This file handles the creation and management of global variables,
|
||||
/// i.e. mainly parts of the CPU state
|
||||
|
||||
// Standard includes
|
||||
#include <cstdint>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
// LLVM includes
|
||||
#include "llvm/IR/DataLayout.h"
|
||||
#include "llvm/IR/GlobalVariable.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
// Local includes
|
||||
#include "variablemanager.h"
|
||||
#include "ptcdump.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static Type *getTypeAtOffset(const DataLayout *TheLayout,
|
||||
StructType *TheStruct,
|
||||
intptr_t Offset) {
|
||||
const StructLayout *Layout = TheLayout->getStructLayout(TheStruct);
|
||||
unsigned FieldIndex = Layout->getElementContainingOffset(Offset);
|
||||
uint64_t FieldOffset = Layout->getElementOffset(FieldIndex);
|
||||
|
||||
Type *VariableType = TheStruct->getTypeAtIndex(FieldIndex);
|
||||
|
||||
if (VariableType->isIntegerTy())
|
||||
return VariableType;
|
||||
else if (VariableType->isArrayTy())
|
||||
return VariableType->getArrayElementType();
|
||||
else if (VariableType->isStructTy())
|
||||
return getTypeAtOffset(TheLayout,
|
||||
dyn_cast<StructType>(VariableType),
|
||||
Offset - FieldOffset);
|
||||
else
|
||||
llvm_unreachable("Unexpected data type");
|
||||
}
|
||||
|
||||
VariableManager::VariableManager(Module& TheModule,
|
||||
StructType *CPUStateType,
|
||||
const DataLayout *HelpersModuleLayout) :
|
||||
TheModule(TheModule),
|
||||
Builder(TheModule.getContext()),
|
||||
CPUStateType(CPUStateType),
|
||||
HelpersModuleLayout(HelpersModuleLayout),
|
||||
Env(nullptr) { }
|
||||
|
||||
void VariableManager::newFunction(Instruction *Delimiter,
|
||||
PTCInstructionList *Instructions) {
|
||||
LocalTemporaries.clear();
|
||||
newBasicBlock(Delimiter, Instructions);
|
||||
}
|
||||
|
||||
/// Informs the VariableManager that a new basic block has begun, so it can
|
||||
/// discard basic block-level variables.
|
||||
///
|
||||
/// \param Delimiter the new point where to insert allocations for local
|
||||
/// variables.
|
||||
/// \param Instructions the new PTCInstructionList to use from now on.
|
||||
void VariableManager::newBasicBlock(Instruction *Delimiter,
|
||||
PTCInstructionList *Instructions) {
|
||||
Temporaries.clear();
|
||||
if (Instructions != nullptr)
|
||||
this->Instructions = Instructions;
|
||||
|
||||
if (Delimiter != nullptr)
|
||||
Builder.SetInsertPoint(Delimiter);
|
||||
}
|
||||
|
||||
void VariableManager::newBasicBlock(BasicBlock *Delimiter,
|
||||
PTCInstructionList *Instructions) {
|
||||
Temporaries.clear();
|
||||
if (Instructions != nullptr)
|
||||
this->Instructions = Instructions;
|
||||
|
||||
if (Delimiter != nullptr)
|
||||
Builder.SetInsertPoint(Delimiter);
|
||||
}
|
||||
|
||||
bool VariableManager::isEnv(Value *TheValue) {
|
||||
auto *Load = dyn_cast<LoadInst>(TheValue);
|
||||
if (Load != nullptr)
|
||||
return Load->getPointerOperand() == Env;
|
||||
|
||||
return TheValue == Env;
|
||||
}
|
||||
|
||||
GlobalVariable* VariableManager::getByCPUStateOffset(intptr_t Offset,
|
||||
std::string Name) {
|
||||
|
||||
GlobalsMap::iterator it = CPUStateGlobals.find(Offset);
|
||||
if (it != CPUStateGlobals.end()) {
|
||||
// TODO: handle renaming
|
||||
return it->second;
|
||||
} else {
|
||||
Type *VariableType = getTypeAtOffset(HelpersModuleLayout,
|
||||
CPUStateType,
|
||||
Offset);
|
||||
|
||||
if (Name.size() == 0) {
|
||||
std::stringstream NameStream;
|
||||
NameStream << "state_0x" << std::hex << Offset;
|
||||
Name = NameStream.str();
|
||||
}
|
||||
|
||||
auto *NewVariable = new GlobalVariable(TheModule,
|
||||
VariableType,
|
||||
false,
|
||||
GlobalValue::ExternalLinkage,
|
||||
ConstantInt::get(VariableType, 0),
|
||||
Name);
|
||||
assert(NewVariable != nullptr);
|
||||
CPUStateGlobals[Offset] = NewVariable;
|
||||
|
||||
return NewVariable;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Value* VariableManager::getOrCreate(unsigned int TemporaryId) {
|
||||
assert(Instructions != nullptr);
|
||||
|
||||
PTCTemp *Temporary = ptc_temp_get(Instructions, TemporaryId);
|
||||
Type *VariableType = Temporary->type == PTC_TYPE_I32 ?
|
||||
Builder.getInt32Ty() : Builder.getInt64Ty();
|
||||
|
||||
if (ptc_temp_is_global(Instructions, TemporaryId)) {
|
||||
// Basically we use fixed_reg to detect "env"
|
||||
if (Temporary->fixed_reg == 0) {
|
||||
return getByCPUStateOffset(Temporary->mem_offset,
|
||||
StringRef(Temporary->name));
|
||||
} else {
|
||||
GlobalsMap::iterator it = OtherGlobals.find(TemporaryId);
|
||||
if (it != OtherGlobals.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
auto InitialValue = ConstantInt::get(VariableType, 0);
|
||||
GlobalVariable *Result = new GlobalVariable(TheModule,
|
||||
VariableType,
|
||||
false,
|
||||
GlobalValue::ExternalLinkage,
|
||||
InitialValue,
|
||||
StringRef(Temporary->name));
|
||||
|
||||
if (Result->getName() == "env")
|
||||
Env = Result;
|
||||
|
||||
OtherGlobals[TemporaryId] = Result;
|
||||
return Result;
|
||||
}
|
||||
}
|
||||
} else if (Temporary->temp_local) {
|
||||
TemporariesMap::iterator it = LocalTemporaries.find(TemporaryId);
|
||||
if (it != LocalTemporaries.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
AllocaInst *NewTemporary = Builder.CreateAlloca(VariableType);
|
||||
LocalTemporaries[TemporaryId] = NewTemporary;
|
||||
return NewTemporary;
|
||||
}
|
||||
} else {
|
||||
TemporariesMap::iterator it = Temporaries.find(TemporaryId);
|
||||
if (it != Temporaries.end()) {
|
||||
return it->second;
|
||||
} else {
|
||||
AllocaInst *NewTemporary = Builder.CreateAlloca(VariableType);
|
||||
Temporaries[TemporaryId] = NewTemporary;
|
||||
return NewTemporary;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user