Added some shifts

This commit is contained in:
Dani Messerman 2015-05-01 14:05:31 +03:00
parent 66f70e7321
commit 22fbe294be
11 changed files with 274 additions and 9 deletions

View File

@ -0,0 +1,168 @@
#include "ARMFuncs.h"
#include "InstructionBlock.h"
ARMFuncs::ShiftTN ARMFuncs::DecodeImmShift(InstructionBlock* instruction, u32 type, u32 imm5)
{
auto ir_builder = instruction->IrBuilder();
switch (type)
{
case 0: return{ SRType::LSL, ir_builder->getInt32(imm5) };
case 1: return{ SRType::LSR, ir_builder->getInt32(imm5 ? imm5 : 32) };
case 2: return{ SRType::ASR, ir_builder->getInt32(imm5 ? imm5 : 32) };
case 3:
if (imm5)
return{ SRType::ROR, ir_builder->getInt32(imm5) };
else
return{ SRType::RRX, ir_builder->getInt32(1) };
default: assert(false, "Invalid shift type");
}
}
ARMFuncs::SRType ARMFuncs::DecodeRegShift(u32 type)
{
switch (type)
{
case 0: return SRType::LSL;
case 1: return SRType::LSR;
case 2: return SRType::ASR;
case 3: return SRType::ROR;
default: assert(false, "Invalid shift type");
}
}
llvm::Value* ARMFuncs::Shift(InstructionBlock* instruction, llvm::Value* value, SRType type, llvm::Value* amount, llvm::Value* carry_in)
{
return Shift_C(instruction, value, type, amount, carry_in).result;
}
ARMFuncs::ResultCarry ARMFuncs::Shift_C(InstructionBlock* instruction, llvm::Value* value, SRType type, llvm::Value* amount, llvm::Value* carry_in)
{
auto ir_builder = instruction->IrBuilder();
// amount_zero_basic_block will not recieve any code, it used only for the phi
auto amount_zero_basic_block = instruction->CreateBasicBlock("ShiftCAmount0");
auto amount_not_zero_basic_block = instruction->CreateBasicBlock("ShiftCAmountNot0");
auto phi_basic_block = instruction->CreateBasicBlock("ShiftCPhi");
ir_builder->CreateCondBr(ir_builder->CreateICmpEQ(amount, ir_builder->getInt32(0)), amount_zero_basic_block, amount_not_zero_basic_block);
ir_builder->SetInsertPoint(amount_zero_basic_block);
ir_builder->CreateBr(phi_basic_block);
ir_builder->SetInsertPoint(amount_not_zero_basic_block);
ResultCarry result_amount_not_zero = {};
switch (type)
{
case SRType::LSL: result_amount_not_zero = LSL_C(instruction, value, amount); break;
case SRType::LSR: result_amount_not_zero = LSR_C(instruction, value, amount); break;
case SRType::ASR: result_amount_not_zero = ASR_C(instruction, value, amount); break;
case SRType::ROR: result_amount_not_zero = ROR_C(instruction, value, amount); break;
case SRType::RRX: result_amount_not_zero = RRX_C(instruction, value, carry_in); break;
default: assert(false, "Invalid shift type");
}
auto pred = ir_builder->GetInsertBlock(); // The basic block might have changed and needs to be current for the phi
ir_builder->CreateBr(phi_basic_block);
ir_builder->SetInsertPoint(phi_basic_block);
auto result_phi = ir_builder->CreatePHI(ir_builder->getInt32Ty(), 2);
auto carry_phi = ir_builder->CreatePHI(ir_builder->getInt1Ty(), 2);
result_phi->addIncoming(value, amount_zero_basic_block);
result_phi->addIncoming(result_amount_not_zero.result, pred);
carry_phi->addIncoming(carry_in, amount_zero_basic_block);
carry_phi->addIncoming(result_amount_not_zero.carry, pred);
return{ result_phi, carry_phi };
}
// Generates code for LSL, LSR that checks for 0 shift
llvm::Value* ShiftZeroCheck(
InstructionBlock *instruction, llvm::Value* x, llvm::Value* shift,
std::function<ARMFuncs::ResultCarry(InstructionBlock *, llvm::Value*, llvm::Value*)> non_zero_function)
{
auto ir_builder = instruction->IrBuilder();
// amount_zero_basic_block will not recieve any code, it used only for the phi
auto amount_zero_basic_block = instruction->CreateBasicBlock("ShiftZeroCheckAmount0");
auto amount_not_zero_basic_block = instruction->CreateBasicBlock("ShiftZeroCheckAmountNot0");
auto phi_basic_block = instruction->CreateBasicBlock("ShiftZeroCheckPhi");
ir_builder->CreateCondBr(ir_builder->CreateICmpEQ(shift, ir_builder->getInt32(0)), amount_zero_basic_block, amount_not_zero_basic_block);
ir_builder->SetInsertPoint(amount_zero_basic_block);
ir_builder->CreateBr(phi_basic_block);
ir_builder->SetInsertPoint(amount_not_zero_basic_block);
auto result_amount_not_zero = non_zero_function(instruction, x, shift);
auto pred = ir_builder->GetInsertBlock(); // The basic block might have changed and needs to be current for the phi
ir_builder->CreateBr(phi_basic_block);
ir_builder->SetInsertPoint(phi_basic_block);
auto phi = ir_builder->CreatePHI(ir_builder->getInt32Ty(), 2);
phi->addIncoming(x, amount_zero_basic_block);
phi->addIncoming(result_amount_not_zero.result, pred);
return phi;
}
ARMFuncs::ResultCarry ARMFuncs::LSL_C(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
auto ir_builder = instruction->IrBuilder();
auto N = ir_builder->getInt32(32);
auto result = ir_builder->CreateShl(x, shift);
auto carry = ir_builder->CreateTrunc(ir_builder->CreateLShr(x, ir_builder->CreateSub(N, shift, "", true, true)), ir_builder->getInt1Ty());
return{ result, carry };
}
llvm::Value* ARMFuncs::LSL(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
return ShiftZeroCheck(instruction, x, shift, &ARMFuncs::LSL_C);
}
ARMFuncs::ResultCarry ARMFuncs::LSR_C(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
auto ir_builder = instruction->IrBuilder();
auto one = ir_builder->getInt32(1);
auto result = ir_builder->CreateLShr(x, shift);
auto carry = ir_builder->CreateTrunc(ir_builder->CreateLShr(x, ir_builder->CreateSub(shift, one, "", true, true)), ir_builder->getInt1Ty());
return{ result, carry };
}
llvm::Value* ARMFuncs::LSR(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
return ShiftZeroCheck(instruction, x, shift, &ARMFuncs::LSR_C);
}
ARMFuncs::ResultCarry ARMFuncs::ASR_C(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
auto ir_builder = instruction->IrBuilder();
auto one = ir_builder->getInt32(1);
auto result = ir_builder->CreateAShr(x, shift);
auto carry = ir_builder->CreateTrunc(ir_builder->CreateLShr(x, ir_builder->CreateSub(shift, one, "", true, true)), ir_builder->getInt1Ty());
return{ result, carry };
}
ARMFuncs::ResultCarry ARMFuncs::ROR_C(InstructionBlock* instruction, llvm::Value* x, llvm::Value* shift)
{
auto ir_builder = instruction->IrBuilder();
auto N = ir_builder->getInt32(32);
auto m = ir_builder->CreateURem(shift, N);
auto result = ir_builder->CreateOr(LSR(instruction, x, m), LSL(instruction, x, ir_builder->CreateSub(N, m)));
auto carry = ir_builder->CreateTrunc(ir_builder->CreateLShr(result, ir_builder->getInt32(31)), ir_builder->getInt1Ty());
return{ result, carry };
}
ARMFuncs::ResultCarry ARMFuncs::RRX_C(InstructionBlock* instruction, llvm::Value* x, llvm::Value* carry_in)
{
auto ir_builder = instruction->IrBuilder();
auto result = ir_builder->CreateLShr(x, 1);
result = ir_builder->CreateOr(result, ir_builder->CreateShl(ir_builder->CreateZExt(carry_in, ir_builder->getInt32Ty()), 31));
auto carry = ir_builder->CreateTrunc(x, ir_builder->getInt1Ty());
return{ result, carry };
}

View File

@ -0,0 +1,42 @@
#include <common/common_types.h>
/*
* Functions from the manual,
* A8.4.3 Pseudocode details of instruction-specified shifts and rotates
* A2.2.1 Integer arithmetic
*/
class InstructionBlock;
namespace llvm
{
class Value;
}
class ARMFuncs
{
public:
enum class SRType { LSL, LSR, ASR, RRX, ROR };
struct ShiftTN
{
SRType type;
llvm::Value *amount;
};
struct ResultCarry
{
llvm::Value *result, *carry;
};
static ShiftTN DecodeImmShift(InstructionBlock *instruction, u32 type, u32 imm5);
static SRType DecodeRegShift(u32 type);
static llvm::Value *Shift(InstructionBlock *instruction, llvm::Value *value, SRType type, llvm::Value *amount, llvm::Value *carry_in);
static ResultCarry Shift_C(InstructionBlock *instruction, llvm::Value *value, SRType type, llvm::Value *amount, llvm::Value *carry_in);
static ResultCarry LSL_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
static llvm::Value *LSL(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
static ResultCarry LSR_C(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
static llvm::Value *LSR(InstructionBlock *instruction, llvm::Value *x, llvm::Value *shift);
static ResultCarry ASR_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);
};

View File

@ -6,6 +6,7 @@ set(SRCS
InstructionBlock.cpp InstructionBlock.cpp
MachineState.cpp MachineState.cpp
TBAA.cpp TBAA.cpp
ARMFuncs.cpp
Instructions/Instruction.cpp Instructions/Instruction.cpp
Instructions/DataProcessing.cpp Instructions/DataProcessing.cpp
@ -19,6 +20,7 @@ set(HEADERS
MachineState.h MachineState.h
TBAA.h TBAA.h
BinarySearch.h BinarySearch.h
ARMFuncs.h
Instructions/Types.h Instructions/Types.h
Instructions/Instruction.h Instructions/Instruction.h

View File

@ -1,6 +1,8 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <common/common_types.h> #include <common/common_types.h>
#include <llvm/IR/IRBuilder.h>
#include "ModuleGen.h"
namespace llvm namespace llvm
{ {
@ -8,7 +10,6 @@ namespace llvm
class BasicBlock; class BasicBlock;
} }
class ModuleGen;
class Instruction; class Instruction;
enum class Register; enum class Register;
@ -51,6 +52,7 @@ public:
u32 Address(); u32 Address();
ModuleGen *Module() { return module; } ModuleGen *Module() { return module; }
llvm::IRBuilder<> *IrBuilder() { return module->IrBuilder(); }
llvm::BasicBlock *GetEntryBasicBlock() { return entry_basic_block; } llvm::BasicBlock *GetEntryBasicBlock() { return entry_basic_block; }
private: private:

View File

@ -2,6 +2,7 @@
#include "Disassembler.h" #include "Disassembler.h"
#include "InstructionBlock.h" #include "InstructionBlock.h"
#include "ModuleGen.h" #include "ModuleGen.h"
#include "ARMFuncs.h"
static RegisterInstruction<DataProcessing> register_instruction; static RegisterInstruction<DataProcessing> register_instruction;
@ -9,12 +10,11 @@ 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({ CondDef(), 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<2>(&op2), FieldDef<1>(0), FieldDef<4>(&rm) }))
{ {
form = Form::Register; form = Form::Register;
if (imm5 != 0) return false; // Shifts if (rm == Register::PC) return false;
if (s != 0) return false; // Set flags if (rd == Register::PC && s) return false; // SEE SUBS PC, LR and related instructions;
if (rm == Register::PC) return false; // Jump
return true; return true;
} }
if (ReadFields({ CondDef(), 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),
@ -29,10 +29,51 @@ bool DataProcessing::Decode()
void DataProcessing::GenerateInstructionCode(InstructionBlock* instruction_block) void DataProcessing::GenerateInstructionCode(InstructionBlock* instruction_block)
{ {
// Currently supports only mov reg, reg auto ir_builder = instruction_block->IrBuilder();
auto value = instruction_block->Read(rm); auto original_carry = instruction_block->Read(Register::C);
instruction_block->Write(rd, value); ARMFuncs::ResultCarry result = { instruction_block->Read(rm), original_carry };
switch (op2)
{
case Op2Type::MoveAndLSL:
if (imm5 != 0)
{
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSL,
ARMFuncs::DecodeImmShift(instruction_block, 0, imm5).amount, result.carry);
}
break;
case Op2Type::LSR:
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::LSR,
ARMFuncs::DecodeImmShift(instruction_block, 1, imm5).amount, result.carry);
break;
case Op2Type::ASR:
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ASR,
ARMFuncs::DecodeImmShift(instruction_block, 2, imm5).amount, result.carry);
break;
case Op2Type::RRXAndROR:
if (imm5 == 0)
{
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::RRX,
ir_builder->getInt32(1), result.carry);
}
else
{
result = ARMFuncs::Shift_C(instruction_block, result.result, ARMFuncs::SRType::ROR,
ARMFuncs::DecodeImmShift(instruction_block, 3, imm5).amount, result.carry);
}
break;
}
instruction_block->Write(rd, result.result);
if (s)
{
instruction_block->Write(Register::N, ir_builder->CreateTrunc(ir_builder->CreateLShr(result.result, 31), ir_builder->getInt1Ty()));
instruction_block->Write(Register::Z, ir_builder->CreateICmpEQ(result.result, ir_builder->getInt32(0)));
if (result.carry != original_carry)
instruction_block->Write(Register::C, result.carry);
}
if (rd == Register::PC) if (rd == Register::PC)
{ {

View File

@ -18,6 +18,10 @@ public:
// Compare, Test, Misc // Compare, Test, Misc
BitwiseOr = 12, MoveAndShifts, BitwiseBitClear, BitwiseNot BitwiseOr = 12, MoveAndShifts, BitwiseBitClear, BitwiseNot
}; };
enum class Op2Type
{
MoveAndLSL, LSR, ASR, RRXAndROR
};
enum class Form enum class Form
{ {
Register, RegisterShiftedRegister, Immediate Register, RegisterShiftedRegister, Immediate
@ -35,4 +39,5 @@ private:
Register rm; Register rm;
u32 imm12; u32 imm12;
u32 imm5; u32 imm5;
Op2Type op2;
}; };

View File

@ -5,6 +5,7 @@
#include <llvm/IR/Constants.h> #include <llvm/IR/Constants.h>
#include <llvm/IR/LLVMContext.h> #include <llvm/IR/LLVMContext.h>
#include <llvm/IR/GlobalVariable.h> #include <llvm/IR/GlobalVariable.h>
#include "TBAA.h"
using namespace llvm; using namespace llvm;

View File

@ -6,6 +6,7 @@ class ModuleGen;
namespace llvm namespace llvm
{ {
class Value; class Value;
class Instruction;
class GlobalVariable; class GlobalVariable;
} }

View File

@ -9,6 +9,7 @@
#include <llvm/IR/GlobalVariable.h> #include <llvm/IR/GlobalVariable.h>
#include <stack> #include <stack>
#include "MachineState.h" #include "MachineState.h"
#include "TBAA.h"
using namespace llvm; using namespace llvm;

View File

@ -1,12 +1,13 @@
#pragma once
#include <llvm/IR/IRBuilder.h> #include <llvm/IR/IRBuilder.h>
#include <unordered_map> #include <unordered_map>
#include <common/common_types.h> #include <common/common_types.h>
#include "TBAA.h"
enum class Register; enum class Register;
class InstructionBlock; class InstructionBlock;
class MachineState; class MachineState;
class TBAA;
namespace llvm namespace llvm
{ {

View File

@ -1,3 +1,4 @@
#pragma once
#include "Instructions/Types.h" #include "Instructions/Types.h"
namespace llvm namespace llvm