Alloy now builds on clang.
Hopefully not just bouncing back to MSVC failures…
This commit is contained in:
parent
4cbd267a52
commit
19b6e90b63
|
@ -183,33 +183,37 @@ protected:
|
||||||
|
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct I8 : ValueOp<I8<TAG>, KEY_TYPE_V_I8, Reg8, int8_t, TAG> {
|
struct I8 : ValueOp<I8<TAG>, KEY_TYPE_V_I8, Reg8, int8_t, TAG> {
|
||||||
|
typedef ValueOp<I8<TAG>, KEY_TYPE_V_I8, Reg8, int8_t, TAG> BASE;
|
||||||
const int8_t constant() const {
|
const int8_t constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.i8;
|
return BASE::value->constant.i8;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct I16 : ValueOp<I16<TAG>, KEY_TYPE_V_I16, Reg16, int16_t, TAG> {
|
struct I16 : ValueOp<I16<TAG>, KEY_TYPE_V_I16, Reg16, int16_t, TAG> {
|
||||||
|
typedef ValueOp<I16<TAG>, KEY_TYPE_V_I16, Reg16, int16_t, TAG> BASE;
|
||||||
const int16_t constant() const {
|
const int16_t constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.i16;
|
return BASE::value->constant.i16;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct I32 : ValueOp<I32<TAG>, KEY_TYPE_V_I32, Reg32, int32_t, TAG> {
|
struct I32 : ValueOp<I32<TAG>, KEY_TYPE_V_I32, Reg32, int32_t, TAG> {
|
||||||
|
typedef ValueOp<I32<TAG>, KEY_TYPE_V_I32, Reg32, int32_t, TAG> BASE;
|
||||||
const int32_t constant() const {
|
const int32_t constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.i32;
|
return BASE::value->constant.i32;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct I64 : ValueOp<I64<TAG>, KEY_TYPE_V_I64, Reg64, int64_t, TAG> {
|
struct I64 : ValueOp<I64<TAG>, KEY_TYPE_V_I64, Reg64, int64_t, TAG> {
|
||||||
|
typedef ValueOp<I64<TAG>, KEY_TYPE_V_I64, Reg64, int64_t, TAG> BASE;
|
||||||
const int64_t constant() const {
|
const int64_t constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.i64;
|
return BASE::value->constant.i64;
|
||||||
}
|
}
|
||||||
bool ConstantFitsIn32Reg() const override {
|
bool ConstantFitsIn32Reg() const override {
|
||||||
int64_t v = value->constant.i64;
|
int64_t v = BASE::value->constant.i64;
|
||||||
if ((v & ~0x7FFFFFFF) == 0) {
|
if ((v & ~0x7FFFFFFF) == 0) {
|
||||||
// Fits under 31 bits, so just load using normal mov.
|
// Fits under 31 bits, so just load using normal mov.
|
||||||
return true;
|
return true;
|
||||||
|
@ -222,23 +226,26 @@ struct I64 : ValueOp<I64<TAG>, KEY_TYPE_V_I64, Reg64, int64_t, TAG> {
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct F32 : ValueOp<F32<TAG>, KEY_TYPE_V_F32, Xmm, float, TAG> {
|
struct F32 : ValueOp<F32<TAG>, KEY_TYPE_V_F32, Xmm, float, TAG> {
|
||||||
|
typedef ValueOp<F32<TAG>, KEY_TYPE_V_F32, Xmm, float, TAG> BASE;
|
||||||
const float constant() const {
|
const float constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.f32;
|
return BASE::value->constant.f32;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct F64 : ValueOp<F64<TAG>, KEY_TYPE_V_F64, Xmm, double, TAG> {
|
struct F64 : ValueOp<F64<TAG>, KEY_TYPE_V_F64, Xmm, double, TAG> {
|
||||||
|
typedef ValueOp<F64<TAG>, KEY_TYPE_V_F64, Xmm, double, TAG> BASE;
|
||||||
const double constant() const {
|
const double constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.f64;
|
return BASE::value->constant.f64;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
template <int TAG = -1>
|
template <int TAG = -1>
|
||||||
struct V128 : ValueOp<V128<TAG>, KEY_TYPE_V_V128, Xmm, vec128_t, TAG> {
|
struct V128 : ValueOp<V128<TAG>, KEY_TYPE_V_V128, Xmm, vec128_t, TAG> {
|
||||||
|
typedef ValueOp<V128<TAG>, KEY_TYPE_V_V128, Xmm, vec128_t, TAG> BASE;
|
||||||
const vec128_t& constant() const {
|
const vec128_t& constant() const {
|
||||||
assert_true(is_constant);
|
assert_true(BASE::is_constant);
|
||||||
return value->constant.v128;
|
return BASE::value->constant.v128;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -308,6 +315,7 @@ template <hir::Opcode OPCODE, typename... Ts>
|
||||||
struct I;
|
struct I;
|
||||||
template <hir::Opcode OPCODE, typename DEST>
|
template <hir::Opcode OPCODE, typename DEST>
|
||||||
struct I<OPCODE, DEST> : DestField<DEST> {
|
struct I<OPCODE, DEST> : DestField<DEST> {
|
||||||
|
typedef DestField<DEST> BASE;
|
||||||
static const hir::Opcode opcode = OPCODE;
|
static const hir::Opcode opcode = OPCODE;
|
||||||
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type>::value;
|
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type>::value;
|
||||||
static const KeyType dest_type = DEST::key_type;
|
static const KeyType dest_type = DEST::key_type;
|
||||||
|
@ -316,7 +324,7 @@ protected:
|
||||||
template <typename... Ti> friend struct SequenceFields;
|
template <typename... Ti> friend struct SequenceFields;
|
||||||
bool Load(const Instr* i, TagTable& tag_table) {
|
bool Load(const Instr* i, TagTable& tag_table) {
|
||||||
if (InstrKey(i).value == key &&
|
if (InstrKey(i).value == key &&
|
||||||
LoadDest(i, tag_table)) {
|
BASE::LoadDest(i, tag_table)) {
|
||||||
instr = i;
|
instr = i;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -325,6 +333,7 @@ protected:
|
||||||
};
|
};
|
||||||
template <hir::Opcode OPCODE, typename DEST, typename SRC1>
|
template <hir::Opcode OPCODE, typename DEST, typename SRC1>
|
||||||
struct I<OPCODE, DEST, SRC1> : DestField<DEST> {
|
struct I<OPCODE, DEST, SRC1> : DestField<DEST> {
|
||||||
|
typedef DestField<DEST> BASE;
|
||||||
static const hir::Opcode opcode = OPCODE;
|
static const hir::Opcode opcode = OPCODE;
|
||||||
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type>::value;
|
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type>::value;
|
||||||
static const KeyType dest_type = DEST::key_type;
|
static const KeyType dest_type = DEST::key_type;
|
||||||
|
@ -335,7 +344,7 @@ protected:
|
||||||
template <typename... Ti> friend struct SequenceFields;
|
template <typename... Ti> friend struct SequenceFields;
|
||||||
bool Load(const Instr* i, TagTable& tag_table) {
|
bool Load(const Instr* i, TagTable& tag_table) {
|
||||||
if (InstrKey(i).value == key &&
|
if (InstrKey(i).value == key &&
|
||||||
LoadDest(i, tag_table) &&
|
BASE::LoadDest(i, tag_table) &&
|
||||||
tag_table.CheckTag<SRC1>(i->src1)) {
|
tag_table.CheckTag<SRC1>(i->src1)) {
|
||||||
instr = i;
|
instr = i;
|
||||||
src1.Load(i->src1);
|
src1.Load(i->src1);
|
||||||
|
@ -346,6 +355,7 @@ protected:
|
||||||
};
|
};
|
||||||
template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2>
|
template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2>
|
||||||
struct I<OPCODE, DEST, SRC1, SRC2> : DestField<DEST> {
|
struct I<OPCODE, DEST, SRC1, SRC2> : DestField<DEST> {
|
||||||
|
typedef DestField<DEST> BASE;
|
||||||
static const hir::Opcode opcode = OPCODE;
|
static const hir::Opcode opcode = OPCODE;
|
||||||
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, SRC2::key_type>::value;
|
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, SRC2::key_type>::value;
|
||||||
static const KeyType dest_type = DEST::key_type;
|
static const KeyType dest_type = DEST::key_type;
|
||||||
|
@ -358,7 +368,7 @@ protected:
|
||||||
template <typename... Ti> friend struct SequenceFields;
|
template <typename... Ti> friend struct SequenceFields;
|
||||||
bool Load(const Instr* i, TagTable& tag_table) {
|
bool Load(const Instr* i, TagTable& tag_table) {
|
||||||
if (InstrKey(i).value == key &&
|
if (InstrKey(i).value == key &&
|
||||||
LoadDest(i, tag_table) &&
|
BASE::LoadDest(i, tag_table) &&
|
||||||
tag_table.CheckTag<SRC1>(i->src1) &&
|
tag_table.CheckTag<SRC1>(i->src1) &&
|
||||||
tag_table.CheckTag<SRC2>(i->src2)) {
|
tag_table.CheckTag<SRC2>(i->src2)) {
|
||||||
instr = i;
|
instr = i;
|
||||||
|
@ -371,6 +381,7 @@ protected:
|
||||||
};
|
};
|
||||||
template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2, typename SRC3>
|
template <hir::Opcode OPCODE, typename DEST, typename SRC1, typename SRC2, typename SRC3>
|
||||||
struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> {
|
struct I<OPCODE, DEST, SRC1, SRC2, SRC3> : DestField<DEST> {
|
||||||
|
typedef DestField<DEST> BASE;
|
||||||
static const hir::Opcode opcode = OPCODE;
|
static const hir::Opcode opcode = OPCODE;
|
||||||
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, SRC2::key_type, SRC3::key_type>::value;
|
static const uint32_t key = InstrKey::Construct<OPCODE, DEST::key_type, SRC1::key_type, SRC2::key_type, SRC3::key_type>::value;
|
||||||
static const KeyType dest_type = DEST::key_type;
|
static const KeyType dest_type = DEST::key_type;
|
||||||
|
@ -385,7 +396,7 @@ protected:
|
||||||
template <typename... Ti> friend struct SequenceFields;
|
template <typename... Ti> friend struct SequenceFields;
|
||||||
bool Load(const Instr* i, TagTable& tag_table) {
|
bool Load(const Instr* i, TagTable& tag_table) {
|
||||||
if (InstrKey(i).value == key &&
|
if (InstrKey(i).value == key &&
|
||||||
LoadDest(i, tag_table) &&
|
BASE::LoadDest(i, tag_table) &&
|
||||||
tag_table.CheckTag<SRC1>(i->src1) &&
|
tag_table.CheckTag<SRC1>(i->src1) &&
|
||||||
tag_table.CheckTag<SRC2>(i->src2) &&
|
tag_table.CheckTag<SRC2>(i->src2) &&
|
||||||
tag_table.CheckTag<SRC3>(i->src3)) {
|
tag_table.CheckTag<SRC3>(i->src3)) {
|
||||||
|
@ -404,7 +415,6 @@ struct SequenceFields;
|
||||||
template <typename I1>
|
template <typename I1>
|
||||||
struct SequenceFields<I1> {
|
struct SequenceFields<I1> {
|
||||||
I1 i1;
|
I1 i1;
|
||||||
typedef typename I1 I1Type;
|
|
||||||
protected:
|
protected:
|
||||||
template <typename SEQ, typename... Ti> friend struct Sequence;
|
template <typename SEQ, typename... Ti> friend struct Sequence;
|
||||||
bool Check(const Instr* i, TagTable& tag_table, const Instr** new_tail) {
|
bool Check(const Instr* i, TagTable& tag_table, const Instr** new_tail) {
|
||||||
|
@ -516,9 +526,10 @@ const Reg64 GetTempReg<Reg64>(X64Emitter& e) {
|
||||||
|
|
||||||
template <typename SEQ, typename T>
|
template <typename SEQ, typename T>
|
||||||
struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
|
typedef Sequence<SingleSequence<SEQ, T>, T> BASE;
|
||||||
typedef T EmitArgType;
|
typedef T EmitArgType;
|
||||||
static const uint32_t head_key = T::key;
|
static const uint32_t head_key = T::key;
|
||||||
static void Emit(X64Emitter& e, const EmitArgs& _) {
|
static void Emit(X64Emitter& e, const typename BASE::EmitArgs& _) {
|
||||||
SEQ::Emit(e, _.i1);
|
SEQ::Emit(e, _.i1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -547,7 +558,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src1.ConstantFitsIn32Reg()) {
|
if (i.src1.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src1.constant()));
|
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src1.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src1)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src1)::reg_type>(e);
|
||||||
e.mov(temp, i.src1.constant());
|
e.mov(temp, i.src1.constant());
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
}
|
}
|
||||||
|
@ -560,7 +571,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src2.ConstantFitsIn32Reg()) {
|
if (i.src2.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2.constant());
|
e.mov(temp, i.src2.constant());
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
}
|
}
|
||||||
|
@ -586,7 +597,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src1.is_constant) {
|
if (i.src1.is_constant) {
|
||||||
assert_true(!i.src2.is_constant);
|
assert_true(!i.src2.is_constant);
|
||||||
if (i.dest == i.src2) {
|
if (i.dest == i.src2) {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2);
|
e.mov(temp, i.src2);
|
||||||
e.mov(i.dest, i.src1.constant());
|
e.mov(i.dest, i.src1.constant());
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
|
@ -599,7 +610,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src2.ConstantFitsIn32Reg()) {
|
if (i.src2.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2.constant());
|
e.mov(temp, i.src2.constant());
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
}
|
}
|
||||||
|
@ -608,7 +619,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src2.ConstantFitsIn32Reg()) {
|
if (i.src2.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
reg_const_fn(e, i.dest, static_cast<int32_t>(i.src2.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2.constant());
|
e.mov(temp, i.src2.constant());
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
}
|
}
|
||||||
|
@ -617,7 +628,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.dest == i.src1) {
|
if (i.dest == i.src1) {
|
||||||
reg_reg_fn(e, i.dest, i.src2);
|
reg_reg_fn(e, i.dest, i.src2);
|
||||||
} else if (i.dest == i.src2) {
|
} else if (i.dest == i.src2) {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2);
|
e.mov(temp, i.src2);
|
||||||
e.mov(i.dest, i.src1);
|
e.mov(i.dest, i.src1);
|
||||||
reg_reg_fn(e, i.dest, temp);
|
reg_reg_fn(e, i.dest, temp);
|
||||||
|
@ -667,7 +678,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src1.ConstantFitsIn32Reg()) {
|
if (i.src1.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.src2, static_cast<int32_t>(i.src1.constant()));
|
reg_const_fn(e, i.src2, static_cast<int32_t>(i.src1.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src1)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src1)::reg_type>(e);
|
||||||
e.mov(temp, i.src1.constant());
|
e.mov(temp, i.src1.constant());
|
||||||
reg_reg_fn(e, i.src2, temp);
|
reg_reg_fn(e, i.src2, temp);
|
||||||
}
|
}
|
||||||
|
@ -675,7 +686,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src2.ConstantFitsIn32Reg()) {
|
if (i.src2.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.src1, static_cast<int32_t>(i.src2.constant()));
|
reg_const_fn(e, i.src1, static_cast<int32_t>(i.src2.constant()));
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2.constant());
|
e.mov(temp, i.src2.constant());
|
||||||
reg_reg_fn(e, i.src1, temp);
|
reg_reg_fn(e, i.src1, temp);
|
||||||
}
|
}
|
||||||
|
@ -692,7 +703,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src1.ConstantFitsIn32Reg()) {
|
if (i.src1.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, i.src2, static_cast<int32_t>(i.src1.constant()), true);
|
reg_const_fn(e, i.dest, i.src2, static_cast<int32_t>(i.src1.constant()), true);
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src1)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src1)::reg_type>(e);
|
||||||
e.mov(temp, i.src1.constant());
|
e.mov(temp, i.src1.constant());
|
||||||
reg_reg_fn(e, i.dest, i.src2, temp, true);
|
reg_reg_fn(e, i.dest, i.src2, temp, true);
|
||||||
}
|
}
|
||||||
|
@ -700,7 +711,7 @@ struct SingleSequence : public Sequence<SingleSequence<SEQ, T>, T> {
|
||||||
if (i.src2.ConstantFitsIn32Reg()) {
|
if (i.src2.ConstantFitsIn32Reg()) {
|
||||||
reg_const_fn(e, i.dest, i.src1, static_cast<int32_t>(i.src2.constant()), false);
|
reg_const_fn(e, i.dest, i.src1, static_cast<int32_t>(i.src2.constant()), false);
|
||||||
} else {
|
} else {
|
||||||
auto temp = GetTempReg<decltype(i.src2)::reg_type>(e);
|
auto temp = GetTempReg<typename decltype(i.src2)::reg_type>(e);
|
||||||
e.mov(temp, i.src2.constant());
|
e.mov(temp, i.src2.constant());
|
||||||
reg_reg_fn(e, i.dest, i.src1, temp, false);
|
reg_reg_fn(e, i.dest, i.src1, temp, false);
|
||||||
}
|
}
|
||||||
|
@ -721,8 +732,6 @@ static const tag_t TAG5 = 5;
|
||||||
static const tag_t TAG6 = 6;
|
static const tag_t TAG6 = 6;
|
||||||
static const tag_t TAG7 = 7;
|
static const tag_t TAG7 = 7;
|
||||||
|
|
||||||
typedef bool (*SequenceSelectFn)(X64Emitter&, const Instr*, const Instr**);
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Register() {
|
void Register() {
|
||||||
sequence_table.insert({ T::head_key, T::Select });
|
sequence_table.insert({ T::head_key, T::Select });
|
||||||
|
|
|
@ -39,11 +39,12 @@ using namespace Xbyak;
|
||||||
using namespace alloy::hir;
|
using namespace alloy::hir;
|
||||||
using namespace alloy::runtime;
|
using namespace alloy::runtime;
|
||||||
|
|
||||||
|
typedef bool (*SequenceSelectFn)(X64Emitter&, const Instr*, const Instr**);
|
||||||
|
std::unordered_multimap<uint32_t, SequenceSelectFn> sequence_table;
|
||||||
|
|
||||||
// Utilities/types used only in this file:
|
// Utilities/types used only in this file:
|
||||||
#include <alloy/backend/x64/x64_sequence.inl>
|
#include <alloy/backend/x64/x64_sequence.inl>
|
||||||
|
|
||||||
std::unordered_multimap<uint32_t, SequenceSelectFn> sequence_table;
|
|
||||||
|
|
||||||
// Selects the right byte/word/etc from a vector. We need to flip logical
|
// Selects the right byte/word/etc from a vector. We need to flip logical
|
||||||
// indices (0,1,2,3,4,5,6,7,...) = (3,2,1,0,7,6,5,4,...)
|
// indices (0,1,2,3,4,5,6,7,...) = (3,2,1,0,7,6,5,4,...)
|
||||||
#define VEC128_B(n) ((n) ^ 0x3)
|
#define VEC128_B(n) ((n) ^ 0x3)
|
||||||
|
@ -63,7 +64,7 @@ EMITTER(COMMENT, MATCH(I<OPCODE_COMMENT, VoidOp, OffsetOp>)) {
|
||||||
// TODO(benvanik): don't just leak this memory.
|
// TODO(benvanik): don't just leak this memory.
|
||||||
auto str_copy = strdup(str);
|
auto str_copy = strdup(str);
|
||||||
e.mov(e.rdx, reinterpret_cast<uint64_t>(str_copy));
|
e.mov(e.rdx, reinterpret_cast<uint64_t>(str_copy));
|
||||||
e.CallNative(TraceString);
|
e.CallNative(reinterpret_cast<void*>(TraceString));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1104,12 +1105,7 @@ EMITTER(LOAD_CLOCK, MATCH(I<OPCODE_LOAD_CLOCK, I64<>>)) {
|
||||||
e.mov(i.dest, e.rax);
|
e.mov(i.dest, e.rax);
|
||||||
}
|
}
|
||||||
static uint64_t LoadClock(void* raw_context) {
|
static uint64_t LoadClock(void* raw_context) {
|
||||||
LARGE_INTEGER counter;
|
return poly::threading::ticks();
|
||||||
uint64_t time = 0;
|
|
||||||
if (QueryPerformanceCounter(&counter)) {
|
|
||||||
time = counter.QuadPart;
|
|
||||||
}
|
|
||||||
return time;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EMITTER_OPCODE_TABLE(
|
EMITTER_OPCODE_TABLE(
|
||||||
|
@ -1245,7 +1241,7 @@ EMITTER(LOAD_CONTEXT_I8, MATCH(I<OPCODE_LOAD_CONTEXT, I8<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.byte[addr]);
|
e.mov(e.r8, e.byte[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadI8);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadI8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1256,7 +1252,7 @@ EMITTER(LOAD_CONTEXT_I16, MATCH(I<OPCODE_LOAD_CONTEXT, I16<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.word[addr]);
|
e.mov(e.r8, e.word[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadI16);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadI16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1267,7 +1263,7 @@ EMITTER(LOAD_CONTEXT_I32, MATCH(I<OPCODE_LOAD_CONTEXT, I32<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.dword[addr]);
|
e.mov(e.r8, e.dword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadI32);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadI32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1278,7 +1274,7 @@ EMITTER(LOAD_CONTEXT_I64, MATCH(I<OPCODE_LOAD_CONTEXT, I64<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.qword[addr]);
|
e.mov(e.r8, e.qword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadI64);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadI64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1289,7 +1285,7 @@ EMITTER(LOAD_CONTEXT_F32, MATCH(I<OPCODE_LOAD_CONTEXT, F32<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.dword[addr]);
|
e.lea(e.r8, e.dword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadF32);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadF32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1300,7 +1296,7 @@ EMITTER(LOAD_CONTEXT_F64, MATCH(I<OPCODE_LOAD_CONTEXT, F64<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.qword[addr]);
|
e.lea(e.r8, e.qword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadF64);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadF64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1311,7 +1307,7 @@ EMITTER(LOAD_CONTEXT_V128, MATCH(I<OPCODE_LOAD_CONTEXT, V128<>, OffsetOp>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextLoadV128);
|
e.CallNative(reinterpret_cast<void*>(TraceContextLoadV128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1341,7 +1337,7 @@ EMITTER(STORE_CONTEXT_I8, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, I8<>>)
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.byte[addr]);
|
e.mov(e.r8, e.byte[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreI8);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreI8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1356,7 +1352,7 @@ EMITTER(STORE_CONTEXT_I16, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, I16<>
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.word[addr]);
|
e.mov(e.r8, e.word[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreI16);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreI16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1371,7 +1367,7 @@ EMITTER(STORE_CONTEXT_I32, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, I32<>
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.dword[addr]);
|
e.mov(e.r8, e.dword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreI32);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreI32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1386,7 +1382,7 @@ EMITTER(STORE_CONTEXT_I64, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, I64<>
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, e.qword[addr]);
|
e.mov(e.r8, e.qword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreI64);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreI64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1401,7 +1397,7 @@ EMITTER(STORE_CONTEXT_F32, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, F32<>
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.dword[addr]);
|
e.lea(e.r8, e.dword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreF32);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreF32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1416,7 +1412,7 @@ EMITTER(STORE_CONTEXT_F64, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, F64<>
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.qword[addr]);
|
e.lea(e.r8, e.qword[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreF64);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreF64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1432,7 +1428,7 @@ EMITTER(STORE_CONTEXT_V128, MATCH(I<OPCODE_STORE_CONTEXT, VoidOp, OffsetOp, V128
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.mov(e.rdx, i.src1.value);
|
e.mov(e.rdx, i.src1.value);
|
||||||
e.CallNative(TraceContextStoreV128);
|
e.CallNative(reinterpret_cast<void*>(TraceContextStoreV128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1473,7 +1469,7 @@ EMITTER(LOAD_I8, MATCH(I<OPCODE_LOAD, I8<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8b, i.dest);
|
e.mov(e.r8b, i.dest);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadI8);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadI8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1484,7 +1480,7 @@ EMITTER(LOAD_I16, MATCH(I<OPCODE_LOAD, I16<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8w, i.dest);
|
e.mov(e.r8w, i.dest);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadI16);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadI16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1495,7 +1491,7 @@ EMITTER(LOAD_I32, MATCH(I<OPCODE_LOAD, I32<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8d, i.dest);
|
e.mov(e.r8d, i.dest);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadI32);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadI32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1506,7 +1502,7 @@ EMITTER(LOAD_I64, MATCH(I<OPCODE_LOAD, I64<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.mov(e.r8, i.dest);
|
e.mov(e.r8, i.dest);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadI64);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadI64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1517,7 +1513,7 @@ EMITTER(LOAD_F32, MATCH(I<OPCODE_LOAD, F32<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.dword[addr]);
|
e.lea(e.r8, e.dword[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadF32);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadF32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1528,7 +1524,7 @@ EMITTER(LOAD_F64, MATCH(I<OPCODE_LOAD, F64<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.qword[addr]);
|
e.lea(e.r8, e.qword[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadF64);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadF64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1540,7 +1536,7 @@ EMITTER(LOAD_V128, MATCH(I<OPCODE_LOAD, V128<>, I64<>>)) {
|
||||||
if (IsTracingData()) {
|
if (IsTracingData()) {
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryLoadV128);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryLoadV128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1578,7 +1574,7 @@ EMITTER(STORE_I8, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I8<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.mov(e.r8b, e.byte[addr]);
|
e.mov(e.r8b, e.byte[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreI8);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreI8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1595,7 +1591,7 @@ EMITTER(STORE_I16, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I16<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.mov(e.r8w, e.word[addr]);
|
e.mov(e.r8w, e.word[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreI16);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreI16));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1612,7 +1608,7 @@ EMITTER(STORE_I32, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I32<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.mov(e.r8d, e.dword[addr]);
|
e.mov(e.r8d, e.dword[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreI32);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreI32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1629,7 +1625,7 @@ EMITTER(STORE_I64, MATCH(I<OPCODE_STORE, VoidOp, I64<>, I64<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.mov(e.r8, e.qword[addr]);
|
e.mov(e.r8, e.qword[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreI64);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreI64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1646,7 +1642,7 @@ EMITTER(STORE_F32, MATCH(I<OPCODE_STORE, VoidOp, I64<>, F32<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreF32);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreF32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1663,7 +1659,7 @@ EMITTER(STORE_F64, MATCH(I<OPCODE_STORE, VoidOp, I64<>, F64<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreF64);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreF64));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1681,7 +1677,7 @@ EMITTER(STORE_V128, MATCH(I<OPCODE_STORE, VoidOp, I64<>, V128<>>)) {
|
||||||
auto addr = ComputeMemoryAddress(e, i.src1);
|
auto addr = ComputeMemoryAddress(e, i.src1);
|
||||||
e.lea(e.r8, e.ptr[addr]);
|
e.lea(e.r8, e.ptr[addr]);
|
||||||
e.lea(e.rdx, e.ptr[addr]);
|
e.lea(e.rdx, e.ptr[addr]);
|
||||||
e.CallNative(TraceMemoryStoreV128);
|
e.CallNative(reinterpret_cast<void*>(TraceMemoryStoreV128));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2099,7 +2095,7 @@ EMITTER_OPCODE_TABLE(
|
||||||
// OPCODE_COMPARE_*
|
// OPCODE_COMPARE_*
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
#define EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, type, reg_type) \
|
#define EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, type, reg_type) \
|
||||||
EMITTER(COMPARE_##op##_##type, MATCH(I<OPCODE_COMPARE_##op##, I8<>, type<>, type<>>)) { \
|
EMITTER(COMPARE_##op##_##type, MATCH(I<OPCODE_COMPARE_##op, I8<>, type<>, type<>>)) { \
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
||||||
EmitAssociativeCompareOp( \
|
EmitAssociativeCompareOp( \
|
||||||
e, i, \
|
e, i, \
|
||||||
|
@ -2119,7 +2115,7 @@ EMITTER_OPCODE_TABLE(
|
||||||
EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, I32, Reg32); \
|
EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, I32, Reg32); \
|
||||||
EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, I64, Reg64); \
|
EMITTER_ASSOCIATIVE_COMPARE_INT(op, instr, inverse_instr, I64, Reg64); \
|
||||||
EMITTER_OPCODE_TABLE( \
|
EMITTER_OPCODE_TABLE( \
|
||||||
OPCODE_COMPARE_##op##, \
|
OPCODE_COMPARE_##op, \
|
||||||
COMPARE_##op##_I8, \
|
COMPARE_##op##_I8, \
|
||||||
COMPARE_##op##_I16, \
|
COMPARE_##op##_I16, \
|
||||||
COMPARE_##op##_I32, \
|
COMPARE_##op##_I32, \
|
||||||
|
@ -2135,13 +2131,13 @@ EMITTER_ASSOCIATIVE_COMPARE_XX(UGE, setae, setb);
|
||||||
|
|
||||||
// http://x86.renejeschke.de/html/file_module_x86_id_288.html
|
// http://x86.renejeschke.de/html/file_module_x86_id_288.html
|
||||||
#define EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(op, instr) \
|
#define EMITTER_ASSOCIATIVE_COMPARE_FLT_XX(op, instr) \
|
||||||
EMITTER(COMPARE_##op##_F32, MATCH(I<OPCODE_COMPARE_##op##, I8<>, F32<>, F32<>>)) { \
|
EMITTER(COMPARE_##op##_F32, MATCH(I<OPCODE_COMPARE_##op, I8<>, F32<>, F32<>>)) { \
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
||||||
e.vcomiss(i.src1, i.src2); \
|
e.vcomiss(i.src1, i.src2); \
|
||||||
e.instr(i.dest); \
|
e.instr(i.dest); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
EMITTER(COMPARE_##op##_F64, MATCH(I<OPCODE_COMPARE_##op##, I8<>, F64<>, F64<>>)) { \
|
EMITTER(COMPARE_##op##_F64, MATCH(I<OPCODE_COMPARE_##op, I8<>, F64<>, F64<>>)) { \
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
static void Emit(X64Emitter& e, const EmitArgType& i) { \
|
||||||
if (i.src1.is_constant) { \
|
if (i.src1.is_constant) { \
|
||||||
e.LoadConstantXmm(e.xmm0, i.src1.constant()); \
|
e.LoadConstantXmm(e.xmm0, i.src1.constant()); \
|
||||||
|
@ -3479,39 +3475,44 @@ EMITTER_OPCODE_TABLE(
|
||||||
// http://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html
|
// http://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html
|
||||||
EMITTER(POW2_F32, MATCH(I<OPCODE_POW2, F32<>, F32<>>)) {
|
EMITTER(POW2_F32, MATCH(I<OPCODE_POW2, F32<>, F32<>>)) {
|
||||||
static __m128 EmulatePow2(__m128 src) {
|
static __m128 EmulatePow2(__m128 src) {
|
||||||
float result = static_cast<float>(pow(2, src.m128_f32[0]));
|
float src_value;
|
||||||
|
_mm_store_ss(&src_value, src);
|
||||||
|
float result = std::pow(2, src_value);
|
||||||
return _mm_load_ss(&result);
|
return _mm_load_ss(&result);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
assert_always();
|
assert_always();
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulatePow2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulatePow2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EMITTER(POW2_F64, MATCH(I<OPCODE_POW2, F64<>, F64<>>)) {
|
EMITTER(POW2_F64, MATCH(I<OPCODE_POW2, F64<>, F64<>>)) {
|
||||||
static __m128d EmulatePow2(__m128 src) {
|
static __m128d EmulatePow2(__m128 src) {
|
||||||
double result = pow(2, src.m128_f32[0]);
|
double src_value;
|
||||||
|
_mm_store_sd(&src_value, src);
|
||||||
|
double result = std::pow(2, src_value);
|
||||||
return _mm_load_sd(&result);
|
return _mm_load_sd(&result);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
assert_always();
|
assert_always();
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulatePow2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulatePow2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EMITTER(POW2_V128, MATCH(I<OPCODE_POW2, V128<>, V128<>>)) {
|
EMITTER(POW2_V128, MATCH(I<OPCODE_POW2, V128<>, V128<>>)) {
|
||||||
static __m128 EmulatePow2(__m128 src) {
|
static __m128 EmulatePow2(__m128 src) {
|
||||||
__m128 result;
|
alignas(16) float values[4];
|
||||||
|
_mm_store_ps(values, src);
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
result.m128_f32[i] = static_cast<float>(pow(2, src.m128_f32[i]));
|
values[i] = std::pow(2, values[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return _mm_load_ps(values);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulatePow2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulatePow2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3530,39 +3531,44 @@ EMITTER_OPCODE_TABLE(
|
||||||
// TODO(benvanik): this emulated fn destroys all xmm registers! don't do it!
|
// TODO(benvanik): this emulated fn destroys all xmm registers! don't do it!
|
||||||
EMITTER(LOG2_F32, MATCH(I<OPCODE_LOG2, F32<>, F32<>>)) {
|
EMITTER(LOG2_F32, MATCH(I<OPCODE_LOG2, F32<>, F32<>>)) {
|
||||||
static __m128 EmulateLog2(__m128 src) {
|
static __m128 EmulateLog2(__m128 src) {
|
||||||
float result = log2(src.m128_f32[0]);
|
float src_value;
|
||||||
|
_mm_store_ss(&src_value, src);
|
||||||
|
float result = std::log2(src_value);
|
||||||
return _mm_load_ss(&result);
|
return _mm_load_ss(&result);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
assert_always();
|
assert_always();
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulateLog2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulateLog2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EMITTER(LOG2_F64, MATCH(I<OPCODE_LOG2, F64<>, F64<>>)) {
|
EMITTER(LOG2_F64, MATCH(I<OPCODE_LOG2, F64<>, F64<>>)) {
|
||||||
static __m128d EmulateLog2(__m128d src) {
|
static __m128d EmulateLog2(__m128d src) {
|
||||||
double result = log2(src.m128d_f64[0]);
|
double src_value;
|
||||||
|
_mm_store_sd(&src_value, src);
|
||||||
|
double result = std::log2(src_value);
|
||||||
return _mm_load_sd(&result);
|
return _mm_load_sd(&result);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
assert_always();
|
assert_always();
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulateLog2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulateLog2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
EMITTER(LOG2_V128, MATCH(I<OPCODE_LOG2, V128<>, V128<>>)) {
|
EMITTER(LOG2_V128, MATCH(I<OPCODE_LOG2, V128<>, V128<>>)) {
|
||||||
static __m128 EmulateLog2(__m128 src) {
|
static __m128 EmulateLog2(__m128 src) {
|
||||||
__m128 result;
|
alignas(16) float values[4];
|
||||||
|
_mm_store_ps(values, src);
|
||||||
for (size_t i = 0; i < 4; ++i) {
|
for (size_t i = 0; i < 4; ++i) {
|
||||||
result.m128_f32[i] = log2(src.m128_f32[i]);
|
values[i] = std::log2(values[i]);
|
||||||
}
|
}
|
||||||
return result;
|
return _mm_load_ps(values);
|
||||||
}
|
}
|
||||||
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
static void Emit(X64Emitter& e, const EmitArgType& i) {
|
||||||
e.lea(e.r8, e.StashXmm(i.src1));
|
e.lea(e.r8, e.StashXmm(i.src1));
|
||||||
e.CallNativeSafe(EmulateLog2);
|
e.CallNativeSafe(reinterpret_cast<void*>(EmulateLog2));
|
||||||
e.vmovaps(i.dest, e.xmm0);
|
e.vmovaps(i.dest, e.xmm0);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -4996,7 +5002,7 @@ EMITTER_OPCODE_TABLE(
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void alloy::backend::x64::RegisterSequences() {
|
void RegisterSequences() {
|
||||||
#define REGISTER_EMITTER_OPCODE_TABLE(opcode) Register_##opcode()
|
#define REGISTER_EMITTER_OPCODE_TABLE(opcode) Register_##opcode()
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMMENT);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_COMMENT);
|
||||||
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_NOP);
|
REGISTER_EMITTER_OPCODE_TABLE(OPCODE_NOP);
|
||||||
|
@ -5109,7 +5115,7 @@ void alloy::backend::x64::RegisterSequences() {
|
||||||
//REGISTER_EMITTER_OPCODE_TABLE(OPCODE_ATOMIC_SUB);
|
//REGISTER_EMITTER_OPCODE_TABLE(OPCODE_ATOMIC_SUB);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool alloy::backend::x64::SelectSequence(X64Emitter& e, const Instr* i, const Instr** new_tail) {
|
bool SelectSequence(X64Emitter& e, const Instr* i, const Instr** new_tail) {
|
||||||
const InstrKey key(i);
|
const InstrKey key(i);
|
||||||
const auto its = sequence_table.equal_range(key);
|
const auto its = sequence_table.equal_range(key);
|
||||||
for (auto it = its.first; it != its.second; ++it) {
|
for (auto it = its.first; it != its.second; ++it) {
|
||||||
|
|
|
@ -43,7 +43,7 @@ void ValueReductionPass::ComputeLastUse(Value* value) {
|
||||||
// Note that this list isn't sorted (unfortunately), so we have to scan
|
// Note that this list isn't sorted (unfortunately), so we have to scan
|
||||||
// them all.
|
// them all.
|
||||||
uint32_t max_ordinal = 0;
|
uint32_t max_ordinal = 0;
|
||||||
Value::Use* last_use = NULL;
|
Value::Use* last_use = nullptr;
|
||||||
auto use = value->use_head;
|
auto use = value->use_head;
|
||||||
while (use) {
|
while (use) {
|
||||||
if (!last_use || use->instr->ordinal >= max_ordinal) {
|
if (!last_use || use->instr->ordinal >= max_ordinal) {
|
||||||
|
@ -52,7 +52,7 @@ void ValueReductionPass::ComputeLastUse(Value* value) {
|
||||||
}
|
}
|
||||||
use = use->next;
|
use = use->next;
|
||||||
}
|
}
|
||||||
value->last_use = last_use->instr;
|
value->last_use = last_use ? last_use->instr : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ValueReductionPass::Run(HIRBuilder* builder) {
|
int ValueReductionPass::Run(HIRBuilder* builder) {
|
||||||
|
|
|
@ -248,6 +248,9 @@ void Disasm_dcbf(InstrData& i, StringBuffer* str) {
|
||||||
case 3:
|
case 3:
|
||||||
name = "dcbflp";
|
name = "dcbflp";
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
name = "dcbf.??";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
str->Append("%-8s r%d, r%d", name, i.X.RA, i.X.RB);
|
str->Append("%-8s r%d, r%d", name, i.X.RA, i.X.RB);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,7 @@ enum TypeName {
|
||||||
MAX_TYPENAME,
|
MAX_TYPENAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
static size_t GetTypeSize(TypeName type_name) {
|
inline size_t GetTypeSize(TypeName type_name) {
|
||||||
switch (type_name) {
|
switch (type_name) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -23,6 +23,13 @@
|
||||||
#define thread_local __thread
|
#define thread_local __thread
|
||||||
#endif // XE_COMPILER_MSVC
|
#endif // XE_COMPILER_MSVC
|
||||||
|
|
||||||
|
// C++11 alignas keyword.
|
||||||
|
// This will hopefully be coming soon, as most of the alignment spec is in the
|
||||||
|
// latest CTP.
|
||||||
|
#if XE_COMPILER_MSVC
|
||||||
|
#define alignas(N) __declspec(align(N))
|
||||||
|
#endif // XE_COMPILER_MSVC
|
||||||
|
|
||||||
namespace poly {} // namespace poly
|
namespace poly {} // namespace poly
|
||||||
|
|
||||||
#endif // POLY_CXX_COMPAT_H_
|
#endif // POLY_CXX_COMPAT_H_
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
namespace poly {
|
namespace poly {
|
||||||
namespace threading {
|
namespace threading {
|
||||||
|
|
||||||
// Gets the current high-perforance tick count.
|
// Gets the current high-performance tick count.
|
||||||
uint64_t ticks();
|
uint64_t ticks();
|
||||||
|
|
||||||
// Gets a stable thread-specific ID, but may not be. Use for informative
|
// Gets a stable thread-specific ID, but may not be. Use for informative
|
||||||
|
|
Loading…
Reference in New Issue