Generates mov reg, reg

This commit is contained in:
Dani Messerman 2015-04-30 20:29:06 +03:00
parent a91f373f36
commit 3731d28ca9
8 changed files with 401 additions and 19 deletions

View File

@ -3,6 +3,7 @@ set(SRCS
CodeGen.cpp
ModuleGen.cpp
Disassembler.cpp
InstructionBlock.cpp
Instructions/Instruction.cpp
Instructions/DataProcessing.cpp
@ -11,6 +12,7 @@ set(HEADERS
CodeGen.h
ModuleGen.h
Disassembler.h
InstructionBlock.h
Instructions/Types.h
Instructions/Instruction.h

View File

@ -0,0 +1,49 @@
#include "InstructionBlock.h"
#include "ModuleGen.h"
#include "Instructions/Instruction.h"
#include <sstream>
#include <iomanip>
InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
: module(module),
instruction(std::unique_ptr<Instruction>(instruction))
{
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(8) << instruction->Address();
address_string = ss.str();
}
InstructionBlock::~InstructionBlock()
{
}
void InstructionBlock::GenerateEntryBlock()
{
entry_basic_block = llvm::BasicBlock::Create(llvm::getGlobalContext(), address_string + "_Entry");
}
void InstructionBlock::GenerateCode()
{
Module()->IrBuilder()->SetInsertPoint(entry_basic_block);
instruction->GenerateCode(this);
exit_basic_block = Module()->IrBuilder()->GetInsertBlock();
}
llvm::Value *InstructionBlock::Read(Register reg)
{
auto ib = module->IrBuilder();
return ib->CreateAlignedLoad(module->GetRegisterPtr(reg), 4);
}
llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value)
{
auto ib = module->IrBuilder();
return ib->CreateAlignedStore(value, module->GetRegisterPtr(reg), 4);
}
size_t InstructionBlock::Address()
{
return instruction->Address();
}

View File

@ -0,0 +1,64 @@
#include <memory>
#include <string>
namespace llvm
{
class Value;
class BasicBlock;
}
class ModuleGen;
class Instruction;
enum class Register;
/*
* An instruction blocks
* Holds the entry and exit points for an instruction
* Responsible to generate the code
*/
class InstructionBlock
{
public:
InstructionBlock(ModuleGen *module, Instruction *instruction);
~InstructionBlock();
/*
* Generates the basic block of the instruction
*/
void GenerateEntryBlock();
/*
* Generates the code for the instruction
*/
void GenerateCode();
/*
* Generates code to read the register
*/
llvm::Value *Read(Register reg);
/*
* Generates code to write the value
* Returns the write instruction = written value
*/
llvm::Value *Write(Register reg, llvm::Value *value);
size_t Address();
ModuleGen *Module() { return module; }
llvm::BasicBlock *GetEntryBasicBlock() { return entry_basic_block; }
llvm::BasicBlock *GetExitBasicBlock() { return exit_basic_block; }
private:
// Textual representation of the address
// Used to generate names
std::string address_string;
ModuleGen *module;
std::unique_ptr<Instruction> instruction;
// The block at the entry to instruction
llvm::BasicBlock *entry_basic_block;
// The block at the exit from the instruction
llvm::BasicBlock *exit_basic_block;
};

View File

@ -1,15 +1,35 @@
#include "DataProcessing.h"
#include "Disassembler.h"
#include "InstructionBlock.h"
static RegisterInstruction<DataProcessing> register_instruction;
bool DataProcessing::Decode()
{
// Mov and shifts must have zeroes at some operands of different data processing instructions
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(0), FieldDef<4>((u32)ShortOpType::MoveAndShifts), FieldDef<1>(&s), FieldDef<4>(0),
FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<3>(0), FieldDef<4>(&rm) }))
{
form = Form::Register;
if (imm5 != 0) return false; // Shifts
if (s != 0) return false; // Set flags
if (rd == Register::PC) return false; // Jump
return true;
}
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn),
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
{
// TODO: not implemented
form = Form::Immediate;
return true;
return false;
}
return false;
}
void DataProcessing::GenerateCode(InstructionBlock* instruction_block)
{
// Currently supports only mov reg, reg
auto value = instruction_block->Read(rm);
instruction_block->Write(rd, value);
}

View File

@ -16,7 +16,7 @@ public:
{
BitwiseAnd = 0, BitwiseXor, Subtract, RevSubtract, Add, AddWithCarry, SubtractWithCarry, ReverseSubtractWithCarry,
// Compare, Test, Misc
BitwiseOr = 12, Move, BitwiseBitClear, BitwiseNot
BitwiseOr = 12, MoveAndShifts, BitwiseBitClear, BitwiseNot
};
enum class Form
{
@ -25,6 +25,7 @@ public:
public:
virtual bool Decode() override;
void GenerateCode(InstructionBlock* instruction_block) override;
private:
Form form;
Condition cond;
@ -32,5 +33,7 @@ private:
bool s;
Register rn;
Register rd;
Register rm;
u32 imm12;
u32 imm5;
};

View File

@ -2,6 +2,8 @@
#include "common/common_types.h"
#include <initializer_list>
class InstructionBlock;
class Instruction
{
protected:
@ -15,9 +17,17 @@ public:
* Returns true on success, or false otherwise
*/
bool Read(u32 instruction, u32 address);
/*
* Generates code for the instruction into the instruction block
* Derived classes must override this
*/
virtual void GenerateCode(InstructionBlock *instruction_block) = 0;
u32 Address() { return address; }
protected:
/*
* Derived classes should override this, and implement it by calling ReadFields
* Derived classes must override this, and implement it by calling ReadFields
*/
virtual bool Decode() = 0;
/*
@ -36,7 +46,6 @@ protected:
*/
template<size_t BitCount, typename Type>
static FieldDefObject FieldDef(Type *field);
private:
/*
* Function used by FieldDefObject to write to a field

View File

@ -3,8 +3,11 @@
#include "core/loader/loader.h"
#include "core/mem_map.h"
#include "Instructions/Instruction.h"
#include "Instructions/Types.h"
#include "InstructionBlock.h"
#include <llvm/IR/Function.h>
#include <llvm/IR/GlobalVariable.h>
#include <stack>
using namespace llvm;
@ -21,10 +24,37 @@ ModuleGen::~ModuleGen()
void ModuleGen::Run()
{
GenerateGlobals();
DecodeInstructions();
GenerateInstructionsEntry();
GenerateCanRunFunction();
GenerateRunFunction();
GenerateGetBlockAddressFunction();
GenerateBlocks();
GenerateInstructionsCode();
GenerateInstructionsTermination();
AddInstructionsToRunFunction();
GenerateBlockAddressArray();
}
Value *ModuleGen::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);
}
auto base = ir_builder->CreateAlignedLoad(global, 4);
return ir_builder->CreateConstInBoundsGEP1_32(base, index);
}
void ModuleGen::GenerateGlobals()
@ -35,36 +65,193 @@ void ModuleGen::GenerateGlobals()
// 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, flags_global_initializer->getType(), false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
auto get_block_address_function_type = FunctionType::get(ir_builder->getInt8PtrTy(), ir_builder->getInt32Ty(), false);
get_block_address_function = Function::Create(get_block_address_function_type, GlobalValue::PrivateLinkage, "GetBlockAddress", module);
auto can_run_function_type = FunctionType::get(ir_builder->getInt1Ty(), false);
can_run_function = Function::Create(can_run_function_type, GlobalValue::ExternalLinkage, "CanRun", module);
auto run_function_type = FunctionType::get(ir_builder->getVoidTy(), false);
run_function = Function::Create(run_function_type, GlobalValue::ExternalLinkage, "Run", module);
block_address_array_base = Loader::ROMCodeStart / 4;
block_address_array_size = Loader::ROMCodeSize / 4;
block_address_array_type = ArrayType::get(ir_builder->getInt8PtrTy(), block_address_array_size);
block_address_array = new GlobalVariable(*module, block_address_array_type, true, GlobalValue::ExternalLinkage, nullptr, "BlockAddressArray");
}
void ModuleGen::GenerateBlockAddressArray()
{
auto local_block_address_array_values = std::make_unique<Constant*[]>(block_address_array_size);
std::fill(
local_block_address_array_values.get(),
local_block_address_array_values.get() + block_address_array_size,
ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
for (auto i = 0; i < instruction_blocks.size(); ++i)
{
auto &block = instruction_blocks[i];
auto entry_basic_block = block->GetEntryBasicBlock();
auto index = block->Address() / 4 - block_address_array_base;
local_block_address_array_values[index] = BlockAddress::get(entry_basic_block->getParent(), entry_basic_block);
}
auto local_block_address_array_values_ref = ArrayRef<Constant*>(local_block_address_array_values.get(), block_address_array_size);
auto local_blocks_address_array = ConstantArray::get(block_address_array_type, local_block_address_array_values_ref);
block_address_array->setInitializer(local_blocks_address_array);
}
void ModuleGen::GenerateGetBlockAddressFunction()
{
/*
entry_basic_block:
auto index = (pc - block_address_array_base) / 4;
if(index < block_address_array_size)
{
index_in_bounds_basic_block:
return block_address_array[index];
}
else
{
index_out_of_bounds_basic_block:
return nullptr;
}
*/
auto pc = &*get_block_address_function->arg_begin();
auto entry_basic_block = BasicBlock::Create(getGlobalContext(), "Entry", get_block_address_function);
auto index_in_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexInBounds", get_block_address_function);
auto index_out_of_bounds_basic_block = BasicBlock::Create(getGlobalContext(), "IndexOutOfBounds", get_block_address_function);
ir_builder->SetInsertPoint(entry_basic_block);
auto index = ir_builder->CreateUDiv(pc, ir_builder->getInt32(4));
index = ir_builder->CreateSub(index, ir_builder->getInt32(block_address_array_base));
auto in_bounds_pred = ir_builder->CreateICmpULT(index, ir_builder->getInt32(block_address_array_size));
ir_builder->CreateCondBr(in_bounds_pred, index_in_bounds_basic_block, index_out_of_bounds_basic_block);
ir_builder->SetInsertPoint(index_in_bounds_basic_block);
Value *gep_values[] = { ir_builder->getInt32(0), index };
auto block_address = ir_builder->CreateLoad(ir_builder->CreateInBoundsGEP(block_address_array, gep_values));
ir_builder->CreateRet(block_address);
ir_builder->SetInsertPoint(index_out_of_bounds_basic_block);
ir_builder->CreateRet(ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
}
void ModuleGen::GenerateCanRunFunction()
{
auto can_run_function_type = FunctionType::get(ir_builder->getInt1Ty(), false);
can_run_function = Function::Create(can_run_function_type, GlobalValue::ExternalLinkage, "CanRun", module);
// return GetBlockAddress(Read(PC)) != nullptr;
auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", can_run_function);
ir_builder->SetInsertPoint(basic_block);
ir_builder->CreateRet(ir_builder->getInt1(false));
auto block_address = ir_builder->CreateCall(get_block_address_function, ir_builder->CreateAlignedLoad(GetRegisterPtr(Register::PC), 4));
ir_builder->CreateRet(ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy())));
}
void ModuleGen::GenerateRunFunction()
{
auto run_function_type = FunctionType::get(ir_builder->getVoidTy(), false);
run_function = Function::Create(run_function_type, GlobalValue::ExternalLinkage, "Run", module);
auto basic_block = BasicBlock::Create(getGlobalContext(), "Entry", run_function);
/*
run_function_entry:
run_function_re_entry:
auto block_address = GetBlockAddress(Read(PC))
if(index != nullptr)
{
block_present_basic_block:
goto block_address;
return;
}
else
{
block_not_present_basic_block:
return;
}
*/
run_function_entry = BasicBlock::Create(getGlobalContext(), "Entry", run_function);
// run_function_re_entry is needed because it isn't possible to jump to the first block of a function
run_function_re_entry = BasicBlock::Create(getGlobalContext(), "ReEntry", run_function);
auto block_present_basic_block = BasicBlock::Create(getGlobalContext(), "BlockPresent", run_function);
auto block_not_present_basic_block = BasicBlock::Create(getGlobalContext(), "BlockNotPresent", run_function);
ir_builder->SetInsertPoint(basic_block);
ir_builder->SetInsertPoint(run_function_entry);
ir_builder->CreateBr(run_function_re_entry);
ir_builder->SetInsertPoint(run_function_re_entry);
auto block_address = ir_builder->CreateCall(get_block_address_function, ir_builder->CreateAlignedLoad(GetRegisterPtr(Register::PC), 4));
auto block_present_pred = ir_builder->CreateICmpNE(block_address, ConstantPointerNull::get(ir_builder->getInt8PtrTy()));
ir_builder->CreateCondBr(block_present_pred, block_present_basic_block, block_not_present_basic_block);
ir_builder->SetInsertPoint(block_present_basic_block);
auto indirect_br = ir_builder->CreateIndirectBr(block_address, instruction_blocks.size());
for (auto &block : instruction_blocks)
{
indirect_br->addDestination(block->GetEntryBasicBlock());
}
ir_builder->SetInsertPoint(block_not_present_basic_block);
ir_builder->CreateRetVoid();
}
void ModuleGen::GenerateBlocks()
void ModuleGen::DecodeInstructions()
{
for (auto i = Loader::ROMCodeStart; i <= Loader::ROMCodeStart + Loader::ROMCodeSize - 4; i += 4)
{
auto instruction = Disassembler::Disassemble(Memory::Read32(i), i);
if (instruction != nullptr)
if (instruction == nullptr) continue;
auto instruction_block = std::make_unique<InstructionBlock>(this, instruction.release());
instruction_blocks_by_pc[i] = instruction_block.get();
instruction_blocks.push_back(std::move(instruction_block));
}
}
void ModuleGen::GenerateInstructionsEntry()
{
for (auto &instruction : instruction_blocks)
{
LOG_DEBUG(BinaryTranslator, "Instruction at %08x", i);
instruction->GenerateEntryBlock();
}
}
void ModuleGen::GenerateInstructionsCode()
{
for (auto &instruction : instruction_blocks)
{
instruction->GenerateCode();
}
}
void ModuleGen::GenerateInstructionsTermination()
{
// Return to the switch
for (auto &block : instruction_blocks)
{
ir_builder->SetInsertPoint(block->GetExitBasicBlock());
ir_builder->CreateAlignedStore(ir_builder->getInt32(block->Address() + 4), GetRegisterPtr(Register::PC), 4);
ir_builder->CreateBr(run_function_re_entry);
}
}
void ModuleGen::AddInstructionsToRunFunction()
{
std::stack<BasicBlock *> basic_blocks_stack;
for (auto &block : instruction_blocks)
{
basic_blocks_stack.push(block->GetEntryBasicBlock());
while (basic_blocks_stack.size())
{
auto basic_block = basic_blocks_stack.top();
basic_blocks_stack.pop();
basic_block->insertInto(run_function);
auto terminator = basic_block->getTerminator();
for (auto i = 0; i < terminator->getNumSuccessors(); ++i)
{
auto new_basic_block = terminator->getSuccessor(i);
if (new_basic_block->getParent()) continue; // Already added to run
basic_blocks_stack.push(new_basic_block);
}
}
}
}

View File

@ -1,4 +1,10 @@
#include <llvm/IR/IRBuilder.h>
#include <unordered_map>
#include <common/common_types.h>
enum class Register;
class InstructionBlock;
namespace llvm
{
@ -12,11 +18,30 @@ public:
~ModuleGen();
void Run();
// Returns the address of a register or a flag
llvm::Value *GetRegisterPtr(Register reg);
llvm::IRBuilder<> *IrBuilder() { return ir_builder.get(); }
llvm::Module *Module() { return module; }
private:
// Generates the declarations of all the globals of the module
void GenerateGlobals();
void GenerateBlockAddressArray();
void GenerateGetBlockAddressFunction();
void GenerateCanRunFunction();
void GenerateRunFunction();
void GenerateBlocks();
private:
// Creates InstructionBlock for each instruction
void DecodeInstructions();
// Generates the entry basic blocks for each instruction
void GenerateInstructionsEntry();
// Generates the code of each instruction
void GenerateInstructionsCode();
// Terminates each block
void GenerateInstructionsTermination();
// Adds all the basic blocks of an instruction to the run function
void AddInstructionsToRunFunction();
std::unique_ptr<llvm::IRBuilder<>> ir_builder;
llvm::Module *module;
@ -31,6 +56,21 @@ private:
* Orderered N, Z, C, V
*/
llvm::GlobalVariable *flags_global;
size_t block_address_array_base;
size_t block_address_array_size;
/*
* i8 **BlockAddressArray;
* The array at [i/4 - block_address_array_base] contains the block address for the instruction at i
* or nullptr if it is not decoded
*/
llvm::ArrayType *block_address_array_type;
llvm::GlobalVariable *block_address_array;
/*
* i8 *GetBlockAddress(u32 pc)
* Returns the address of the block for the instruction at pc
*/
llvm::Function *get_block_address_function;
/*
* bool CanRun()
* Returns whether there is a binary translation available for a PC
@ -41,4 +81,12 @@ private:
* Runs binary translated opcodes
*/
llvm::Function *run_function;
llvm::BasicBlock *run_function_entry;
llvm::BasicBlock *run_function_re_entry;
/*
* All the instruction blocks
*/
std::vector<std::unique_ptr<InstructionBlock>> instruction_blocks;
std::unordered_map<u32, InstructionBlock *> instruction_blocks_by_pc;
};