Added arithmetic instructions (add, sub, and, or, ...)

This commit is contained in:
Dani Messerman 2015-05-05 22:15:48 +03:00
parent 840ab06561
commit 3ae4d8b646
8 changed files with 226 additions and 12 deletions

View File

@ -131,6 +131,13 @@ ARMFuncs::ResultCarry ARMFuncs::RRX_C(InstructionBlock* instruction, llvm::Value
return{ result, carry }; return{ result, carry };
} }
llvm::Value* ARMFuncs::ARMExpandImm(InstructionBlock* instruction, u32 imm12)
{
auto ir_builder = instruction->IrBuilder();
// Manual says carry in does not affect the result, so use undef
return ARMExpandImm_C(instruction, imm12, llvm::UndefValue::get(ir_builder->getInt1Ty())).result;
}
ARMFuncs::ResultCarry ARMFuncs::ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value* carry) ARMFuncs::ResultCarry ARMFuncs::ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value* carry)
{ {
auto ir_builder = instruction->IrBuilder(); auto ir_builder = instruction->IrBuilder();
@ -139,3 +146,26 @@ ARMFuncs::ResultCarry ARMFuncs::ARMExpandImm_C(InstructionBlock *instruction, u3
auto shift = ir_builder->getInt32(2 * (imm12 >> 8)); auto shift = ir_builder->getInt32(2 * (imm12 >> 8));
return Shift_C(instruction, value, SRType::ROR, shift, carry); return Shift_C(instruction, value, SRType::ROR, shift, carry);
} }
// AddWithCarry from armsupp.cpp
ARMFuncs::ResultCarryOverflow ARMFuncs::AddWithCarry(InstructionBlock* instruction, llvm::Value* x, llvm::Value* y, llvm::Value* carry_in)
{
auto ir_builder = instruction->IrBuilder();
auto xu64 = ir_builder->CreateZExt(x, ir_builder->getInt64Ty());
auto xs64 = ir_builder->CreateSExt(x, ir_builder->getInt64Ty());
auto yu64 = ir_builder->CreateZExt(y, ir_builder->getInt64Ty());
auto ys64 = ir_builder->CreateSExt(y, ir_builder->getInt64Ty());
auto c64 = ir_builder->CreateZExt(carry_in, ir_builder->getInt64Ty());
auto unsignedSum = ir_builder->CreateAdd(ir_builder->CreateAdd(xu64, yu64), c64);
auto singedSum = ir_builder->CreateAdd(ir_builder->CreateAdd(xs64, ys64), c64);
auto result32 = ir_builder->CreateTrunc(unsignedSum, ir_builder->getInt32Ty());
auto resultU64 = ir_builder->CreateZExt(result32, ir_builder->getInt64Ty());
auto resultS64 = ir_builder->CreateSExt(result32, ir_builder->getInt64Ty());
auto carry = ir_builder->CreateICmpNE(resultU64, unsignedSum);
auto overflow = ir_builder->CreateICmpNE(resultS64, singedSum);
return{ result32, carry, overflow };
}

View File

@ -27,6 +27,10 @@ public:
{ {
llvm::Value *result, *carry; llvm::Value *result, *carry;
}; };
struct ResultCarryOverflow
{
llvm::Value *result, *carry, *overflow;
};
static ShiftTN DecodeImmShift(InstructionBlock *instruction, u32 type, u32 imm5); static ShiftTN DecodeImmShift(InstructionBlock *instruction, u32 type, u32 imm5);
static SRType DecodeRegShift(u32 type); static SRType DecodeRegShift(u32 type);
@ -41,5 +45,8 @@ public:
static ResultCarry ROR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift); static ResultCarry ROR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
static ResultCarry RRX_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *carry_in); static ResultCarry RRX_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *carry_in);
static llvm::Value *ARMExpandImm(InstructionBlock *instruction, u32 imm12);
static ResultCarry ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value *carry); static ResultCarry ARMExpandImm_C(InstructionBlock *instruction, u32 imm12, llvm::Value *carry);
static ResultCarryOverflow AddWithCarry(InstructionBlock *instruction, llvm::Value *x, llvm::Value *y, llvm::Value *carry_in);
}; };

View File

@ -82,10 +82,24 @@ void BlockColors::AddBasicBlocksToFunction(Function* function, BasicBlock* basic
return; return;
} }
basic_block->insertInto(function); std::stack<BasicBlock *> basic_blocks;
auto terminator = basic_block->getTerminator(); basic_blocks.push(basic_block);
while (basic_blocks.size())
{
auto top = basic_blocks.top();
basic_blocks.pop();
top->insertInto(function);
auto terminator = top->getTerminator();
for (auto i = 0; i < terminator->getNumSuccessors(); ++i) for (auto i = 0; i < terminator->getNumSuccessors(); ++i)
{ {
AddBasicBlocksToFunction(function, terminator->getSuccessor(i)); auto next = terminator->getSuccessor(i);
if (next->getParent())
{
assert(next->getParent() == function);
continue;
}
basic_blocks.push(next);
}
} }
} }

View File

@ -12,6 +12,7 @@ set(SRCS
Instructions/Instruction.cpp Instructions/Instruction.cpp
Instructions/MovShift.cpp Instructions/MovShift.cpp
Instructions/Branch.cpp Instructions/Branch.cpp
Instructions/Arithmetic.cpp
) )
set(HEADERS set(HEADERS
CodeGen.h CodeGen.h
@ -28,6 +29,7 @@ set(HEADERS
Instructions/Instruction.h Instructions/Instruction.h
Instructions/MovShift.h Instructions/MovShift.h
Instructions/Branch.h Instructions/Branch.h
Instructions/Arithmetic.h
) )
create_directory_groups(${SRCS} ${HEADERS}) create_directory_groups(${SRCS} ${HEADERS})

View File

@ -0,0 +1,128 @@
#include "Arithmetic.h"
#include "Disassembler.h"
#include <binary_translation/ARMFuncs.h>
#include <binary_translation/InstructionBlock.h>
static RegisterInstruction<Arithmetic> register_instruction;
bool IsSupported(Arithmetic::Op op)
{
switch (op)
{
case Arithmetic::Op::BitwiseAnd: return true;
case Arithmetic::Op::BitwiseXor: return true;
case Arithmetic::Op::Subtract: return true;
case Arithmetic::Op::RevSubtract: return true;
case Arithmetic::Op::Add: return true;
case Arithmetic::Op::AddWithCarry: return true;
case Arithmetic::Op::SubtractWithCarry: return true;
case Arithmetic::Op::ReverseSubtractWithCarry: return true;
case Arithmetic::Op::BitwiseOr: return true;
case Arithmetic::Op::MoveAndShifts: return false; // Handled in MovShift.cpp
case Arithmetic::Op::BitwiseBitClear: return true;
case Arithmetic::Op::BitwiseNot: return false; // MVN
default: return false;
}
}
bool IsBitwise(Arithmetic::Op op)
{
switch (op)
{
case Arithmetic::Op::BitwiseAnd: return true;
case Arithmetic::Op::BitwiseXor: return true;
case Arithmetic::Op::BitwiseOr: return true;
case Arithmetic::Op::BitwiseBitClear: return true;
default: break;
}
}
bool Arithmetic::Decode()
{
if (ReadFields({ CondDef(), FieldDef<3>(0), FieldDef<4>(&op), FieldDef<1>(&s), FieldDef<4>(&rn),
FieldDef<4>(&rd), FieldDef<5>(&imm5), FieldDef<2>(&type), FieldDef<1>(0), FieldDef<4>(&rm)}))
{
form = Form::Register;
if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions;
if (rn == Register::PC) return false;
if (rm == Register::PC) return false;
return IsSupported(op);
}
if (ReadFields({ CondDef(), FieldDef<3>(1), FieldDef<4>(&op), FieldDef<1>(&s), FieldDef<4>(&rn),
FieldDef<4>(&rd), FieldDef<12>(&imm12) }))
{
form = Form::Immediate;
if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions;
if (rn == Register::PC) return false;
return IsSupported(op);
}
return false;
}
void Arithmetic::GenerateInstructionCode(InstructionBlock* instruction_block)
{
auto ir_builder = instruction_block->Module()->IrBuilder();
llvm::Value *left, *right, *carry_in;
ARMFuncs::ResultCarryOverflow result = { nullptr, nullptr, nullptr };
auto bitwise = IsBitwise(op);
carry_in = instruction_block->Read(Register::C);
left = instruction_block->Read(rn);
if (form == Form::Register)
{
if (bitwise)
{
auto shift_tn = ARMFuncs::DecodeImmShift(instruction_block, type, imm5);
auto shifted_carry = ARMFuncs::Shift_C(instruction_block, instruction_block->Read(rm), shift_tn.type, shift_tn.amount, carry_in);
right = shifted_carry.result;
result.carry = shifted_carry.carry;
}
else
{
auto shift_tn = ARMFuncs::DecodeImmShift(instruction_block, type, imm5);
right = ARMFuncs::Shift(instruction_block, instruction_block->Read(rm), shift_tn.type, shift_tn.amount, carry_in);
}
}
else
{
if (bitwise)
{
auto imm32_carry = ARMFuncs::ARMExpandImm_C(instruction_block, imm12, carry_in);
right = imm32_carry.result;
result.carry = imm32_carry.carry;
}
else
{
right = ARMFuncs::ARMExpandImm(instruction_block, imm12);
}
}
switch (op)
{
case Op::BitwiseAnd: result.result = ir_builder->CreateAnd(left, right); break;
case Op::BitwiseXor: result.result = ir_builder->CreateXor(left, right); break;
case Op::Subtract: result = ARMFuncs::AddWithCarry(instruction_block, left, ir_builder->CreateNot(right), ir_builder->getInt32(1)); break;
case Op::RevSubtract: result = ARMFuncs::AddWithCarry(instruction_block, ir_builder->CreateNot(left), right, ir_builder->getInt32(1)); break;
case Op::Add: result = ARMFuncs::AddWithCarry(instruction_block, left, right, ir_builder->getInt32(0)); break;
case Op::AddWithCarry: result = ARMFuncs::AddWithCarry(instruction_block, left, right, carry_in); break;
case Op::SubtractWithCarry: result = ARMFuncs::AddWithCarry(instruction_block, left, ir_builder->CreateNot(right), carry_in); break;
case Op::ReverseSubtractWithCarry: result = ARMFuncs::AddWithCarry(instruction_block, ir_builder->CreateNot(left), right, carry_in); break;
case Op::BitwiseOr: result.result = ir_builder->CreateOr(left, right); break;
case Op::BitwiseBitClear: result.result = ir_builder->CreateAnd(left, ir_builder->CreateNot(right)); break;
default: break;
}
instruction_block->Write(rd, result.result);
if (s)
{
instruction_block->Write(Register::N, ir_builder->CreateICmpSLT(result.result, ir_builder->getInt32(0)));
instruction_block->Write(Register::Z, ir_builder->CreateICmpEQ(result.result, ir_builder->getInt32(0)));
instruction_block->Write(Register::C, result.carry);
if (result.overflow)
instruction_block->Write(Register::V, result.overflow);
}
}

View File

@ -0,0 +1,36 @@
#include "Instruction.h"
#include "Types.h"
/*
* Data processing instructions
* ARMv7-A 5.2.1 (register), 5.2.2 (register-shifted register), 5.2.3 (immediate)
*/
class Arithmetic : public Instruction
{
public:
enum class Form
{
Register, RegisterShiftedRegister, Immediate
};
enum class Op
{
BitwiseAnd = 0, BitwiseXor, Subtract, RevSubtract, Add, AddWithCarry, SubtractWithCarry, ReverseSubtractWithCarry,
// Compare, Test, Misc
BitwiseOr = 12, MoveAndShifts, BitwiseBitClear, BitwiseNot
};
public:
virtual bool Decode() override;
void GenerateInstructionCode(InstructionBlock* instruction_block) override;
private:
Form form;
Op op;
bool s;
Register rn;
Register rd;
u32 imm5;
u32 imm12;
u32 type;
Register rm;
};

View File

@ -1,11 +1,6 @@
#include "Instruction.h" #include "Instruction.h"
#include "Types.h" #include "Types.h"
/*
* Data processing instructions
* ARMv7-A 5.2.1 (register), 5.2.2 (register-shifted register, 5.2.3 (immediate)
*/
class Branch : public Instruction class Branch : public Instruction
{ {
public: public:

View File

@ -243,7 +243,9 @@ void ModuleGen::DecodeInstructions()
for (auto i = Loader::ROMCodeStart; i <= Loader::ROMCodeStart + Loader::ROMCodeSize - 4; i += 4) for (auto i = Loader::ROMCodeStart; i <= Loader::ROMCodeStart + Loader::ROMCodeSize - 4; i += 4)
{ {
++total; ++total;
auto instruction = Disassembler::Disassemble(Memory::Read32(i), i); auto bytes = Memory::Read32(i);
if (bytes == 0) continue;
auto instruction = Disassembler::Disassemble(bytes, i);
if (instruction == nullptr) continue; if (instruction == nullptr) continue;
++generated; ++generated;
auto instruction_block = std::make_unique<InstructionBlock>(this, instruction.release()); auto instruction_block = std::make_unique<InstructionBlock>(this, instruction.release());