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
MachineState.h
TBAA.h
BinarySearch.h
Instructions/Types.h
Instructions/Instruction.h

View File

@ -10,7 +10,7 @@ InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction)
instruction(std::unique_ptr<Instruction>(instruction))
{
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();
}
@ -20,7 +20,7 @@ InstructionBlock::~InstructionBlock()
void InstructionBlock::GenerateEntryBlock()
{
entry_basic_block = llvm::BasicBlock::Create(llvm::getGlobalContext(), address_string + "_Entry");
entry_basic_block = CreateBasicBlock("Entry");
}
void InstructionBlock::GenerateCode()
@ -29,14 +29,6 @@ void InstructionBlock::GenerateCode()
ir_builder->SetInsertPoint(entry_basic_block);
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)
@ -49,6 +41,11 @@ llvm::Value *InstructionBlock::Write(Register reg, llvm::Value *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()
{
return instruction->Address();

View File

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

View File

@ -8,17 +8,14 @@ static RegisterInstruction<Branch> register_instruction;
bool Branch::Decode()
{
// 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;
return true;
}
// 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;
link = true;
@ -28,7 +25,7 @@ bool Branch::Decode()
return false;
}
void Branch::GenerateCode(InstructionBlock* instruction_block)
void Branch::GenerateInstructionCode(InstructionBlock* instruction_block)
{
auto ir_builder = instruction_block->Module()->IrBuilder();
if (link)

View File

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

View File

@ -8,17 +8,16 @@ 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),
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) }))
{
form = Form::Register;
if (cond != Condition::AL) return false;
if (imm5 != 0) return false; // Shifts
if (s != 0) return false; // Set flags
if (rm == 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),
if (ReadFields({ CondDef(), FieldDef<3>(1), FieldDef<4>(&short_op), FieldDef<1>(&s), FieldDef<4>(&rn),
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
{
// TODO: not implemented
@ -28,7 +27,7 @@ bool DataProcessing::Decode()
return false;
}
void DataProcessing::GenerateCode(InstructionBlock* instruction_block)
void DataProcessing::GenerateInstructionCode(InstructionBlock* instruction_block)
{
// Currently supports only mov reg, reg

View File

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

View File

@ -1,5 +1,10 @@
#include "Instruction.h"
#include "common/logging/log.h"
#include <cassert>
#include "InstructionBlock.h"
#include "ModuleGen.h"
#include "MachineState.h"
#include "BinarySearch.h"
Instruction::Instruction()
{
@ -14,7 +19,45 @@ bool Instruction::Read(u32 instruction, u32 address)
this->instruction = instruction;
this->address = address;
// 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)
@ -36,6 +79,11 @@ bool Instruction::ReadFields(const std::initializer_list<FieldDefObject> &fields
return true;
}
Instruction::FieldDefObject Instruction::CondDef()
{
return FieldDef<4>(&cond);
}
Instruction::FieldDefObject::FieldDefObject(u32 bit_count, u32 const_value)
: bit_count(bit_count), const_value(const_value), constant(true)
{

View File

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

View File

@ -24,6 +24,25 @@ void MachineState::GenerateGlobals()
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)
{
auto load = module->IrBuilder()->CreateAlignedLoad(GetRegisterPtr(reg), 4);
@ -38,21 +57,33 @@ Value* MachineState::WriteRegiser(Register reg, Value *value)
return store;
}
Value *MachineState::GetRegisterPtr(Register reg)
Value* MachineState::ConditionPassed(Condition cond)
{
Value *global;
unsigned index;
if (reg <= Register::PC)
auto ir_builder = module->IrBuilder();
Value *pred = nullptr;
auto not = false;
switch (cond)
{
global = registers_global;
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::R0);
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);
}
else
switch (cond)
{
global = flags_global;
index = static_cast<unsigned>(reg)-static_cast<unsigned>(Register::N);
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");
}
auto base = module->IrBuilder()->CreateAlignedLoad(global, 4);
module->GetTBAA()->TagConst(base);
return module->IrBuilder()->CreateConstInBoundsGEP1_32(base, index);
if (not) pred = ir_builder->CreateNot(pred);
return pred;
}

View File

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