Added conditional execution

24% of instructions in 3dscraft
This commit is contained in:
Dani Messerman 2015-05-01 01:32:48 +03:00
parent 7882bb2c4c
commit 66f70e7321
12 changed files with 151 additions and 41 deletions

View File

@ -0,0 +1,22 @@
#pragma once
#include "common/logging/log.h"
#include <cmath>
// Used for debugging
struct BinarySearch
{
size_t min;
size_t mid;
size_t max;
BinarySearch(size_t max) : min(0), mid(max / 2), max(max) { }
BinarySearch(size_t min, size_t max) : min(min), mid((min + max) / 2), max(max) { }
BinarySearch l() { return BinarySearch(min, mid); }
BinarySearch r() { return BinarySearch(mid, max); }
operator size_t()
{
LOG_DEBUG(BinaryTranslator, "BinarySearch: %x: %x - %x (%x, %d)", mid, max, min, max - min, (size_t)std::log2(max - min));
return mid;
}
operator int() { return static_cast<size_t>(*this); }
};

View File

@ -18,6 +18,7 @@ set(HEADERS
InstructionBlock.h InstructionBlock.h
MachineState.h MachineState.h
TBAA.h TBAA.h
BinarySearch.h
Instructions/Types.h Instructions/Types.h
Instructions/Instruction.h Instructions/Instruction.h

View File

@ -10,7 +10,7 @@ InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
instruction(std::unique_ptr<Instruction>(instruction)) instruction(std::unique_ptr<Instruction>(instruction))
{ {
std::stringstream ss; std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(8) << instruction->Address(); ss << std::hex << std::setfill('0') << std::setw(8) << instruction->Address() << "_";
address_string = ss.str(); address_string = ss.str();
} }
@ -20,7 +20,7 @@ InstructionBlock::~InstructionBlock()
void InstructionBlock::GenerateEntryBlock() void InstructionBlock::GenerateEntryBlock()
{ {
entry_basic_block = llvm::BasicBlock::Create(llvm::getGlobalContext(), address_string + "_Entry"); entry_basic_block = CreateBasicBlock("Entry");
} }
void InstructionBlock::GenerateCode() void InstructionBlock::GenerateCode()
@ -29,14 +29,6 @@ void InstructionBlock::GenerateCode()
ir_builder->SetInsertPoint(entry_basic_block); ir_builder->SetInsertPoint(entry_basic_block);
instruction->GenerateCode(this); instruction->GenerateCode(this);
auto basic_block = ir_builder->GetInsertBlock();
// If the basic block is terminated there has been a jump
// If not, jump to the next instruction
if (!basic_block->getTerminator())
{
Module()->BranchWritePCConst(Address() + 4);
}
} }
llvm::Value *InstructionBlock::Read(Register reg) llvm::Value *InstructionBlock::Read(Register reg)
@ -49,6 +41,11 @@ llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *value)
return module->Machine()->WriteRegiser(reg, value); return module->Machine()->WriteRegiser(reg, value);
} }
llvm::BasicBlock *InstructionBlock::CreateBasicBlock(const char *name)
{
return llvm::BasicBlock::Create(llvm::getGlobalContext(), address_string + name);
}
u32 InstructionBlock::Address() u32 InstructionBlock::Address()
{ {
return instruction->Address(); return instruction->Address();

View File

@ -44,6 +44,11 @@ public:
*/ */
llvm::Value *Write(Register reg, llvm::Value *value); llvm::Value *Write(Register reg, llvm::Value *value);
/*
* Creates a basic block for use by instructions
*/
llvm::BasicBlock *CreateBasicBlock(const char *name);
u32 Address(); u32 Address();
ModuleGen *Module() { return module; } ModuleGen *Module() { return module; }

View File

@ -8,17 +8,14 @@ static RegisterInstruction<Branch> register_instruction;
bool Branch::Decode() bool Branch::Decode()
{ {
// B imm, BL imm // B imm, BL imm
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(5), FieldDef<1>(&link), FieldDef<24>(&imm24) })) if (ReadFields({ CondDef(), FieldDef<3>(5), FieldDef<1>(&link), FieldDef<24>(&imm24) }))
{ {
if (cond != Condition::AL) return false;
form = Form::Immediate; form = Form::Immediate;
return true; return true;
} }
// BLX reg // BLX reg
if (ReadFields({ FieldDef<4>(&cond), FieldDef<24>(0x12fff3), FieldDef<4>(&rm)})) if (ReadFields({ CondDef(), FieldDef<24>(0x12fff3), FieldDef<4>(&rm) }))
{ {
if (cond != Condition::AL) return false;
if (rm == Register::PC) return false; if (rm == Register::PC) return false;
link = true; link = true;
@ -28,7 +25,7 @@ bool Branch::Decode()
return false; return false;
} }
void Branch::GenerateCode(InstructionBlock* instruction_block) void Branch::GenerateInstructionCode(InstructionBlock* instruction_block)
{ {
auto ir_builder = instruction_block->Module()->IrBuilder(); auto ir_builder = instruction_block->Module()->IrBuilder();
if (link) if (link)

View File

@ -16,10 +16,9 @@ public:
public: public:
virtual bool Decode() override; virtual bool Decode() override;
void GenerateCode(InstructionBlock* instruction_block) override; void GenerateInstructionCode(InstructionBlock* instruction_block) override;
private: private:
Form form; Form form;
Condition cond;
bool link; bool link;
u32 imm24; u32 imm24;
Register rm; Register rm;

View File

@ -8,17 +8,16 @@ static RegisterInstruction<DataProcessing> register_instruction;
bool DataProcessing::Decode() bool DataProcessing::Decode()
{ {
// Mov and shifts must have zeroes at some operands of different data processing instructions // 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), if (ReadFields({ CondDef(), 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) })) FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<3>(0), FieldDef<4>(&rm) }))
{ {
form = Form::Register; form = Form::Register;
if (cond != Condition::AL) return false;
if (imm5 != 0) return false; // Shifts if (imm5 != 0) return false; // Shifts
if (s != 0) return false; // Set flags if (s != 0) return false; // Set flags
if (rm == Register::PC) return false; // Jump if (rm == Register::PC) return false; // Jump
return true; return true;
} }
if (ReadFields({ FieldDef<4>(&cond), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn), if (ReadFields({ CondDef(), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn),
FieldDef<4>(&rd), FieldDef<12>(&imm12) })) FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
{ {
// TODO: not implemented // TODO: not implemented
@ -28,7 +27,7 @@ bool DataProcessing::Decode()
return false; return false;
} }
void DataProcessing::GenerateCode(InstructionBlock* instruction_block) void DataProcessing::GenerateInstructionCode(InstructionBlock* instruction_block)
{ {
// Currently supports only mov reg, reg // Currently supports only mov reg, reg

View File

@ -25,10 +25,9 @@ public:
public: public:
virtual bool Decode() override; virtual bool Decode() override;
void GenerateCode(InstructionBlock* instruction_block) override; void GenerateInstructionCode(InstructionBlock* instruction_block) override;
private: private:
Form form; Form form;
Condition cond;
ShortOpType short_op; ShortOpType short_op;
bool s; bool s;
Register rn; Register rn;

View File

@ -1,5 +1,10 @@
#include "Instruction.h" #include "Instruction.h"
#include "common/logging/log.h"
#include <cassert> #include <cassert>
#include "InstructionBlock.h"
#include "ModuleGen.h"
#include "MachineState.h"
#include "BinarySearch.h"
Instruction::Instruction() Instruction::Instruction()
{ {
@ -14,7 +19,45 @@ bool Instruction::Read(u32 instruction, u32 address)
this->instruction = instruction; this->instruction = instruction;
this->address = address; this->address = address;
// Call the read of derived class // Call the read of derived class
return Decode(); if (!Decode()) return false;
if (cond == Condition::Invalid) return false;
return true;
}
void Instruction::GenerateCode(InstructionBlock *instruction_block)
{
auto ir_builder = instruction_block->Module()->IrBuilder();
if (cond == Condition::AL)
{
GenerateInstructionCode(instruction_block);
}
else
{
auto pred = instruction_block->Module()->Machine()->ConditionPassed(cond);
auto passed_block = instruction_block->CreateBasicBlock("Passed");
auto not_passed_block = instruction_block->CreateBasicBlock("NotPassed");
ir_builder->CreateCondBr(pred, passed_block, not_passed_block);
ir_builder->SetInsertPoint(passed_block);
GenerateInstructionCode(instruction_block);
// If the basic block is terminated there has been a jump
// If not, jump to the next not passed block (which will jump to the next instruction)
if (!ir_builder->GetInsertBlock()->getTerminator())
{
ir_builder->CreateBr(not_passed_block);
}
ir_builder->SetInsertPoint(not_passed_block);
}
// If the basic block is terminated there has been a jump
// If not, jump to the next instruction
if (!ir_builder->GetInsertBlock()->getTerminator())
{
instruction_block->Module()->BranchWritePCConst(Address() + 4);
}
} }
bool Instruction::ReadFields(const std::initializer_list<FieldDefObject> &fields) bool Instruction::ReadFields(const std::initializer_list<FieldDefObject> &fields)
@ -36,6 +79,11 @@ bool Instruction::ReadFields(const std::initializer_list<FieldDefObject> &fields
return true; return true;
} }
Instruction::FieldDefObject Instruction::CondDef()
{
return FieldDef<4>(&cond);
}
Instruction::FieldDefObject::FieldDefObject(u32 bit_count, u32 const_value) Instruction::FieldDefObject::FieldDefObject(u32 bit_count, u32 const_value)
: bit_count(bit_count), const_value(const_value), constant(true) : bit_count(bit_count), const_value(const_value), constant(true)
{ {

View File

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "common/common_types.h" #include "common/common_types.h"
#include <initializer_list> #include <initializer_list>
#include "Types.h"
class InstructionBlock; class InstructionBlock;
@ -19,10 +20,9 @@ public:
bool Read(u32 instruction, u32 address); bool Read(u32 instruction, u32 address);
/* /*
* Generates code for the instruction into the instruction block * Generates non instruction specific code, and then calls GenerateInstructionCode
* Derived classes must override this
*/ */
virtual void GenerateCode(InstructionBlock *instruction_block) = 0; void GenerateCode(InstructionBlock *instruction_block);
u32 Address() { return address; } u32 Address() { return address; }
protected: protected:
@ -30,6 +30,11 @@ protected:
* Derived classes must override this, and implement it by calling ReadFields * Derived classes must override this, and implement it by calling ReadFields
*/ */
virtual bool Decode() = 0; virtual bool Decode() = 0;
/*
* Generates code for the instruction into the instruction block
* Derived classes must override this
*/
virtual void GenerateInstructionCode(InstructionBlock *instruction_block) = 0;
/* /*
* Reads fields from the instruction * Reads fields from the instruction
* The fields come most significant first * The fields come most significant first
@ -46,6 +51,10 @@ protected:
*/ */
template<size_t BitCount, typename Type> template<size_t BitCount, typename Type>
static FieldDefObject FieldDef(Type *field); static FieldDefObject FieldDef(Type *field);
/*
* Creates a field definition for the condition field
*/
FieldDefObject CondDef();
private: private:
/* /*
* Function used by FieldDefObject to write to a field * Function used by FieldDefObject to write to a field
@ -57,6 +66,8 @@ private:
u32 instruction; u32 instruction;
// Instruction address // Instruction address
u32 address; u32 address;
Condition cond;
}; };
/* /*

View File

@ -24,6 +24,25 @@ void MachineState::GenerateGlobals()
false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags"); false, GlobalValue::ExternalLinkage, flags_global_initializer, "Flags");
} }
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) Value* MachineState::ReadRegiser(Register reg)
{ {
auto load = module->IrBuilder()->CreateAlignedLoad(GetRegisterPtr(reg), 4); auto load = module->IrBuilder()->CreateAlignedLoad(GetRegisterPtr(reg), 4);
@ -38,21 +57,33 @@ Value* MachineState::WriteRegiser(Register reg, Value *value)
return store; return store;
} }
Value *MachineState::GetRegisterPtr(Register reg) Value* MachineState::ConditionPassed(Condition cond)
{ {
Value *global; auto ir_builder = module->IrBuilder();
unsigned index; Value *pred = nullptr;
if (reg <= Register::PC) auto not = false;
switch (cond)
{ {
global = registers_global; case Condition::NE: case Condition::CC: case Condition::PL: case Condition::VC:
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::R0); case Condition::LS: case Condition::LT: case Condition::LE:
not = true;
cond = (Condition)((int)cond - 1);
} }
else
switch (cond)
{ {
global = flags_global; case Condition::EQ: pred = ReadRegiser(Register::Z); break;
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::N); 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");
} }
auto base = module->IrBuilder()->CreateAlignedLoad(global, 4);
module->GetTBAA()->TagConst(base); if (not) pred = ir_builder->CreateNot(pred);
return module->IrBuilder()->CreateConstInBoundsGEP1_32(base, index); return pred;
} }

View File

@ -1,4 +1,5 @@
enum class Condition;
enum class Register; enum class Register;
class ModuleGen; class ModuleGen;
@ -20,7 +21,7 @@ public:
void GenerateGlobals(); void GenerateGlobals();
llvm::Value *ReadRegiser(Register reg); llvm::Value *ReadRegiser(Register reg);
llvm::Value *WriteRegiser(Register reg, llvm::Value *value); llvm::Value *WriteRegiser(Register reg, llvm::Value *value);
llvm::Value* ConditionPassed(Condition cond);
private: private:
// Returns the address of a register or a flag // Returns the address of a register or a flag
llvm::Value *GetRegisterPtr(Register reg); llvm::Value *GetRegisterPtr(Register reg);