/** ****************************************************************************** * Xenia : Xbox 360 Emulator Research Project * ****************************************************************************** * Copyright 2013 Ben Vanik. All rights reserved. * * Released under the BSD license - see LICENSE in the root for more details. * ****************************************************************************** */ #include #include #include using namespace alloy; using namespace alloy::backend::x64; using namespace alloy::backend::x64::lir; using namespace alloy::backend::x64::lowering; using namespace alloy::hir; using namespace std; namespace { enum ArgType { NULL_ARG_TYPE, VALUE_ARG_TYPE, CONSTANT_ARG_TYPE, OUT_ARG_TYPE, IN_ARG_TYPE, REG_ARG_TYPE, }; template class Arg { public: const static ArgType arg_type = ARG_TYPE; }; class NullArg : public Arg {}; template class ValueRef : public Arg { public: enum { type = TYPE }; }; template // vec class Constant : public Arg { public: enum { type = TYPE }; enum : bool { has_value = HAS_VALUE }; const static int8_t i8 = INT8_VALUE; const static int16_t i16 = INT16_VALUE; const static int32_t i32 = INT32_VALUE; const static int64_t i64 = INT64_VALUE; const static intmax_t f32_num = FLOAT32_NUM_VALUE; const static intmax_t f32_den = FLOAT32_DEN_VALUE; const static intmax_t f64_num = FLOAT64_NUM_VALUE; const static intmax_t f64_den = FLOAT64_DEN_VALUE; // vec }; template class Int8Constant : public Constant {}; template class Int16Constant : public Constant {}; template class Int32Constant : public Constant {}; template class Int64Constant : public Constant {}; template class Float32Constant : public Constant {}; template class Float64Constant : public Constant {}; // vec template class Out : public Arg { public: enum { slot = SLOT }; }; template class In : public Arg { public: enum { slot = SLOT }; enum { arg = ARG }; }; template class Reg : public Arg { public: enum { reg_name = REG_NAME }; }; class Matcher { public: template struct IntType { static const int value = v; }; template static bool CheckArg(Instr* instr_list[], Instr::Op& op, IntType) { return true; } template static bool CheckArg(Instr* instr_list[], Instr::Op& op, IntType) { return op.value->type == T::type; } template static bool CheckArg(Instr* instr_list[], Instr::Op& op, IntType) { if (op.value->type != T::type) { return false; } if (!T::has_value) { return true; } switch (T::type) { case INT8_TYPE: return op.value->constant.i8 == T::i8; case INT16_TYPE: return op.value->constant.i16 == T::i16; case INT32_TYPE: return op.value->constant.i32 == T::i32; case INT64_TYPE: return op.value->constant.i64 == T::i64; case FLOAT32_TYPE: return op.value->constant.f32 == (T::f32_num / T::f32_den); case FLOAT64_TYPE: return op.value->constant.f64 == (T::f64_num / T::f64_den); // vec } return false; } template static bool CheckArg(Instr* instr_list[], Instr::Op& op, IntType) { Instr* instr = instr_list[T::slot]; return op.value == instr->dest; } template static bool CheckArg(Instr* instr_list[], Instr::Op& op, IntType) { Instr* instr = instr_list[T::slot]; switch (T::arg) { case 0: return op.value == instr->src1.value; case 1: return op.value == instr->src2.value; case 2: return op.value == instr->src3.value; } return false; } template static bool CheckDest(Instr* instr_list[], Value* value, IntType) { return true; } template static bool CheckDest(Instr* instr_list[], Value* value, IntType) { return value->type == T::type; } template static bool CheckDest(Instr* instr_list[], Value* value, IntType) { Instr* instr = instr_list[T::slot]; return value == instr->dest; } template static bool CheckDest(Instr* instr_list[], Value* value, IntType) { Instr* instr = instr_list[T::slot]; switch (T::arg) { case 0: return value == instr->src1.value; case 1: return value == instr->src2.value; case 2: return value == instr->src3.value; } return false; } template static typename std::enable_if::value, void>::type Match(Instr* instr_list[], int& instr_offset, Instr*&, bool&) { } template static typename std::enable_if::value, void>::type Match(Instr* instr_list[], int& instr_offset, Instr*& instr, bool& matched) { instr_list[instr_offset++] = instr; typedef std::tuple_element::type T; if (instr->opcode->num != T::opcode) { matched = false; return; } // Matches opcode, check args. if (!std::is_same::value) { if (!CheckDest(instr_list, instr->dest, IntType())) { matched = false; return; } } if (!std::is_same::value) { if (!CheckArg(instr_list, instr->src1, IntType())) { matched = false; return; } } if (!std::is_same::value) { if (!CheckArg(instr_list, instr->src2, IntType())) { matched = false; return; } } if (!std::is_same::value) { if (!CheckArg(instr_list, instr->src3, IntType())) { matched = false; return; } } instr = instr->next; Match(instr_list, instr_offset, instr, matched); } template static bool Matches(Instr* instr_list[], int& instr_offset, Instr*& instr) { bool matched = true; Instr* orig_instr = instr; Match<0, HIRS>(instr_list, instr_offset, instr, matched); if (!matched) { instr = orig_instr; } return matched; } }; class Emitter { public: template static typename std::enable_if::value, void>::type EmitInstr(LIRBuilder* builder, Instr*[]) { } template static typename std::enable_if::value, void>::type EmitInstr(LIRBuilder* builder, Instr* instr_list[]) { typedef std::tuple_element::type T; //LIRInstr* lir_instr = builder->AppendInstr(T::opcode); if (!std::is_same::value) { // lir_instr->dest = ... } if (!std::is_same::value) { // } if (!std::is_same::value) { // } if (!std::is_same::value) { // } EmitInstr(builder, instr_list); } template static void Emit(LIRBuilder* builder, Instr* instr_list[]) { EmitInstr<0, LIRS>(builder, instr_list); } }; template void Translate(LoweringTable* table) { auto exec = [](LIRBuilder* builder, Instr*& instr) { Instr* instr_list[32] = { 0 }; int instr_offset = 0; if (Matcher::Matches(instr_list, instr_offset, instr)) { Emitter::Emit(builder, instr_list); return true; } return false; }; auto new_fn = new LoweringTable::TypedFnWrapper(exec); table->AddSequence(std::tuple_element<0, MATCH>::type::opcode, new_fn); } } // namespace namespace { template class HIR_OPCODE { public: static const Opcode opcode = OPCODE; static const OpcodeSignature signature = SIGNATURE; static const int flags = FLAGS; typedef DEST dest; typedef ARG0 arg0; typedef ARG1 arg1; typedef ARG2 arg2; }; #define DEFINE_OPCODE(num, name, sig, flags) \ template \ class BASE_HIR_##num : public HIR_OPCODE{}; #include #undef DEFINE_OPCODE #define DEFINE_OPCODE_V_O(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_V_O_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_V_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_V_V_O(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_V_V_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_V_V_V_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name<> {} #define DEFINE_OPCODE_X_L(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_O(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_S(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_V_L(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_V_O(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_V_S(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #define DEFINE_OPCODE_X_V_V(name) \ template \ class HIR_##name : public BASE_HIR_OPCODE_##name {} #include } namespace { template class LIR_OPCODE { public: static const LIROpcode opcode = OPCODE; static const LIROpcodeSignature signature = SIGNATURE; static const int flags = FLAGS; typedef DEST dest; typedef ARG0 arg0; typedef ARG1 arg1; typedef ARG2 arg2; }; #define DEFINE_OPCODE(num, name, sig, flags) \ template \ class BASE_##num : public LIR_OPCODE {}; #include #undef DEFINE_OPCODE #define DEFINE_LIR_OPCODE_X(name) \ template \ class LIR_##name : public BASE_LIR_OPCODE_##name<> {} #define DEFINE_LIR_OPCODE_R32(name) \ template \ class LIR_##name : public BASE_LIR_OPCODE_##name {} #define DEFINE_LIR_OPCODE_R32_R32(name) \ template \ class LIR_##name : public BASE_LIR_OPCODE_##name {} #define DEFINE_LIR_OPCODE_R32_R32_C32(name) \ template \ class LIR_##name : public BASE_LIR_OPCODE_##name {} #include } void alloy::backend::x64::lowering::RegisterSequences(LoweringTable* table) { Translate >, tuple< >> (table); Translate, ValueRef, ValueRef> >, tuple< LIR_MOV_I32, In<0, 0>>, LIR_SUB_I32, In<0, 1>> >> (table); Translate, ValueRef, Int32Constant<1>> >, tuple< LIR_MOV_I32, In<0, 0>>, LIR_DEC_I32> >> (table); Translate, ValueRef, Constant> >, tuple< LIR_IMUL_I32_AUX, In<0, 0>, In<0, 1>> >> (table); Translate, ValueRef, ValueRef> >, tuple< LIR_MOV_I32, In<0, 0>>, LIR_IMUL_I32, In<0, 1>> >> (table); Translate, ValueRef, ValueRef> >, tuple< LIR_MOV_I32, In<0, 0>>, LIR_XOR_I32, Reg>, LIR_DIV_I32>, LIR_MOV_I32, Reg> >> (table); //Translate, ValueRef, ValueRef>, // HIR_IS_TRUE, Out<0>> //>, tuple< // LIR_MOV_I32, In<0, 0>>, // LIR_SUB_I32, In<0, 1>>, // LIR_EFLAGS_NOT_ZF> //>> (table); }