More Speed

This commit is contained in:
MerryMage 2016-07-22 23:55:00 +01:00
parent 5fbfc6c155
commit 51448aa06d
16 changed files with 1066 additions and 955 deletions

View file

@ -52,94 +52,69 @@ const char* GetNameOf(Opcode op) {
// Value class member definitions
void Value::ReplaceUsesWith(ValuePtr replacement) {
while (!uses.empty()) {
auto use = uses.front();
use.use_owner.lock()->ReplaceUseOfXWithY(use.value.lock(), replacement);
}
}
std::vector<ValuePtr> Value::GetUses() const {
std::vector<ValuePtr> result(uses.size());
std::transform(uses.begin(), uses.end(), result.begin(), [](const auto& use){ return use.use_owner.lock(); });
return result;
}
void Value::AddUse(ValuePtr owner) {
// There can be multiple uses from the same owner.
uses.push_back({ shared_from_this(), owner });
}
void Value::RemoveUse(ValuePtr owner) {
// Remove only one use.
auto iter = std::find_if(uses.begin(), uses.end(), [&owner](auto use) { return use.use_owner.lock() == owner; });
ASSERT_MSG(iter != uses.end(), "RemoveUse without associated AddUse. Bug in use management code.");
uses.erase(iter);
}
void Value::ReplaceUseOfXWithY(ValuePtr x, ValuePtr y) {
// This should never be called. Use management is incorrect if this is ever called.
ASSERT_MSG(false, "This Value type doesn't use any values. Bug in use management code.");
}
void Value::AssertValid() {
ASSERT(std::all_of(uses.begin(), uses.end(), [](const auto& use) { return !use.use_owner.expired(); }));
Type Value::GetType() const {
return IsImmediate() ? type : inner.inst->GetType();
}
// Inst class member definitions
Inst::Inst(Opcode op_) : Value(op_) {
args.resize(GetNumArgsOf(op));
Value Inst::GetArg(size_t index) const {
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(!args[index].IsEmpty());
return args[index];
}
void Inst::SetArg(size_t index, ValuePtr value) {
auto this_ = shared_from_this();
void Inst::SetArg(size_t index, Value value) {
DEBUG_ASSERT(index < GetNumArgsOf(op));
DEBUG_ASSERT(value.GetType() == GetArgTypeOf(op, index));
if (auto prev_value = args.at(index).lock()) {
prev_value->RemoveUse(this_);
if (!args[index].IsImmediate()) {
UndoUse(args[index]);
}
if (!value.IsImmediate()) {
Use(value);
}
ASSERT(value->GetType() == GetArgTypeOf(op, index));
args.at(index) = value;
value->AddUse(this_);
}
ValuePtr Inst::GetArg(size_t index) const {
ASSERT_MSG(!args.at(index).expired(), "This should never happen. All Values should be owned by a MicroBlock.");
return args.at(index).lock();
args[index] = value;
}
void Inst::Invalidate() {
AssertValid();
ASSERT(!HasUses());
auto this_ = shared_from_this();
for (auto& arg : args) {
arg.lock()->RemoveUse(this_);
}
}
void Inst::AssertValid() {
ASSERT(std::all_of(args.begin(), args.end(), [](const auto& arg) { return !arg.expired(); }));
Value::AssertValid();
}
void Inst::ReplaceUseOfXWithY(ValuePtr x, ValuePtr y) {
bool has_use = false;
auto this_ = shared_from_this();
// Note that there may be multiple uses of x.
for (auto& arg : args) {
if (arg.lock() == x) {
arg = y;
has_use = true;
x->RemoveUse(this_);
y->AddUse(this_);
for (auto& value : args) {
if (!value.IsImmediate()) {
UndoUse(value);
}
}
}
ASSERT_MSG(has_use, "This Inst doesn't have x. Bug in use management code.");
void Inst::Use(Value& value) {
value.GetInst()->use_count++;
switch (op){
case Opcode::GetCarryFromOp:
value.GetInst()->carry_inst = this;
break;
case Opcode::GetOverflowFromOp:
value.GetInst()->overflow_inst = this;
break;
default:
break;
}
}
void Inst::UndoUse(Value& value) {
value.GetInst()->use_count--;
switch (op){
case Opcode::GetCarryFromOp:
value.GetInst()->carry_inst = nullptr;
break;
case Opcode::GetOverflowFromOp:
value.GetInst()->overflow_inst = nullptr;
break;
default:
break;
}
}
std::string DumpBlock(const IR::Block& block) {
@ -160,65 +135,48 @@ std::string DumpBlock(const IR::Block& block) {
}
ret += "\n";
std::map<IR::Value*, size_t> value_to_index;
std::map<const IR::Inst*, size_t> inst_to_index;
size_t index = 0;
const auto arg_to_string = [&value_to_index](IR::ValuePtr arg) -> std::string {
if (!arg) {
const auto arg_to_string = [&inst_to_index](const IR::Value& arg) -> std::string {
if (arg.IsEmpty()) {
return "<null>";
} else if (!arg.IsImmediate()) {
return Common::StringFromFormat("%%%zu", inst_to_index.at(arg.GetInst()));
}
switch (arg->GetOpcode()) {
case Opcode::ImmU1: {
auto inst = reinterpret_cast<ImmU1*>(arg.get());
return Common::StringFromFormat("#%s", inst->value ? "1" : "0");
}
case Opcode::ImmU8: {
auto inst = reinterpret_cast<ImmU8*>(arg.get());
return Common::StringFromFormat("#%u", inst->value);
}
case Opcode::ImmU32: {
auto inst = reinterpret_cast<ImmU32*>(arg.get());
return Common::StringFromFormat("#%#x", inst->value);
}
case Opcode::ImmRegRef: {
auto inst = reinterpret_cast<ImmRegRef*>(arg.get());
return Arm::RegToString(inst->value);
}
default: {
return Common::StringFromFormat("%%%zu", value_to_index.at(arg.get()));
}
switch (arg.GetType()) {
case Type::U1:
return Common::StringFromFormat("#%s", arg.GetU1() ? "1" : "0");
case Type::U8:
return Common::StringFromFormat("#%u", arg.GetU8());
case Type::U32:
return Common::StringFromFormat("#%#x", arg.GetU32());
case Type::RegRef:
return Arm::RegToString(arg.GetRegRef());
default:
return "<unknown immediate type>";
}
};
for (const auto& inst_ptr : block.instructions) {
const Opcode op = inst_ptr->GetOpcode();
switch (op) {
case Opcode::ImmU1:
case Opcode::ImmU8:
case Opcode::ImmU32:
case Opcode::ImmRegRef:
break;
default: {
if (GetTypeOf(op) != Type::Void) {
ret += Common::StringFromFormat("%%%-5zu = ", index);
} else {
ret += " "; // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
}
for (auto inst = block.instructions.begin(); inst != block.instructions.end(); ++inst) {
const Opcode op = inst->GetOpcode();
ret += GetNameOf(op);
const size_t arg_count = GetNumArgsOf(op);
const auto inst = reinterpret_cast<Inst*>(inst_ptr.get());
for (size_t arg_index = 0; arg_index < arg_count; arg_index++) {
ret += arg_index != 0 ? ", " : " ";
ret += arg_to_string(inst->GetArg(arg_index));
}
ret += "\n";
value_to_index[inst_ptr.get()] = index++;
break;
}
if (GetTypeOf(op) != Type::Void) {
ret += Common::StringFromFormat("%%%-5zu = ", index);
} else {
ret += " "; // '%00000 = ' -> 1 + 5 + 3 = 9 spaces
}
ret += GetNameOf(op);
const size_t arg_count = GetNumArgsOf(op);
for (size_t arg_index = 0; arg_index < arg_count; arg_index++) {
ret += arg_index != 0 ? ", " : " ";
ret += arg_to_string(inst->GetArg(arg_index));
}
ret += "\n";
inst_to_index.at(&*inst) = index++;
}
return ret;

View file

@ -10,9 +10,12 @@
#include <memory>
#include <vector>
#include <boost/variant.hpp>
#include <boost/pool/pool.hpp>
#include <boost/intrusive/list.hpp>
#include <boost/optional.hpp>
#include <boost/variant.hpp>
#include "common/assert.h"
#include "common/common_types.h"
#include "frontend/arm_types.h"
#include "frontend/ir/opcodes.h"
@ -47,22 +50,91 @@ const char* GetNameOf(Opcode op);
// Type declarations
/// Base class for microinstructions to derive from.
/**
* A representation of a microinstruction. A single ARM/Thumb instruction may be
* converted into zero or more microinstructions.
*/
class Value;
using ValuePtr = std::shared_ptr<Value>;
using ValueWeakPtr = std::weak_ptr<Value>;
struct Value;
class Inst;
class Value : public std::enable_shared_from_this<Value> {
struct Value final {
public:
virtual ~Value() = default;
Value() : type(Type::Void) {}
bool HasUses() const { return !uses.empty(); }
bool HasOneUse() const { return uses.size() == 1; }
bool HasManyUses() const { return uses.size() > 1; }
explicit Value(Inst* value) : type(Type::Opaque) {
inner.inst = value;
}
/// Replace all uses of this Value with `replacement`.
void ReplaceUsesWith(ValuePtr replacement);
explicit Value(Arm::Reg value) : type(Type::RegRef) {
inner.imm_regref = value;
}
explicit Value(bool value) : type(Type::U1) {
inner.imm_u1 = value;
}
explicit Value(u8 value) : type(Type::U8) {
inner.imm_u8 = value;
}
explicit Value(u32 value) : type(Type::U32) {
inner.imm_u32 = value;
}
bool IsEmpty() const {
return type == Type::Void;
}
bool IsImmediate() const {
return type != Type::Opaque;
}
Type GetType() const;
Inst* GetInst() const {
DEBUG_ASSERT(type == Type::Opaque);
return inner.inst;
}
Arm::Reg GetRegRef() const {
DEBUG_ASSERT(type == Type::RegRef);
return inner.imm_regref;
}
bool GetU1() const {
DEBUG_ASSERT(type == Type::U1);
return inner.imm_u1;
}
u8 GetU8() const {
DEBUG_ASSERT(type == Type::U8);
return inner.imm_u8;
}
u32 GetU32() const {
DEBUG_ASSERT(type == Type::U32);
return inner.imm_u32;
}
private:
Type type;
union {
Inst* inst; // type == Type::Opaque
Arm::Reg imm_regref;
bool imm_u1;
u8 imm_u8;
u32 imm_u32;
} inner;
};
using InstListLinkMode = boost::intrusive::link_mode<boost::intrusive::normal_link>;
class Inst final : public boost::intrusive::list_base_hook<InstListLinkMode> {
public:
Inst(Opcode op) : op(op) {}
bool HasUses() const { return use_count > 0; }
/// Get the microop this microinstruction represents.
Opcode GetOpcode() const { return op; }
@ -70,99 +142,22 @@ public:
Type GetType() const { return GetTypeOf(op); }
/// Get the number of arguments this instruction has.
size_t NumArgs() const { return GetNumArgsOf(op); }
/// Get the number of uses this instruction has.
size_t NumUses() const { return uses.size(); }
std::vector<ValuePtr> GetUses() const;
Value GetArg(size_t index) const;
void SetArg(size_t index, Value value);
/// Prepare this Value for removal from the instruction stream.
virtual void Invalidate() {}
/// Assert that this Value is valid.
virtual void AssertValid();
void Invalidate();
intptr_t GetTag() const { return tag; }
void SetTag(intptr_t tag_) { tag = tag_; }
protected:
friend class Inst;
explicit Value(Opcode op_) : op(op_) {}
void AddUse(ValuePtr owner);
void RemoveUse(ValuePtr owner);
virtual void ReplaceUseOfXWithY(ValuePtr x, ValuePtr y);
size_t use_count = 0;
Inst* carry_inst = nullptr;
Inst* overflow_inst = nullptr;
private:
void Use(Value& value);
void UndoUse(Value& value);
Opcode op;
struct Use {
/// The instruction which is being used.
ValueWeakPtr value;
/// The instruction which is using `value`.
ValueWeakPtr use_owner;
};
std::list<Use> uses;
intptr_t tag = 0;
};
/// Representation of a u1 immediate.
class ImmU1 final : public Value {
public:
explicit ImmU1(bool value_) : Value(Opcode::ImmU1), value(value_) {}
~ImmU1() override = default;
const bool value; ///< Literal value to load
};
/// Representation of a u8 immediate.
class ImmU8 final : public Value {
public:
explicit ImmU8(u8 value_) : Value(Opcode::ImmU8), value(value_) {}
~ImmU8() override = default;
const u8 value; ///< Literal value to load
};
/// Representation of a u32 immediate.
class ImmU32 final : public Value {
public:
explicit ImmU32(u32 value_) : Value(Opcode::ImmU32), value(value_) {}
~ImmU32() override = default;
const u32 value; ///< Literal value to load
};
/// Representation of a GPR reference.
class ImmRegRef final : public Value {
public:
explicit ImmRegRef(Arm::Reg value_) : Value(Opcode::ImmRegRef), value(value_) {}
~ImmRegRef() override = default;
const Arm::Reg value; ///< Literal value to load
};
/**
* A representation of a microinstruction. A single ARM/Thumb instruction may be
* converted into zero or more microinstructions.
*/
class Inst final : public Value {
public:
explicit Inst(Opcode op);
~Inst() override = default;
/// Set argument number `index` to `value`.
void SetArg(size_t index, ValuePtr value);
/// Get argument number `index`.
ValuePtr GetArg(size_t index) const;
void Invalidate() override;
void AssertValid() override;
protected:
void ReplaceUseOfXWithY(ValuePtr x, ValuePtr y) override;
private:
std::vector<ValueWeakPtr> args;
std::array<Value, 3> args;
};
namespace Term {
@ -261,7 +256,9 @@ public:
boost::optional<Arm::LocationDescriptor> cond_failed = {};
/// List of instructions in this block.
std::list<ValuePtr> instructions;
boost::intrusive::list<Inst, InstListLinkMode> instructions;
/// Memory pool for instruction list
std::unique_ptr<boost::pool<>> instruction_alloc_pool = std::make_unique<boost::pool<>>(sizeof(Inst));
/// Terminal instruction of this block.
Terminal terminal = Term::Invalid{};

View file

@ -24,138 +24,132 @@ u32 IREmitter::AlignPC(size_t alignment) {
return static_cast<u32>(pc - pc % alignment);
}
IR::ValuePtr IREmitter::Imm1(bool value) {
auto imm1 = std::make_shared<IR::ImmU1>(value);
AddToBlock(imm1);
return imm1;
IR::Value IREmitter::Imm1(bool imm1) {
return IR::Value(imm1);
}
IR::ValuePtr IREmitter::Imm8(u8 i) {
auto imm8 = std::make_shared<IR::ImmU8>(i);
AddToBlock(imm8);
return imm8;
IR::Value IREmitter::Imm8(u8 imm8) {
return IR::Value(imm8);
}
IR::ValuePtr IREmitter::Imm32(u32 i) {
auto imm32 = std::make_shared<IR::ImmU32>(i);
AddToBlock(imm32);
return imm32;
IR::Value IREmitter::Imm32(u32 imm32) {
return IR::Value(imm32);
}
IR::ValuePtr IREmitter::GetRegister(Reg reg) {
IR::Value IREmitter::GetRegister(Reg reg) {
if (reg == Reg::PC) {
return Imm32(PC());
}
return Inst(IR::Opcode::GetRegister, { RegRef(reg) });
return Inst(IR::Opcode::GetRegister, { IR::Value(reg) });
}
void IREmitter::SetRegister(const Reg reg, IR::ValuePtr value) {
void IREmitter::SetRegister(const Reg reg, const IR::Value& value) {
ASSERT(reg != Reg::PC);
Inst(IR::Opcode::SetRegister, { RegRef(reg), value });
Inst(IR::Opcode::SetRegister, { IR::Value(reg), value });
}
void IREmitter::ALUWritePC(IR::ValuePtr value) {
void IREmitter::ALUWritePC(const IR::Value& value) {
// This behaviour is ARM version-dependent.
// The below implementation is for ARMv6k
BranchWritePC(value);
}
void IREmitter::BranchWritePC(IR::ValuePtr value) {
void IREmitter::BranchWritePC(const IR::Value& value) {
if (!current_location.TFlag) {
auto new_pc = And(value, Imm32(0xFFFFFFFC));
Inst(IR::Opcode::SetRegister, { RegRef(Reg::PC), new_pc });
Inst(IR::Opcode::SetRegister, { IR::Value(Reg::PC), new_pc });
} else {
auto new_pc = And(value, Imm32(0xFFFFFFFE));
Inst(IR::Opcode::SetRegister, { RegRef(Reg::PC), new_pc });
Inst(IR::Opcode::SetRegister, { IR::Value(Reg::PC), new_pc });
}
}
void IREmitter::BXWritePC(IR::ValuePtr value) {
void IREmitter::BXWritePC(const IR::Value& value) {
Inst(IR::Opcode::BXWritePC, {value});
}
void IREmitter::LoadWritePC(IR::ValuePtr value) {
void IREmitter::LoadWritePC(const IR::Value& value) {
// This behaviour is ARM version-dependent.
// The below implementation is for ARMv6k
BXWritePC(value);
}
void IREmitter::CallSupervisor(IR::ValuePtr value) {
void IREmitter::CallSupervisor(const IR::Value& value) {
Inst(IR::Opcode::CallSupervisor, {value});
}
IR::ValuePtr IREmitter::GetCFlag() {
IR::Value IREmitter::GetCFlag() {
return Inst(IR::Opcode::GetCFlag, {});
}
void IREmitter::SetNFlag(IR::ValuePtr value) {
void IREmitter::SetNFlag(const IR::Value& value) {
Inst(IR::Opcode::SetNFlag, {value});
}
void IREmitter::SetZFlag(IR::ValuePtr value) {
void IREmitter::SetZFlag(const IR::Value& value) {
Inst(IR::Opcode::SetZFlag, {value});
}
void IREmitter::SetCFlag(IR::ValuePtr value) {
void IREmitter::SetCFlag(const IR::Value& value) {
Inst(IR::Opcode::SetCFlag, {value});
}
void IREmitter::SetVFlag(IR::ValuePtr value) {
void IREmitter::SetVFlag(const IR::Value& value) {
Inst(IR::Opcode::SetVFlag, {value});
}
IR::ValuePtr IREmitter::LeastSignificantHalf(IR::ValuePtr value) {
IR::Value IREmitter::LeastSignificantHalf(const IR::Value& value) {
return Inst(IR::Opcode::LeastSignificantHalf, {value});
}
IR::ValuePtr IREmitter::LeastSignificantByte(IR::ValuePtr value) {
IR::Value IREmitter::LeastSignificantByte(const IR::Value& value) {
return Inst(IR::Opcode::LeastSignificantByte, {value});
}
IR::ValuePtr IREmitter::MostSignificantBit(IR::ValuePtr value) {
IR::Value IREmitter::MostSignificantBit(const IR::Value& value) {
return Inst(IR::Opcode::MostSignificantBit, {value});
}
IR::ValuePtr IREmitter::IsZero(IR::ValuePtr value) {
IR::Value IREmitter::IsZero(const IR::Value& value) {
return Inst(IR::Opcode::IsZero, {value});
}
IREmitter::ResultAndCarry IREmitter::LogicalShiftLeft(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarry IREmitter::LogicalShiftLeft(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in) {
auto result = Inst(IR::Opcode::LogicalShiftLeft, {value_in, shift_amount, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
return {result, carry_out};
}
IREmitter::ResultAndCarry IREmitter::LogicalShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarry IREmitter::LogicalShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in) {
auto result = Inst(IR::Opcode::LogicalShiftRight, {value_in, shift_amount, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
return {result, carry_out};
}
IREmitter::ResultAndCarry IREmitter::ArithmeticShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarry IREmitter::ArithmeticShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in) {
auto result = Inst(IR::Opcode::ArithmeticShiftRight, {value_in, shift_amount, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
return {result, carry_out};
}
IREmitter::ResultAndCarry IREmitter::RotateRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarry IREmitter::RotateRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in) {
auto result = Inst(IR::Opcode::RotateRight, {value_in, shift_amount, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
return {result, carry_out};
}
IREmitter::ResultAndCarryAndOverflow IREmitter::AddWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarryAndOverflow IREmitter::AddWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in) {
auto result = Inst(IR::Opcode::AddWithCarry, {a, b, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
auto overflow = Inst(IR::Opcode::GetOverflowFromOp, {result});
return {result, carry_out, overflow};
}
IR::ValuePtr IREmitter::Add(IR::ValuePtr a, IR::ValuePtr b) {
IR::Value IREmitter::Add(const IR::Value& a, const IR::Value& b) {
return Inst(IR::Opcode::AddWithCarry, {a, b, Imm1(0)});
}
IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in) {
IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in) {
// This is equivalent to AddWithCarry(a, Not(b), carry_in).
auto result = Inst(IR::Opcode::SubWithCarry, {a, b, carry_in});
auto carry_out = Inst(IR::Opcode::GetCarryFromOp, {result});
@ -163,96 +157,102 @@ IREmitter::ResultAndCarryAndOverflow IREmitter::SubWithCarry(IR::ValuePtr a, IR:
return {result, carry_out, overflow};
}
IR::ValuePtr IREmitter::Sub(IR::ValuePtr a, IR::ValuePtr b) {
IR::Value IREmitter::Sub(const IR::Value& a, const IR::Value& b) {
return Inst(IR::Opcode::SubWithCarry, {a, b, Imm1(1)});
}
IR::ValuePtr IREmitter::And(IR::ValuePtr a, IR::ValuePtr b) {
IR::Value IREmitter::And(const IR::Value& a, const IR::Value& b) {
return Inst(IR::Opcode::And, {a, b});
}
IR::ValuePtr IREmitter::Eor(IR::ValuePtr a, IR::ValuePtr b) {
IR::Value IREmitter::Eor(const IR::Value& a, const IR::Value& b) {
return Inst(IR::Opcode::Eor, {a, b});
}
IR::ValuePtr IREmitter::Or(IR::ValuePtr a, IR::ValuePtr b) {
IR::Value IREmitter::Or(const IR::Value& a, const IR::Value& b) {
return Inst(IR::Opcode::Or, {a, b});
}
IR::ValuePtr IREmitter::Not(IR::ValuePtr a) {
IR::Value IREmitter::Not(const IR::Value& a) {
return Inst(IR::Opcode::Not, {a});
}
IR::ValuePtr IREmitter::SignExtendHalfToWord(IR::ValuePtr a) {
IR::Value IREmitter::SignExtendHalfToWord(const IR::Value& a) {
return Inst(IR::Opcode::SignExtendHalfToWord, {a});
}
IR::ValuePtr IREmitter::SignExtendByteToWord(IR::ValuePtr a) {
IR::Value IREmitter::SignExtendByteToWord(const IR::Value& a) {
return Inst(IR::Opcode::SignExtendByteToWord, {a});
}
IR::ValuePtr IREmitter::ZeroExtendHalfToWord(IR::ValuePtr a) {
IR::Value IREmitter::ZeroExtendHalfToWord(const IR::Value& a) {
return Inst(IR::Opcode::ZeroExtendHalfToWord, {a});
}
IR::ValuePtr IREmitter::ZeroExtendByteToWord(IR::ValuePtr a) {
IR::Value IREmitter::ZeroExtendByteToWord(const IR::Value& a) {
return Inst(IR::Opcode::ZeroExtendByteToWord, {a});
}
IR::ValuePtr IREmitter::ByteReverseWord(IR::ValuePtr a) {
IR::Value IREmitter::ByteReverseWord(const IR::Value& a) {
return Inst(IR::Opcode::ByteReverseWord, {a});
}
IR::ValuePtr IREmitter::ByteReverseHalf(IR::ValuePtr a) {
IR::Value IREmitter::ByteReverseHalf(const IR::Value& a) {
return Inst(IR::Opcode::ByteReverseHalf, {a});
}
IR::ValuePtr IREmitter::ByteReverseDual(IR::ValuePtr a) {
IR::Value IREmitter::ByteReverseDual(const IR::Value& a) {
return Inst(IR::Opcode::ByteReverseDual, {a});
}
IR::ValuePtr IREmitter::ReadMemory8(IR::ValuePtr vaddr) {
IR::Value IREmitter::ReadMemory8(const IR::Value& vaddr) {
return Inst(IR::Opcode::ReadMemory8, {vaddr});
}
IR::ValuePtr IREmitter::ReadMemory16(IR::ValuePtr vaddr) {
IR::Value IREmitter::ReadMemory16(const IR::Value& vaddr) {
auto value = Inst(IR::Opcode::ReadMemory16, {vaddr});
return current_location.EFlag ? ByteReverseHalf(value) : value;
}
IR::ValuePtr IREmitter::ReadMemory32(IR::ValuePtr vaddr) {
IR::Value IREmitter::ReadMemory32(const IR::Value& vaddr) {
auto value = Inst(IR::Opcode::ReadMemory32, {vaddr});
return current_location.EFlag ? ByteReverseWord(value) : value;
}
IR::ValuePtr IREmitter::ReadMemory64(IR::ValuePtr vaddr) {
IR::Value IREmitter::ReadMemory64(const IR::Value& vaddr) {
auto value = Inst(IR::Opcode::ReadMemory64, {vaddr});
return current_location.EFlag ? ByteReverseDual(value) : value;
}
void IREmitter::WriteMemory8(IR::ValuePtr vaddr, IR::ValuePtr value) {
void IREmitter::WriteMemory8(const IR::Value& vaddr, const IR::Value& value) {
Inst(IR::Opcode::WriteMemory8, {vaddr, value});
}
void IREmitter::WriteMemory16(IR::ValuePtr vaddr, IR::ValuePtr value) {
void IREmitter::WriteMemory16(const IR::Value& vaddr, const IR::Value& value) {
if (current_location.EFlag) {
value = ByteReverseHalf(value);
auto v = ByteReverseHalf(value);
Inst(IR::Opcode::WriteMemory16, {vaddr, v});
} else {
Inst(IR::Opcode::WriteMemory16, {vaddr, value});
}
Inst(IR::Opcode::WriteMemory16, {vaddr, value});
}
void IREmitter::WriteMemory32(IR::ValuePtr vaddr, IR::ValuePtr value) {
void IREmitter::WriteMemory32(const IR::Value& vaddr, const IR::Value& value) {
if (current_location.EFlag) {
value = ByteReverseWord(value);
auto v = ByteReverseWord(value);
Inst(IR::Opcode::WriteMemory32, {vaddr, v});
} else {
Inst(IR::Opcode::WriteMemory32, {vaddr, value});
}
Inst(IR::Opcode::WriteMemory32, {vaddr, value});
}
void IREmitter::WriteMemory64(IR::ValuePtr vaddr, IR::ValuePtr value) {
void IREmitter::WriteMemory64(const IR::Value& vaddr, const IR::Value& value) {
if (current_location.EFlag) {
value = ByteReverseDual(value);
auto v = ByteReverseDual(value);
Inst(IR::Opcode::WriteMemory64, {vaddr, v});
} else {
Inst(IR::Opcode::WriteMemory64, {vaddr, value});
}
Inst(IR::Opcode::WriteMemory64, {vaddr, value});
}
void IREmitter::SetTerm(const IR::Terminal& terminal) {
@ -260,28 +260,18 @@ void IREmitter::SetTerm(const IR::Terminal& terminal) {
block.terminal = terminal;
}
IR::ValuePtr IREmitter::Inst(IR::Opcode op, std::initializer_list<IR::ValuePtr> args) {
auto inst = std::make_shared<IR::Inst>(op);
assert(args.size() == inst->NumArgs());
IR::Value IREmitter::Inst(IR::Opcode op, std::initializer_list<IR::Value> args) {
IR::Inst* inst = new(block.instruction_alloc_pool->malloc()) IR::Inst(op);
DEBUG_ASSERT(args.size() == inst->NumArgs());
std::for_each(args.begin(), args.end(), [&inst, op, index = size_t(0)](const auto& v) mutable {
assert(IR::GetArgTypeOf(op, index) == v->GetType());
DEBUG_ASSERT(IR::GetArgTypeOf(op, index) == v.GetType());
inst->SetArg(index, v);
index++;
});
AddToBlock(inst);
return inst;
}
IR::ValuePtr IREmitter::RegRef(Reg reg) {
auto regref = std::make_shared<IR::ImmRegRef>(reg);
AddToBlock(regref);
return regref;
}
void IREmitter::AddToBlock(IR::ValuePtr value) {
block.instructions.emplace_back(value);
block.instructions.push_back(*inst);
return IR::Value(inst);
}
} // namespace Arm

View file

@ -21,79 +21,77 @@ public:
LocationDescriptor current_location;
struct ResultAndCarry {
IR::ValuePtr result;
IR::ValuePtr carry;
IR::Value result;
IR::Value carry;
};
struct ResultAndCarryAndOverflow {
IR::ValuePtr result;
IR::ValuePtr carry;
IR::ValuePtr overflow;
IR::Value result;
IR::Value carry;
IR::Value overflow;
};
void Unimplemented();
u32 PC();
u32 AlignPC(size_t alignment);
IR::ValuePtr Imm1(bool value);
IR::ValuePtr Imm8(u8 value);
IR::ValuePtr Imm32(u32 value);
IR::Value Imm1(bool value);
IR::Value Imm8(u8 value);
IR::Value Imm32(u32 value);
IR::ValuePtr GetRegister(Reg source_reg);
void SetRegister(const Reg dest_reg, IR::ValuePtr value);
IR::Value GetRegister(Reg source_reg);
void SetRegister(const Reg dest_reg, const IR::Value& value);
void ALUWritePC(IR::ValuePtr value);
void BranchWritePC(IR::ValuePtr value);
void BXWritePC(IR::ValuePtr value);
void LoadWritePC(IR::ValuePtr value);
void CallSupervisor(IR::ValuePtr value);
void ALUWritePC(const IR::Value& value);
void BranchWritePC(const IR::Value& value);
void BXWritePC(const IR::Value& value);
void LoadWritePC(const IR::Value& value);
void CallSupervisor(const IR::Value& value);
IR::ValuePtr GetCFlag();
void SetNFlag(IR::ValuePtr value);
void SetZFlag(IR::ValuePtr value);
void SetCFlag(IR::ValuePtr value);
void SetVFlag(IR::ValuePtr value);
IR::Value GetCFlag();
void SetNFlag(const IR::Value& value);
void SetZFlag(const IR::Value& value);
void SetCFlag(const IR::Value& value);
void SetVFlag(const IR::Value& value);
IR::ValuePtr LeastSignificantHalf(IR::ValuePtr value);
IR::ValuePtr LeastSignificantByte(IR::ValuePtr value);
IR::ValuePtr MostSignificantBit(IR::ValuePtr value);
IR::ValuePtr IsZero(IR::ValuePtr value);
IR::Value LeastSignificantHalf(const IR::Value& value);
IR::Value LeastSignificantByte(const IR::Value& value);
IR::Value MostSignificantBit(const IR::Value& value);
IR::Value IsZero(const IR::Value& value);
ResultAndCarry LogicalShiftLeft(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarry LogicalShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarry ArithmeticShiftRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarry RotateRight(IR::ValuePtr value_in, IR::ValuePtr shift_amount, IR::ValuePtr carry_in);
ResultAndCarryAndOverflow AddWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in);
IR::ValuePtr Add(IR::ValuePtr a, IR::ValuePtr b);
ResultAndCarryAndOverflow SubWithCarry(IR::ValuePtr a, IR::ValuePtr b, IR::ValuePtr carry_in);
IR::ValuePtr Sub(IR::ValuePtr a, IR::ValuePtr b);
IR::ValuePtr And(IR::ValuePtr a, IR::ValuePtr b);
IR::ValuePtr Eor(IR::ValuePtr a, IR::ValuePtr b);
IR::ValuePtr Or(IR::ValuePtr a, IR::ValuePtr b);
IR::ValuePtr Not(IR::ValuePtr a);
IR::ValuePtr SignExtendHalfToWord(IR::ValuePtr a);
IR::ValuePtr SignExtendByteToWord(IR::ValuePtr a);
IR::ValuePtr ZeroExtendHalfToWord(IR::ValuePtr a);
IR::ValuePtr ZeroExtendByteToWord(IR::ValuePtr a);
IR::ValuePtr ByteReverseWord(IR::ValuePtr a);
IR::ValuePtr ByteReverseHalf(IR::ValuePtr a);
IR::ValuePtr ByteReverseDual(IR::ValuePtr a);
ResultAndCarry LogicalShiftLeft(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in);
ResultAndCarry LogicalShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in);
ResultAndCarry ArithmeticShiftRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in);
ResultAndCarry RotateRight(const IR::Value& value_in, const IR::Value& shift_amount, const IR::Value& carry_in);
ResultAndCarryAndOverflow AddWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in);
IR::Value Add(const IR::Value& a, const IR::Value& b);
ResultAndCarryAndOverflow SubWithCarry(const IR::Value& a, const IR::Value& b, const IR::Value& carry_in);
IR::Value Sub(const IR::Value& a, const IR::Value& b);
IR::Value And(const IR::Value& a, const IR::Value& b);
IR::Value Eor(const IR::Value& a, const IR::Value& b);
IR::Value Or(const IR::Value& a, const IR::Value& b);
IR::Value Not(const IR::Value& a);
IR::Value SignExtendHalfToWord(const IR::Value& a);
IR::Value SignExtendByteToWord(const IR::Value& a);
IR::Value ZeroExtendHalfToWord(const IR::Value& a);
IR::Value ZeroExtendByteToWord(const IR::Value& a);
IR::Value ByteReverseWord(const IR::Value& a);
IR::Value ByteReverseHalf(const IR::Value& a);
IR::Value ByteReverseDual(const IR::Value& a);
IR::ValuePtr ReadMemory8(IR::ValuePtr vaddr);
IR::ValuePtr ReadMemory16(IR::ValuePtr vaddr);
IR::ValuePtr ReadMemory32(IR::ValuePtr vaddr);
IR::ValuePtr ReadMemory64(IR::ValuePtr vaddr);
void WriteMemory8(IR::ValuePtr vaddr, IR::ValuePtr value);
void WriteMemory16(IR::ValuePtr vaddr, IR::ValuePtr value);
void WriteMemory32(IR::ValuePtr vaddr, IR::ValuePtr value);
void WriteMemory64(IR::ValuePtr vaddr, IR::ValuePtr value);
IR::Value ReadMemory8(const IR::Value& vaddr);
IR::Value ReadMemory16(const IR::Value& vaddr);
IR::Value ReadMemory32(const IR::Value& vaddr);
IR::Value ReadMemory64(const IR::Value& vaddr);
void WriteMemory8(const IR::Value& vaddr, const IR::Value& value);
void WriteMemory16(const IR::Value& vaddr, const IR::Value& value);
void WriteMemory32(const IR::Value& vaddr, const IR::Value& value);
void WriteMemory64(const IR::Value& vaddr, const IR::Value& value);
void SetTerm(const IR::Terminal& terminal);
private:
IR::ValuePtr Inst(IR::Opcode op, std::initializer_list<IR::ValuePtr> args);
IR::ValuePtr RegRef(Reg reg);
void AddToBlock(IR::ValuePtr value);
IR::Value Inst(IR::Opcode op, std::initializer_list<IR::Value> args);
};
} // namespace Arm

View file

@ -1,11 +1,5 @@
// opcode name, return type, arg1 type, arg2 type, arg3 type, ...
// Immediate values
OPCODE(ImmU1, T::U1, )
OPCODE(ImmU8, T::U8, )
OPCODE(ImmU32, T::U32, )
OPCODE(ImmRegRef, T::RegRef, )
// ARM Context getters/setters
OPCODE(GetRegister, T::U32, T::RegRef )
OPCODE(SetRegister, T::Void, T::RegRef, T::U32 )

View file

@ -340,7 +340,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor
visitor.ir.block.cond_failed = { visitor.ir.current_location };
}
return visitor.ir.block;
return std::move(visitor.ir.block);
}
} // namespace Arm

View file

@ -888,7 +888,7 @@ IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType mem
visitor.ir.block.cycle_count++;
}
return visitor.ir.block;
return std::move(visitor.ir.block);
}
} // namespace Arm