diff --git a/src/binary_translation/BinarySearch.h b/src/binary_translation/BinarySearch.h new file mode 100644 index 000000000..779cc25d7 --- /dev/null +++ b/src/binary_translation/BinarySearch.h @@ -0,0 +1,22 @@ +#pragma once +#include "common/logging/log.h" +#include + +// 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(*this); } +}; \ No newline at end of file diff --git a/src/binary_translation/CMakeLists.txt b/src/binary_translation/CMakeLists.txt index e981ffb43..5a22c469b 100644 --- a/src/binary_translation/CMakeLists.txt +++ b/src/binary_translation/CMakeLists.txt @@ -18,6 +18,7 @@ set(HEADERS InstructionBlock.h MachineState.h TBAA.h + BinarySearch.h Instructions/Types.h Instructions/Instruction.h diff --git a/src/binary_translation/InstructionBlock.cpp b/src/binary_translation/InstructionBlock.cpp index e84ac7807..025aca6fa 100644 --- a/src/binary_translation/InstructionBlock.cpp +++ b/src/binary_translation/InstructionBlock.cpp @@ -10,7 +10,7 @@ InstructionBlock::InstructionBlock(ModuleGen* module, Instruction* instruction) instruction(std::unique_ptr(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(); diff --git a/src/binary_translation/InstructionBlock.h b/src/binary_translation/InstructionBlock.h index e8b862d00..4b170c991 100644 --- a/src/binary_translation/InstructionBlock.h +++ b/src/binary_translation/InstructionBlock.h @@ -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; } diff --git a/src/binary_translation/Instructions/Branch.cpp b/src/binary_translation/Instructions/Branch.cpp index 498040f86..5e9003399 100644 --- a/src/binary_translation/Instructions/Branch.cpp +++ b/src/binary_translation/Instructions/Branch.cpp @@ -8,17 +8,14 @@ static RegisterInstruction 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) diff --git a/src/binary_translation/Instructions/Branch.h b/src/binary_translation/Instructions/Branch.h index fe5f4b8a8..469e64eb9 100644 --- a/src/binary_translation/Instructions/Branch.h +++ b/src/binary_translation/Instructions/Branch.h @@ -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; diff --git a/src/binary_translation/Instructions/DataProcessing.cpp b/src/binary_translation/Instructions/DataProcessing.cpp index ce762ba9b..1c61bddb5 100644 --- a/src/binary_translation/Instructions/DataProcessing.cpp +++ b/src/binary_translation/Instructions/DataProcessing.cpp @@ -8,17 +8,16 @@ static RegisterInstruction 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 diff --git a/src/binary_translation/Instructions/DataProcessing.h b/src/binary_translation/Instructions/DataProcessing.h index a33edea3d..05426bd9a 100644 --- a/src/binary_translation/Instructions/DataProcessing.h +++ b/src/binary_translation/Instructions/DataProcessing.h @@ -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; diff --git a/src/binary_translation/Instructions/Instruction.cpp b/src/binary_translation/Instructions/Instruction.cpp index 2ec84e3b3..e4a0a16c8 100644 --- a/src/binary_translation/Instructions/Instruction.cpp +++ b/src/binary_translation/Instructions/Instruction.cpp @@ -1,5 +1,10 @@ #include "Instruction.h" +#include "common/logging/log.h" #include +#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 &fields) @@ -36,6 +79,11 @@ bool Instruction::ReadFields(const std::initializer_list &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) { diff --git a/src/binary_translation/Instructions/Instruction.h b/src/binary_translation/Instructions/Instruction.h index b57191106..343a8cb45 100644 --- a/src/binary_translation/Instructions/Instruction.h +++ b/src/binary_translation/Instructions/Instruction.h @@ -1,6 +1,7 @@ #pragma once #include "common/common_types.h" #include +#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 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; }; /* diff --git a/src/binary_translation/MachineState.cpp b/src/binary_translation/MachineState.cpp index a63b29711..adaff7e9d 100644 --- a/src/binary_translation/MachineState.cpp +++ b/src/binary_translation/MachineState.cpp @@ -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(reg)-static_cast(Register::R0); + } + else + { + global = flags_global; + index = (static_cast(reg)-static_cast(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(reg)-static_cast(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(reg)-static_cast(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; } \ No newline at end of file diff --git a/src/binary_translation/MachineState.h b/src/binary_translation/MachineState.h index 515ce36e5..77c3568ce 100644 --- a/src/binary_translation/MachineState.h +++ b/src/binary_translation/MachineState.h @@ -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);