citra/src/binary_translation/MachineState.cpp
Dani Messerman 2839139250 Added LDR
2015-05-10 22:32:34 +03:00

109 lines
4.1 KiB
C++

#include "MachineState.h"
#include "ModuleGen.h"
#include "Instructions/Types.h"
#include <llvm/IR/GlobalValue.h>
#include <llvm/IR/Constants.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/GlobalVariable.h>
#include "TBAA.h"
using namespace llvm;
MachineState::MachineState(ModuleGen *module) : module(module)
{
}
void MachineState::GenerateGlobals()
{
auto registers_global_initializer = ConstantPointerNull::get(IntegerType::getInt32PtrTy(getGlobalContext()));
registers_global = new GlobalVariable(*module->Module(), registers_global_initializer->getType(),
false, GlobalValue::ExternalLinkage, registers_global_initializer, "Registers");
// Flags is stored internally as i1* indexed in multiples of 4
auto flags_global_initializer = ConstantPointerNull::get(IntegerType::getInt1PtrTy(getGlobalContext()));
flags_global = new GlobalVariable(*module->Module(), flags_global_initializer->getType(),
false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
auto memory_read_32_signature = FunctionType::get(IntegerType::getInt32Ty(getGlobalContext()), IntegerType::getInt32Ty(getGlobalContext()), false);
auto memory_read_32_ptr = PointerType::get(memory_read_32_signature, 0);
auto memory_read_32_initializer = ConstantPointerNull::get(memory_read_32_ptr);
memory_read_32_global = new GlobalVariable(*module->Module(), memory_read_32_ptr,
false, GlobalValue::ExternalLinkage, memory_read_32_initializer, "Memory::Read32");
}
Value *MachineState::GetRegisterPtr(Register reg)
{
Value *global;
unsigned index;
if (reg <= Register::PC)
{
global = registers_global;
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::R0);
}
else
{
global = flags_global;
index = (static_cast<unsigned>(reg)-static_cast<unsigned>(Register::N)) * 4;
}
auto base = module->IrBuilder()->CreateAlignedLoad(global, 4);
module->GetTBAA()->TagConst(base);
return module->IrBuilder()->CreateConstInBoundsGEP1_32(base, index);
}
Value* MachineState::ReadRegiser(Register reg)
{
auto load = module->IrBuilder()->CreateAlignedLoad(GetRegisterPtr(reg), 4);
module->GetTBAA()->TagRegister(load, reg);
return load;
}
Value* MachineState::WriteRegiser(Register reg, Value *value)
{
auto store = module->IrBuilder()->CreateAlignedStore(value, GetRegisterPtr(reg), 4);
module->GetTBAA()->TagRegister(store, reg);
return store;
}
Value* MachineState::ConditionPassed(Condition cond)
{
auto ir_builder = module->IrBuilder();
Value *pred = nullptr;
auto not = false;
switch (cond)
{
case Condition::NE: case Condition::CC: case Condition::PL: case Condition::VC:
case Condition::LS: case Condition::LT: case Condition::LE:
not = true;
cond = (Condition)((int)cond - 1);
}
switch (cond)
{
case Condition::EQ: pred = ReadRegiser(Register::Z); break;
case Condition::CS: pred = ReadRegiser(Register::C); break;
case Condition::MI: pred = ReadRegiser(Register::N); break;
case Condition::VS: pred = ReadRegiser(Register::V); break;
case Condition::HI: pred = ir_builder->CreateAnd(ReadRegiser(Register::C), ir_builder->CreateNot(ReadRegiser(Register::Z))); break;
case Condition::GE: pred = ir_builder->CreateICmpEQ(ReadRegiser(Register::N), ReadRegiser(Register::V)); break;
case Condition::GT: pred = ir_builder->CreateAnd(ir_builder->CreateNot(ReadRegiser(Register::Z)),
ir_builder->CreateICmpEQ(ReadRegiser(Register::N), ReadRegiser(Register::V))); break;
case Condition::AL: pred = ir_builder->getInt1(true);
default: assert(false, "Invalid condition");
}
if (not) pred = ir_builder->CreateNot(pred);
return pred;
}
llvm::Value* MachineState::ReadMemory32(llvm::Value* address)
{
auto ir_builder = module->IrBuilder();
auto memory_read_32 = ir_builder->CreateLoad(memory_read_32_global);
module->GetTBAA()->TagConst(memory_read_32);
auto call = ir_builder->CreateCall(memory_read_32, address);
call->setOnlyReadsMemory();
module->GetTBAA()->TagMemory(call);
return call;
}