diff --git a/CMakeLists.txt b/CMakeLists.txt index d5cb1e83..56fc6e66 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -162,10 +162,10 @@ set(REDREAM_SOURCES src/jit/ir/ir_reader.cc src/jit/ir/ir_writer.cc src/jit/ir/passes/constant_propagation_pass.cc + src/jit/ir/passes/dead_code_elimination_pass.cc src/jit/ir/passes/load_store_elimination_pass.cc src/jit/ir/passes/pass_runner.cc src/jit/ir/passes/register_allocation_pass.cc - src/jit/ir/passes/validate_pass.cc src/renderer/gl_backend.cc src/renderer/gl_shader.cc src/sys/exception_handler.cc @@ -336,6 +336,7 @@ set(REDREAM_TEST_SOURCES ${REDREAM_SOURCES} test/test_interval_tree.cc test/test_intrusive_list.cc + test/test_dead_code_elimination_pass.cc test/test_load_store_elimination_pass.cc test/test_minmax_heap.cc test/test_sh4.cc diff --git a/src/core/array.h b/src/core/array.h index cdc64ed1..bdb16ced 100644 --- a/src/core/array.h +++ b/src/core/array.h @@ -7,22 +7,19 @@ namespace re { template -class array -{ +class array { public: array(size_t size = 8) : data_(nullptr), size_(0), capacity_(0) { Resize(size); } - ~array() { - free(data_); - } + ~array() { free(data_); } array(array const &) = delete; void operator=(array const &) = delete; - T &operator[] (size_t i) { return data_[i]; } - T operator[] (size_t i) const { return data_[i]; } - + T &operator[](size_t i) { return data_[i]; } + T operator[](size_t i) const { return data_[i]; } + T *data() { return data_; } const T *data() const { return data_; } @@ -60,12 +57,11 @@ class array void PopBack() { size_--; } -private: + private: T *data_; size_t size_; size_t capacity_; }; - } #endif diff --git a/src/core/log.cc b/src/core/log.cc index cc6f3d1c..c895c744 100644 --- a/src/core/log.cc +++ b/src/core/log.cc @@ -11,7 +11,7 @@ #define ANSI_COLOR_RESET "\x1b[0m" void Log(LogLevel level, const char *format, ...) { - static char buffer[1024]; + static char buffer[10240]; va_list args; va_start(args, format); diff --git a/src/hw/sh4/sh4_code_cache.cc b/src/hw/sh4/sh4_code_cache.cc index 7296e6b8..2ceb8f87 100644 --- a/src/hw/sh4/sh4_code_cache.cc +++ b/src/hw/sh4/sh4_code_cache.cc @@ -6,9 +6,9 @@ #include "jit/frontend/sh4/sh4_frontend.h" #include "jit/ir/ir_builder.h" #include "jit/ir/passes/constant_propagation_pass.h" +#include "jit/ir/passes/dead_code_elimination_pass.h" #include "jit/ir/passes/load_store_elimination_pass.h" #include "jit/ir/passes/register_allocation_pass.h" -#include "jit/ir/passes/validate_pass.h" using namespace re::hw; using namespace re::jit; @@ -41,9 +41,9 @@ SH4CodeCache::SH4CodeCache(Memory *memory, void *guest_ctx, } // setup optimization passes - pass_runner_.AddPass(std::unique_ptr(new ValidatePass())); pass_runner_.AddPass(std::unique_ptr(new LoadStoreEliminationPass())); pass_runner_.AddPass(std::unique_ptr(new ConstantPropagationPass())); + pass_runner_.AddPass(std::unique_ptr(new DeadCodeEliminationPass())); pass_runner_.AddPass( std::unique_ptr(new RegisterAllocationPass(*backend_))); @@ -90,7 +90,7 @@ SH4BlockEntry *SH4CodeCache::CompileBlock(uint32_t addr, int max_instrs) { // compile the SH4 into IR std::unique_ptr builder = frontend_->BuildBlock(addr, max_instrs); - pass_runner_.Run(*builder); + pass_runner_.Run(*builder, false); // assemble the IR into native code BlockPointer run = backend_->AssembleBlock(*builder, block->flags); diff --git a/src/jit/backend/x64/x64_emitter.cc b/src/jit/backend/x64/x64_emitter.cc index d3a209c4..7c58247e 100644 --- a/src/jit/backend/x64/x64_emitter.cc +++ b/src/jit/backend/x64/x64_emitter.cc @@ -137,12 +137,7 @@ void X64Emitter::EmitProlog(IRBuilder &builder, int *out_stack_size) { modified_marker_++; for (auto instr : builder.instrs()) { - Value *result = instr->result(); - if (!result) { - continue; - } - - int i = result->reg(); + int i = instr->reg(); if (i == NO_REGISTER) { continue; } @@ -345,10 +340,10 @@ bool X64Emitter::CanEncodeAsImmediate(const Value *v) const { EMITTER(LOAD_HOST) { const Xbyak::Reg a = e.GetRegister(instr->arg0()); - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_F32: e.vmovss(result, e.dword[a]); break; @@ -360,9 +355,9 @@ EMITTER(LOAD_HOST) { break; } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: e.mov(result, e.byte[a]); break; @@ -423,7 +418,7 @@ EMITTER(STORE_HOST) { } EMITTER(LOAD_GUEST) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (instr->arg0()->constant()) { // try to resolve the address to a physical page @@ -442,7 +437,7 @@ EMITTER(LOAD_GUEST) { // we didn't have to store the absolute address in the scratch register e.mov(e.rax, reinterpret_cast(host_addr)); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: e.mov(result, e.byte[e.rax]); break; @@ -468,7 +463,7 @@ EMITTER(LOAD_GUEST) { if (e.block_flags() & BF_SLOWMEM) { void *fn = nullptr; - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: fn = reinterpret_cast( static_cast(&Memory::R8)); @@ -499,7 +494,7 @@ EMITTER(LOAD_GUEST) { e.mov(e.r10, reinterpret_cast(e.guest_ctx())); e.mov(e.r11, reinterpret_cast(e.memory()->protected_base())); } else { - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: e.mov(result, e.byte[a.cvt64() + e.r11]); break; @@ -618,10 +613,10 @@ EMITTER(STORE_GUEST) { EMITTER(LOAD_CONTEXT) { int offset = instr->arg0()->i32(); - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_F32: e.movss(result, e.dword[e.r10 + offset]); break; @@ -633,9 +628,9 @@ EMITTER(LOAD_CONTEXT) { break; } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: e.mov(result, e.byte[e.r10 + offset]); break; @@ -720,10 +715,10 @@ EMITTER(STORE_CONTEXT) { EMITTER(LOAD_LOCAL) { int offset = instr->arg0()->i32(); - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_F32: e.movss(result, e.dword[e.rsp + offset]); break; @@ -735,9 +730,9 @@ EMITTER(LOAD_LOCAL) { break; } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I8: e.mov(result, e.byte[e.rsp + offset]); break; @@ -800,7 +795,7 @@ EMITTER(STORE_LOCAL) { } EMITTER(BITCAST) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result.getIdx() == a.getIdx()) { @@ -812,11 +807,11 @@ EMITTER(BITCAST) { } EMITTER(CAST) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_F32: CHECK_EQ(instr->arg0()->type(), VALUE_I32); e.cvtsi2ss(result, a); @@ -830,10 +825,10 @@ EMITTER(CAST) { break; } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); - switch (instr->result()->type()) { + switch (instr->type()) { case VALUE_I32: CHECK_EQ(instr->arg0()->type(), VALUE_F32); e.cvttss2si(result, a); @@ -850,7 +845,7 @@ EMITTER(CAST) { } EMITTER(SEXT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (a == result) { @@ -866,7 +861,7 @@ EMITTER(SEXT) { } EMITTER(ZEXT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (a == result) { @@ -883,7 +878,7 @@ EMITTER(ZEXT) { } EMITTER(SELECT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg cond = e.GetRegister(instr->arg0()); const Xbyak::Reg a = e.GetRegister(instr->arg1()); const Xbyak::Reg b = e.GetRegister(instr->arg2()); @@ -894,7 +889,7 @@ EMITTER(SELECT) { } EMITTER(EQ) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -920,7 +915,7 @@ EMITTER(EQ) { } EMITTER(NE) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -946,7 +941,7 @@ EMITTER(NE) { } EMITTER(SGE) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -974,7 +969,7 @@ EMITTER(SGE) { } EMITTER(SGT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -1002,7 +997,7 @@ EMITTER(SGT) { } EMITTER(UGE) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (e.CanEncodeAsImmediate(instr->arg1())) { @@ -1016,7 +1011,7 @@ EMITTER(UGE) { } EMITTER(UGT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (e.CanEncodeAsImmediate(instr->arg1())) { @@ -1030,7 +1025,7 @@ EMITTER(UGT) { } EMITTER(SLE) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -1058,7 +1053,7 @@ EMITTER(SLE) { } EMITTER(SLT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); if (IsFloatType(instr->arg0()->type())) { const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); @@ -1086,7 +1081,7 @@ EMITTER(SLT) { } EMITTER(ULE) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (e.CanEncodeAsImmediate(instr->arg1())) { @@ -1100,7 +1095,7 @@ EMITTER(ULE) { } EMITTER(ULT) { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (e.CanEncodeAsImmediate(instr->arg1())) { @@ -1114,12 +1109,12 @@ EMITTER(ULT) { } EMITTER(ADD) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { if (result != a) { e.movss(result, a); } @@ -1133,7 +1128,7 @@ EMITTER(ADD) { e.addsd(result, b); } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1150,12 +1145,12 @@ EMITTER(ADD) { } EMITTER(SUB) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { if (result != a) { e.movss(result, a); } @@ -1169,7 +1164,7 @@ EMITTER(SUB) { e.subsd(result, b); } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1186,12 +1181,12 @@ EMITTER(SUB) { } EMITTER(SMUL) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { if (result != a) { e.movss(result, a); } @@ -1205,7 +1200,7 @@ EMITTER(SMUL) { e.mulsd(result, b); } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); const Xbyak::Reg b = e.GetRegister(instr->arg1()); @@ -1218,9 +1213,9 @@ EMITTER(SMUL) { } EMITTER(UMUL) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); const Xbyak::Reg b = e.GetRegister(instr->arg1()); @@ -1232,13 +1227,13 @@ EMITTER(UMUL) { } EMITTER(DIV) { - CHECK(IsFloatType(instr->result()->type())); + CHECK(IsFloatType(instr->type())); - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { if (result != a) { e.movss(result, a); } @@ -1254,11 +1249,11 @@ EMITTER(DIV) { } EMITTER(NEG) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { // TODO use xorps e.movd(e.eax, a); e.xor (e.eax, (uint32_t)0x80000000); @@ -1271,7 +1266,7 @@ EMITTER(NEG) { e.movq(result, e.rax); } } else { - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1283,12 +1278,12 @@ EMITTER(NEG) { } EMITTER(SQRT) { - CHECK(IsFloatType(instr->result()->type())); + CHECK(IsFloatType(instr->type())); - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { e.sqrtss(result, a); } else { e.sqrtsd(result, a); @@ -1296,11 +1291,11 @@ EMITTER(SQRT) { } EMITTER(ABS) { - if (IsFloatType(instr->result()->type())) { - const Xbyak::Xmm result = e.GetXMMRegister(instr->result()); + if (IsFloatType(instr->type())) { + const Xbyak::Xmm result = e.GetXMMRegister(instr); const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0()); - if (instr->result()->type() == VALUE_F32) { + if (instr->type() == VALUE_F32) { // TODO use andps e.movd(e.eax, a); e.and (e.eax, (uint32_t)0x7fffffff); @@ -1321,9 +1316,9 @@ EMITTER(ABS) { } EMITTER(AND) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1339,9 +1334,9 @@ EMITTER(AND) { } EMITTER(OR) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1357,9 +1352,9 @@ EMITTER(OR) { } EMITTER(XOR) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1375,9 +1370,9 @@ EMITTER(XOR) { } EMITTER(NOT) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1388,9 +1383,9 @@ EMITTER(NOT) { } EMITTER(SHL) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1407,9 +1402,9 @@ EMITTER(SHL) { } EMITTER(ASHR) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1426,9 +1421,9 @@ EMITTER(ASHR) { } EMITTER(LSHR) { - CHECK(IsIntType(instr->result()->type())); + CHECK(IsIntType(instr->type())); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg a = e.GetRegister(instr->arg0()); if (result != a) { @@ -1445,9 +1440,9 @@ EMITTER(LSHR) { } EMITTER(ASHD) { - CHECK_EQ(instr->result()->type(), VALUE_I32); + CHECK_EQ(instr->type(), VALUE_I32); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg v = e.GetRegister(instr->arg0()); const Xbyak::Reg n = e.GetRegister(instr->arg1()); @@ -1486,9 +1481,9 @@ EMITTER(ASHD) { } EMITTER(LSHD) { - CHECK_EQ(instr->result()->type(), VALUE_I32); + CHECK_EQ(instr->type(), VALUE_I32); - const Xbyak::Reg result = e.GetRegister(instr->result()); + const Xbyak::Reg result = e.GetRegister(instr); const Xbyak::Reg v = e.GetRegister(instr->arg0()); const Xbyak::Reg n = e.GetRegister(instr->arg1()); diff --git a/src/jit/ir/ir_builder.cc b/src/jit/ir/ir_builder.cc index 0d2eda1f..e74a06f0 100644 --- a/src/jit/ir/ir_builder.cc +++ b/src/jit/ir/ir_builder.cc @@ -38,9 +38,9 @@ uint64_t Value::GetZExtValue() const { } } -void Value::AddRef(ValueRef *ref) { refs_.Append(ref); } +void Value::AddRef(Use *ref) { refs_.Append(ref); } -void Value::RemoveRef(ValueRef *ref) { refs_.Remove(ref); } +void Value::RemoveRef(Use *ref) { refs_.Remove(ref); } void Value::ReplaceRefsWith(Value *other) { CHECK_NE(this, other); @@ -48,25 +48,32 @@ void Value::ReplaceRefsWith(Value *other) { // NOTE set_value will modify refs, be careful iterating auto it = refs_.begin(); while (it != refs_.end()) { - ValueRef *ref = *(it++); + Use *ref = *(it++); ref->set_value(other); } } -ValueRef::ValueRef(Instr *instr) : instr_(instr), value_(nullptr) {} +// +// Use +// +Use::Use(Instr *instr) : instr_(instr), value_(nullptr) {} -ValueRef::~ValueRef() { +Use::~Use() { if (value_) { value_->RemoveRef(this); } } +// +// Local +// Local::Local(ValueType ty, Value *offset) : type_(ty), offset_(offset) {} // // Instr // -Instr::Instr(Op op) : op_(op), args_{{this}, {this}, {this}, {this}}, tag_(0) {} +Instr::Instr(Op op, ValueType result_type) + : Value(result_type), op_(op), uses_{{this}, {this}, {this}}, tag_(0) {} Instr::~Instr() {} @@ -79,7 +86,7 @@ void IRBuilder::Dump() const { IRWriter writer; std::ostringstream ss; writer.Print(*this, ss); - LOG_INFO(ss.str().c_str()); + LOG_INFO("%s", ss.str().c_str()); } InsertPoint IRBuilder::GetInsertPoint() { return {current_instr_}; } @@ -95,14 +102,12 @@ void IRBuilder::RemoveInstr(Instr *instr) { instr->~Instr(); } -Value *IRBuilder::LoadHost(Value *addr, ValueType type) { +Instr *IRBuilder::LoadHost(Value *addr, ValueType type) { CHECK_EQ(VALUE_I64, addr->type()); - Instr *instr = AppendInstr(OP_LOAD_HOST); - Value *result = AllocDynamic(type); + Instr *instr = AppendInstr(OP_LOAD_HOST, type); instr->set_arg0(addr); - instr->set_result(result); - return result; + return instr; } void IRBuilder::StoreHost(Value *addr, Value *v) { @@ -113,14 +118,12 @@ void IRBuilder::StoreHost(Value *addr, Value *v) { instr->set_arg1(v); } -Value *IRBuilder::LoadGuest(Value *addr, ValueType type) { +Instr *IRBuilder::LoadGuest(Value *addr, ValueType type) { CHECK_EQ(VALUE_I32, addr->type()); - Instr *instr = AppendInstr(OP_LOAD_GUEST); - Value *result = AllocDynamic(type); + Instr *instr = AppendInstr(OP_LOAD_GUEST, type); instr->set_arg0(addr); - instr->set_result(result); - return result; + return instr; } void IRBuilder::StoreGuest(Value *addr, Value *v) { @@ -131,12 +134,10 @@ void IRBuilder::StoreGuest(Value *addr, Value *v) { instr->set_arg1(v); } -Value *IRBuilder::LoadContext(size_t offset, ValueType type) { - Instr *instr = AppendInstr(OP_LOAD_CONTEXT); - Value *result = AllocDynamic(type); +Instr *IRBuilder::LoadContext(size_t offset, ValueType type) { + Instr *instr = AppendInstr(OP_LOAD_CONTEXT, type); instr->set_arg0(AllocConstant((int32_t)offset)); - instr->set_result(result); - return result; + return instr; } void IRBuilder::StoreContext(size_t offset, Value *v) { @@ -145,12 +146,10 @@ void IRBuilder::StoreContext(size_t offset, Value *v) { instr->set_arg1(v); } -Value *IRBuilder::LoadLocal(Local *local) { - Instr *instr = AppendInstr(OP_LOAD_LOCAL); - Value *result = AllocDynamic(local->type()); +Instr *IRBuilder::LoadLocal(Local *local) { + Instr *instr = AppendInstr(OP_LOAD_LOCAL, local->type()); instr->set_arg0(local->offset()); - instr->set_result(result); - return result; + return instr; } void IRBuilder::StoreLocal(Local *local, Value *v) { @@ -159,366 +158,302 @@ void IRBuilder::StoreLocal(Local *local, Value *v) { instr->set_arg1(v); } -Value *IRBuilder::Bitcast(Value *v, ValueType dest_type) { +Instr *IRBuilder::Bitcast(Value *v, ValueType dest_type) { CHECK((IsIntType(v->type()) && IsIntType(dest_type)) || (IsFloatType(v->type()) && IsFloatType(dest_type))); - Instr *instr = AppendInstr(OP_BITCAST); - Value *result = AllocDynamic(dest_type); + Instr *instr = AppendInstr(OP_BITCAST, dest_type); instr->set_arg0(v); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Cast(Value *v, ValueType dest_type) { +Instr *IRBuilder::Cast(Value *v, ValueType dest_type) { CHECK((IsIntType(v->type()) && IsFloatType(dest_type)) || (IsFloatType(v->type()) && IsIntType(dest_type))); - Instr *instr = AppendInstr(OP_CAST); - Value *result = AllocDynamic(dest_type); + Instr *instr = AppendInstr(OP_CAST, dest_type); instr->set_arg0(v); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SExt(Value *v, ValueType dest_type) { +Instr *IRBuilder::SExt(Value *v, ValueType dest_type) { CHECK(IsIntType(v->type()) && IsIntType(dest_type)); - Instr *instr = AppendInstr(OP_SEXT); - Value *result = AllocDynamic(dest_type); + Instr *instr = AppendInstr(OP_SEXT, dest_type); instr->set_arg0(v); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::ZExt(Value *v, ValueType dest_type) { +Instr *IRBuilder::ZExt(Value *v, ValueType dest_type) { CHECK(IsIntType(v->type()) && IsIntType(dest_type)); - Instr *instr = AppendInstr(OP_ZEXT); - Value *result = AllocDynamic(dest_type); + Instr *instr = AppendInstr(OP_ZEXT, dest_type); instr->set_arg0(v); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Select(Value *cond, Value *t, Value *f) { +Instr *IRBuilder::Select(Value *cond, Value *t, Value *f) { CHECK_EQ(t->type(), f->type()); if (cond->type() != VALUE_I8) { cond = NE(cond, AllocConstant(0)); } - Instr *instr = AppendInstr(OP_SELECT); - Value *result = AllocDynamic(t->type()); + Instr *instr = AppendInstr(OP_SELECT, t->type()); instr->set_arg0(cond); instr->set_arg1(t); instr->set_arg2(f); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::EQ(Value *a, Value *b) { +Instr *IRBuilder::EQ(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_EQ); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_EQ, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::NE(Value *a, Value *b) { +Instr *IRBuilder::NE(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_NE); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_NE, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SGE(Value *a, Value *b) { +Instr *IRBuilder::SGE(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SGE); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_SGE, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SGT(Value *a, Value *b) { +Instr *IRBuilder::SGT(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SGT); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_SGT, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::UGE(Value *a, Value *b) { +Instr *IRBuilder::UGE(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); CHECK_EQ(true, IsIntType(a->type()) && IsIntType(b->type())); - Instr *instr = AppendInstr(OP_UGE); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_UGE, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::UGT(Value *a, Value *b) { +Instr *IRBuilder::UGT(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); CHECK_EQ(true, IsIntType(a->type()) && IsIntType(b->type())); - Instr *instr = AppendInstr(OP_UGT); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_UGT, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SLE(Value *a, Value *b) { +Instr *IRBuilder::SLE(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SLE); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_SLE, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SLT(Value *a, Value *b) { +Instr *IRBuilder::SLT(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SLT); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_SLT, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::ULE(Value *a, Value *b) { +Instr *IRBuilder::ULE(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); CHECK_EQ(true, IsIntType(a->type()) && IsIntType(b->type())); - Instr *instr = AppendInstr(OP_ULE); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_ULE, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::ULT(Value *a, Value *b) { +Instr *IRBuilder::ULT(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); CHECK_EQ(true, IsIntType(a->type()) && IsIntType(b->type())); - Instr *instr = AppendInstr(OP_ULT); - Value *result = AllocDynamic(VALUE_I8); + Instr *instr = AppendInstr(OP_ULT, VALUE_I8); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Add(Value *a, Value *b) { +Instr *IRBuilder::Add(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_ADD); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_ADD, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Sub(Value *a, Value *b) { +Instr *IRBuilder::Sub(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SUB); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_SUB, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::SMul(Value *a, Value *b) { +Instr *IRBuilder::SMul(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_SMUL); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_SMUL, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::UMul(Value *a, Value *b) { +Instr *IRBuilder::UMul(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); CHECK(IsIntType(a->type())); - Instr *instr = AppendInstr(OP_UMUL); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_UMUL, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Div(Value *a, Value *b) { +Instr *IRBuilder::Div(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_DIV); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_DIV, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Neg(Value *a) { - Instr *instr = AppendInstr(OP_NEG); - Value *result = AllocDynamic(a->type()); +Instr *IRBuilder::Neg(Value *a) { + Instr *instr = AppendInstr(OP_NEG, a->type()); instr->set_arg0(a); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Sqrt(Value *a) { - Instr *instr = AppendInstr(OP_SQRT); - Value *result = AllocDynamic(a->type()); +Instr *IRBuilder::Sqrt(Value *a) { + Instr *instr = AppendInstr(OP_SQRT, a->type()); instr->set_arg0(a); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Abs(Value *a) { - Instr *instr = AppendInstr(OP_ABS); - Value *result = AllocDynamic(a->type()); +Instr *IRBuilder::Abs(Value *a) { + Instr *instr = AppendInstr(OP_ABS, a->type()); instr->set_arg0(a); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::And(Value *a, Value *b) { +Instr *IRBuilder::And(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_AND); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_AND, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Or(Value *a, Value *b) { +Instr *IRBuilder::Or(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_OR); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_OR, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Xor(Value *a, Value *b) { +Instr *IRBuilder::Xor(Value *a, Value *b) { CHECK_EQ(a->type(), b->type()); - Instr *instr = AppendInstr(OP_XOR); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_XOR, a->type()); instr->set_arg0(a); instr->set_arg1(b); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Not(Value *a) { - Instr *instr = AppendInstr(OP_NOT); - Value *result = AllocDynamic(a->type()); +Instr *IRBuilder::Not(Value *a) { + Instr *instr = AppendInstr(OP_NOT, a->type()); instr->set_arg0(a); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Shl(Value *a, Value *n) { +Instr *IRBuilder::Shl(Value *a, Value *n) { CHECK_EQ(VALUE_I32, n->type()); - Instr *instr = AppendInstr(OP_SHL); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_SHL, a->type()); instr->set_arg0(a); instr->set_arg1(n); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::Shl(Value *a, int n) { +Instr *IRBuilder::Shl(Value *a, int n) { return Shl(a, AllocConstant((int32_t)n)); } -Value *IRBuilder::AShr(Value *a, Value *n) { +Instr *IRBuilder::AShr(Value *a, Value *n) { CHECK_EQ(VALUE_I32, n->type()); - Instr *instr = AppendInstr(OP_ASHR); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_ASHR, a->type()); instr->set_arg0(a); instr->set_arg1(n); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::AShr(Value *a, int n) { +Instr *IRBuilder::AShr(Value *a, int n) { return AShr(a, AllocConstant((int32_t)n)); } -Value *IRBuilder::LShr(Value *a, Value *n) { +Instr *IRBuilder::LShr(Value *a, Value *n) { CHECK_EQ(VALUE_I32, n->type()); - Instr *instr = AppendInstr(OP_LSHR); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_LSHR, a->type()); instr->set_arg0(a); instr->set_arg1(n); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::LShr(Value *a, int n) { +Instr *IRBuilder::LShr(Value *a, int n) { return LShr(a, AllocConstant((int32_t)n)); } -Value *IRBuilder::AShd(Value *a, Value *n) { +Instr *IRBuilder::AShd(Value *a, Value *n) { CHECK_EQ(VALUE_I32, a->type()); CHECK_EQ(VALUE_I32, n->type()); - Instr *instr = AppendInstr(OP_ASHD); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_ASHD, a->type()); instr->set_arg0(a); instr->set_arg1(n); - instr->set_result(result); - return result; + return instr; } -Value *IRBuilder::LShd(Value *a, Value *n) { +Instr *IRBuilder::LShd(Value *a, Value *n) { CHECK_EQ(VALUE_I32, a->type()); CHECK_EQ(VALUE_I32, n->type()); - Instr *instr = AppendInstr(OP_LSHD); - Value *result = AllocDynamic(a->type()); + Instr *instr = AppendInstr(OP_LSHD, a->type()); instr->set_arg0(a); instr->set_arg1(n); - instr->set_result(result); - return result; + return instr; } void IRBuilder::CallExternal1(Value *addr) { @@ -600,14 +535,21 @@ Local *IRBuilder::AllocLocal(ValueType type) { return l; } -Instr *IRBuilder::AllocInstr(Op op) { +Instr *IRBuilder::AllocInstr(Op op, ValueType result_type) { Instr *instr = arena_.Alloc(); - new (instr) Instr(op); + new (instr) Instr(op, result_type); return instr; } Instr *IRBuilder::AppendInstr(Op op) { - Instr *instr = AllocInstr(op); + Instr *instr = AllocInstr(op, VALUE_V); + instrs_.Insert(current_instr_, instr); + current_instr_ = instr; + return instr; +} + +Instr *IRBuilder::AppendInstr(Op op, ValueType result_type) { + Instr *instr = AllocInstr(op, result_type); instrs_.Insert(current_instr_, instr); current_instr_ = instr; return instr; diff --git a/src/jit/ir/ir_builder.h b/src/jit/ir/ir_builder.h index 1e248f58..803d9192 100644 --- a/src/jit/ir/ir_builder.h +++ b/src/jit/ir/ir_builder.h @@ -51,7 +51,7 @@ enum { }; class Instr; -class ValueRef; +class Use; static inline bool IsFloatType(ValueType type) { return type == VALUE_F32 || type == VALUE_F64; @@ -93,6 +93,11 @@ class Value { bool constant() const { return constant_; } + // defined at the end of the file, Instr is only forward declared at this + // point, it can't be static_cast to + const Instr *def() const; + Instr *def(); + int8_t i8() const { DCHECK(constant_ && type_ == VALUE_I8); return i8_; @@ -124,8 +129,8 @@ class Value { } double f64() { return static_cast(this)->f64(); } - const IntrusiveList &refs() const { return refs_; } - IntrusiveList &refs() { return refs_; } + const IntrusiveList &uses() const { return refs_; } + IntrusiveList &uses() { return refs_; } int reg() const { return reg_; } void set_reg(int reg) { reg_ = reg; } @@ -135,8 +140,8 @@ class Value { uint64_t GetZExtValue() const; - void AddRef(ValueRef *ref); - void RemoveRef(ValueRef *ref); + void AddRef(Use *ref); + void RemoveRef(Use *ref); void ReplaceRefsWith(Value *other); private: @@ -150,19 +155,19 @@ class Value { float f32_; double f64_; }; - IntrusiveList refs_; + IntrusiveList refs_; // initializing here so each constructor variation doesn't have to int reg_{NO_REGISTER}; intptr_t tag_{0}; }; -// ValueRef is a layer of indirection between an instruction and a values it -// uses. Values maintain a list of all of their references, making it possible -// during optimization to replace all references to a value with a new value. -class ValueRef : public IntrusiveListNode { +// Use is a layer of indirection between an instruction and a values it uses. +// Values maintain a list of all of their uses, making it possible to replace +// all uses of a value with a new value during optimizations +class Use : public IntrusiveListNode { public: - ValueRef(Instr *instr); - ~ValueRef(); + Use(Instr *instr); + ~Use(); const Instr *instr() const { return instr_; } Instr *instr() { return instr_; } @@ -227,9 +232,7 @@ struct ValueInfo { }; // Locals are allocated for values that need to be spilled to the stack during -// register allocation. When allocated, a default offset of 0 is assigned, -// each backend is expected to update the offset to an appropriate value -// before emitting. +// register allocation. class Local : public IntrusiveListNode { public: Local(ValueType ty, Value *offset); @@ -252,9 +255,9 @@ class Local : public IntrusiveListNode { // // instructions // -class Instr : public IntrusiveListNode { +class Instr : public Value, public IntrusiveListNode { public: - Instr(Op op); + Instr(Op op, ValueType result_type); ~Instr(); Op op() const { return op_; } @@ -271,20 +274,25 @@ class Instr : public IntrusiveListNode { Value *arg2() { return arg(2); } void set_arg2(Value *v) { set_arg(2, v); } - const Value *result() const { return arg(3); } - Value *result() { return arg(3); } - void set_result(Value *v) { set_arg(3, v); } - - const Value *arg(int i) const { return args_[i].value(); } - Value *arg(int i) { return args_[i].value(); } - void set_arg(int i, Value *v) { args_[i].set_value(v); } + const Value *arg(int i) const { + CHECK_LT(i, 3); + return uses_[i].value(); + } + Value *arg(int i) { + CHECK_LT(i, 3); + return uses_[i].value(); + } + void set_arg(int i, Value *v) { + CHECK_LT(i, 3); + uses_[i].set_value(v); + } intptr_t tag() const { return tag_; } void set_tag(intptr_t tag) { tag_ = tag; } private: Op op_; - ValueRef args_[4]; + Use uses_[3]; intptr_t tag_; }; @@ -317,63 +325,63 @@ class IRBuilder { void RemoveInstr(Instr *instr); // direct access to host memory - Value *LoadHost(Value *addr, ValueType type); + Instr *LoadHost(Value *addr, ValueType type); void StoreHost(Value *addr, Value *v); // guest memory operations - Value *LoadGuest(Value *addr, ValueType type); + Instr *LoadGuest(Value *addr, ValueType type); void StoreGuest(Value *addr, Value *v); // context operations - Value *LoadContext(size_t offset, ValueType type); + Instr *LoadContext(size_t offset, ValueType type); void StoreContext(size_t offset, Value *v); // local operations - Value *LoadLocal(Local *local); + Instr *LoadLocal(Local *local); void StoreLocal(Local *local, Value *v); // cast / conversion operations - Value *Bitcast(Value *v, ValueType dest_type); - Value *Cast(Value *v, ValueType dest_type); - Value *SExt(Value *v, ValueType dest_type); - Value *ZExt(Value *v, ValueType dest_type); + Instr *Bitcast(Value *v, ValueType dest_type); + Instr *Cast(Value *v, ValueType dest_type); + Instr *SExt(Value *v, ValueType dest_type); + Instr *ZExt(Value *v, ValueType dest_type); // conditionals - Value *Select(Value *cond, Value *t, Value *f); - Value *EQ(Value *a, Value *b); - Value *NE(Value *a, Value *b); - Value *SGE(Value *a, Value *b); - Value *SGT(Value *a, Value *b); - Value *UGE(Value *a, Value *b); - Value *UGT(Value *a, Value *b); - Value *SLE(Value *a, Value *b); - Value *SLT(Value *a, Value *b); - Value *ULE(Value *a, Value *b); - Value *ULT(Value *a, Value *b); + Instr *Select(Value *cond, Value *t, Value *f); + Instr *EQ(Value *a, Value *b); + Instr *NE(Value *a, Value *b); + Instr *SGE(Value *a, Value *b); + Instr *SGT(Value *a, Value *b); + Instr *UGE(Value *a, Value *b); + Instr *UGT(Value *a, Value *b); + Instr *SLE(Value *a, Value *b); + Instr *SLT(Value *a, Value *b); + Instr *ULE(Value *a, Value *b); + Instr *ULT(Value *a, Value *b); // math operators - Value *Add(Value *a, Value *b); - Value *Sub(Value *a, Value *b); - Value *SMul(Value *a, Value *b); - Value *UMul(Value *a, Value *b); - Value *Div(Value *a, Value *b); - Value *Neg(Value *a); - Value *Sqrt(Value *a); - Value *Abs(Value *a); + Instr *Add(Value *a, Value *b); + Instr *Sub(Value *a, Value *b); + Instr *SMul(Value *a, Value *b); + Instr *UMul(Value *a, Value *b); + Instr *Div(Value *a, Value *b); + Instr *Neg(Value *a); + Instr *Sqrt(Value *a); + Instr *Abs(Value *a); // bitwise operations - Value *And(Value *a, Value *b); - Value *Or(Value *a, Value *b); - Value *Xor(Value *a, Value *b); - Value *Not(Value *a); - Value *Shl(Value *a, Value *n); - Value *Shl(Value *a, int n); - Value *AShr(Value *a, Value *n); - Value *AShr(Value *a, int n); - Value *LShr(Value *a, Value *n); - Value *LShr(Value *a, int n); - Value *AShd(Value *a, Value *n); - Value *LShd(Value *a, Value *n); + Instr *And(Value *a, Value *b); + Instr *Or(Value *a, Value *b); + Instr *Xor(Value *a, Value *b); + Instr *Not(Value *a); + Instr *Shl(Value *a, Value *n); + Instr *Shl(Value *a, int n); + Instr *AShr(Value *a, Value *n); + Instr *AShr(Value *a, int n); + Instr *LShr(Value *a, Value *n); + Instr *LShr(Value *a, int n); + Instr *AShd(Value *a, Value *n); + Instr *LShd(Value *a, Value *n); // calls void CallExternal1(Value *addr); @@ -394,14 +402,25 @@ class IRBuilder { Local *AllocLocal(ValueType type); protected: - Instr *AllocInstr(Op op); + Instr *AllocInstr(Op op, ValueType result_type); Instr *AppendInstr(Op op); + Instr *AppendInstr(Op op, ValueType result_type); Arena arena_; IntrusiveList instrs_; IntrusiveList locals_; Instr *current_instr_; }; + +inline const Instr *Value::def() const { + CHECK(!constant_); + return static_cast(this); +} + +inline Instr *Value::def() { + CHECK(!constant_); + return static_cast(this); +} } } } diff --git a/src/jit/ir/ir_reader.cc b/src/jit/ir/ir_reader.cc index 112b406d..ce607b8f 100644 --- a/src/jit/ir/ir_reader.cc +++ b/src/jit/ir/ir_reader.cc @@ -257,11 +257,24 @@ bool IRReader::ParseOperator(IRLexer &lex, IRBuilder &builder) { } bool IRReader::ParseInstruction(IRLexer &lex, IRBuilder &builder) { - Value *arg[4] = {}; + int slot = -1; + ValueType type = VALUE_V; + Value *arg[3] = {}; + // parse result type and slot number if (lex.tok() == TOK_TYPE) { - // parse result value - if (!ParseValue(lex, builder, &arg[3]) || !ParseOperator(lex, builder)) { + if (!ParseType(lex, builder, &type)) { + return false; + } + + const char *ident = lex.val().s; + if (ident[0] != '%') { + return false; + } + slot = atoi(&ident[1]); + lex.Next(); + + if (!ParseOperator(lex, builder)) { return false; } } @@ -285,12 +298,19 @@ bool IRReader::ParseInstruction(IRLexer &lex, IRBuilder &builder) { } // create instruction - Instr *instr = builder.AppendInstr(op); + Instr *instr = builder.AppendInstr(op, type); - for (int i = 0; i < 4; i++) { - if (arg[i]) { - instr->set_arg(i, arg[i]); + for (int i = 0; i < 3; i++) { + if (!arg[i]) { + continue; } + + instr->set_arg(i, arg[i]); + } + + // insert instruction into slot if specified + if (slot != -1) { + slots_.insert(std::make_pair(slot, instr)); } return true; diff --git a/src/jit/ir/ir_writer.cc b/src/jit/ir/ir_writer.cc index c702dcbf..cd0f37c6 100644 --- a/src/jit/ir/ir_writer.cc +++ b/src/jit/ir/ir_writer.cc @@ -92,8 +92,8 @@ void IRWriter::PrintValue(const Value *value, std::ostream &output) { void IRWriter::PrintInstruction(const Instr *instr, std::ostream &output) { // print result value if we have one - if (instr->result()) { - PrintValue(instr->result(), output); + if (instr->type() != VALUE_V) { + PrintValue(instr, output); output << " = "; } @@ -119,5 +119,7 @@ void IRWriter::PrintInstruction(const Instr *instr, std::ostream &output) { need_comma = true; } + // output << " [tag " << instr->tag() << ", reg " << instr->reg() << "]"; + output << std::endl; } diff --git a/src/jit/ir/passes/constant_propagation_pass.cc b/src/jit/ir/passes/constant_propagation_pass.cc index 6f95201a..22838534 100644 --- a/src/jit/ir/passes/constant_propagation_pass.cc +++ b/src/jit/ir/passes/constant_propagation_pass.cc @@ -55,15 +55,15 @@ int fold_masks[NUM_OPS]; #define ARG1_UNSIGNED() static_cast(ARG1()) #define ARG2_UNSIGNED() static_cast(ARG2()) #define RESULT(expr) \ - instr->result()->ReplaceRefsWith( \ + instr->ReplaceRefsWith( \ builder.AllocConstant(static_cast(expr))); \ builder.RemoveInstr(instr) static FoldFn GetFoldFn(Instr *instr) { - auto it = fold_cbs.find(CALLBACK_IDX( - instr->op(), instr->result() ? (int)instr->result()->type() : VALUE_V, - instr->arg0() ? (int)instr->arg0()->type() : VALUE_V, - instr->arg1() ? (int)instr->arg1()->type() : VALUE_V)); + auto it = fold_cbs.find( + CALLBACK_IDX(instr->op(), instr->type(), + instr->arg0() ? (int)instr->arg0()->type() : VALUE_V, + instr->arg1() ? (int)instr->arg1()->type() : VALUE_V)); if (it == fold_cbs.end()) { return nullptr; } @@ -90,7 +90,7 @@ static int GetConstantSig(Instr *instr) { return cnst_sig; } -void ConstantPropagationPass::Run(IRBuilder &builder) { +void ConstantPropagationPass::Run(IRBuilder &builder, bool debug) { PROFILER_RUNTIME("ConstantPropagationPass::Run"); auto it = builder.instrs().begin(); @@ -115,7 +115,7 @@ void ConstantPropagationPass::Run(IRBuilder &builder) { } FOLD(SELECT, ARG0_CNST) { - instr->result()->ReplaceRefsWith(ARG0() ? instr->arg1() : instr->arg2()); + instr->ReplaceRefsWith(ARG0() ? instr->arg1() : instr->arg2()); builder.RemoveInstr(instr); } REGISTER_FOLD(SELECT, I8, I8, I8); diff --git a/src/jit/ir/passes/constant_propagation_pass.h b/src/jit/ir/passes/constant_propagation_pass.h index 4557714d..442ad712 100644 --- a/src/jit/ir/passes/constant_propagation_pass.h +++ b/src/jit/ir/passes/constant_propagation_pass.h @@ -10,9 +10,9 @@ namespace passes { class ConstantPropagationPass : public Pass { public: - void Run(IRBuilder &builder); + const char *name() { return "Constant Propagation Pass"; } - private: + void Run(IRBuilder &builder, bool debug); }; } } diff --git a/src/jit/ir/passes/dead_code_elimination_pass.cc b/src/jit/ir/passes/dead_code_elimination_pass.cc new file mode 100644 index 00000000..2154a64e --- /dev/null +++ b/src/jit/ir/passes/dead_code_elimination_pass.cc @@ -0,0 +1,27 @@ +#include "emu/profiler.h" +#include "jit/ir/passes/dead_code_elimination_pass.h" + +using namespace re::jit::backend; +using namespace re::jit::ir; +using namespace re::jit::ir::passes; + +void DeadCodeEliminationPass::Run(IRBuilder &builder, bool debug) { + PROFILER_RUNTIME("DeadCodeEliminationPass::Run"); + + // iterate in reverse in order to remove groups of dead instructions that + // only use eachother + auto it = builder.instrs().rbegin(); + auto end = builder.instrs().rend(); + + while (it != end) { + Instr *instr = *(it++); + + if (instr->type() == VALUE_V) { + continue; + } + + if (!instr->uses().head()) { + builder.RemoveInstr(instr); + } + } +} diff --git a/src/jit/ir/passes/dead_code_elimination_pass.h b/src/jit/ir/passes/dead_code_elimination_pass.h new file mode 100644 index 00000000..b2068f23 --- /dev/null +++ b/src/jit/ir/passes/dead_code_elimination_pass.h @@ -0,0 +1,23 @@ +#ifndef DEAD_CODE_ELIMINATION_PASS_H +#define DEAD_CODE_ELIMINATION_PASS_H + +#include "jit/backend/backend.h" +#include "jit/ir/passes/pass_runner.h" + +namespace re { +namespace jit { +namespace ir { +namespace passes { + +class DeadCodeEliminationPass : public Pass { + public: + const char *name() { return "Dead Code Elimination Pass"; } + + void Run(IRBuilder &builder, bool debug); +}; +} +} +} +} + +#endif diff --git a/src/jit/ir/passes/load_store_elimination_pass.cc b/src/jit/ir/passes/load_store_elimination_pass.cc index 8c7da913..99d21c80 100644 --- a/src/jit/ir/passes/load_store_elimination_pass.cc +++ b/src/jit/ir/passes/load_store_elimination_pass.cc @@ -7,7 +7,7 @@ using namespace re::jit::ir::passes; LoadStoreEliminationPass::LoadStoreEliminationPass() : available_(nullptr), num_available_(0) {} -void LoadStoreEliminationPass::Run(IRBuilder &builder) { +void LoadStoreEliminationPass::Run(IRBuilder &builder, bool debug) { PROFILER_RUNTIME("LoadStoreEliminationPass::Run"); Reset(); @@ -28,14 +28,13 @@ void LoadStoreEliminationPass::Run(IRBuilder &builder) { int offset = instr->arg0()->i32(); Value *available = GetAvailable(offset); - if (available && available->type() == instr->result()->type()) { - instr->result()->ReplaceRefsWith(available); - CHECK_EQ(instr->result(), available); + if (available && available->type() == instr->type()) { + instr->ReplaceRefsWith(available); builder.RemoveInstr(instr); continue; } - SetAvailable(offset, instr->result()); + SetAvailable(offset, instr); } else if (instr->op() == OP_STORE_CONTEXT) { int offset = instr->arg0()->i32(); @@ -58,7 +57,7 @@ void LoadStoreEliminationPass::Run(IRBuilder &builder) { if (instr->op() == OP_LOAD_CONTEXT) { int offset = instr->arg0()->i32(); - int size = SizeForType(instr->result()->type()); + int size = SizeForType(instr->type()); EraseAvailable(offset, size); } else if (instr->op() == OP_STORE_CONTEXT) { diff --git a/src/jit/ir/passes/load_store_elimination_pass.h b/src/jit/ir/passes/load_store_elimination_pass.h index b83f9557..fb55675c 100644 --- a/src/jit/ir/passes/load_store_elimination_pass.h +++ b/src/jit/ir/passes/load_store_elimination_pass.h @@ -17,7 +17,9 @@ class LoadStoreEliminationPass : public Pass { public: LoadStoreEliminationPass(); - void Run(IRBuilder &builder); + const char *name() { return "Load / Store Elimination Pass"; } + + void Run(IRBuilder &builder, bool debug); private: void Reset(); diff --git a/src/jit/ir/passes/pass_runner.cc b/src/jit/ir/passes/pass_runner.cc index 9bb65643..12278ab7 100644 --- a/src/jit/ir/passes/pass_runner.cc +++ b/src/jit/ir/passes/pass_runner.cc @@ -11,10 +11,20 @@ void PassRunner::AddPass(std::unique_ptr pass) { passes_.push_back(std::move(pass)); } -void PassRunner::Run(IRBuilder &builder) { +void PassRunner::Run(IRBuilder &builder, bool debug) { PROFILER_RUNTIME("PassRunner::Run"); + if (debug) { + LOG_INFO("Original:"); + builder.Dump(); + } + for (auto &pass : passes_) { - pass->Run(builder); + pass->Run(builder, debug); + + if (debug) { + LOG_INFO("%s:", pass->name()); + builder.Dump(); + } } } diff --git a/src/jit/ir/passes/pass_runner.h b/src/jit/ir/passes/pass_runner.h index 881548e1..5bd41f0b 100644 --- a/src/jit/ir/passes/pass_runner.h +++ b/src/jit/ir/passes/pass_runner.h @@ -13,7 +13,10 @@ namespace passes { class Pass { public: virtual ~Pass() {} - virtual void Run(IRBuilder &builder) = 0; + + virtual const char *name() = 0; + + virtual void Run(IRBuilder &builder, bool debug) = 0; }; class PassRunner { @@ -21,7 +24,7 @@ class PassRunner { PassRunner(); void AddPass(std::unique_ptr pass); - void Run(IRBuilder &builder); + void Run(IRBuilder &builder, bool debug); private: std::vector> passes_; diff --git a/src/jit/ir/passes/register_allocation_pass.cc b/src/jit/ir/passes/register_allocation_pass.cc index 7f44c7f7..905e7c45 100644 --- a/src/jit/ir/passes/register_allocation_pass.cc +++ b/src/jit/ir/passes/register_allocation_pass.cc @@ -75,6 +75,8 @@ void RegisterSet::PopTailInterval() { } void RegisterSet::InsertInterval(Interval *interval) { + CHECK(interval->start && interval->end && interval->next); + live_[num_live_++] = interval; re::mmheap_push(live_, live_ + num_live_, LiveIntervalSort()); } @@ -90,7 +92,7 @@ RegisterAllocationPass::RegisterAllocationPass(const Backend &backend) RegisterAllocationPass::~RegisterAllocationPass() { delete[] intervals_; } -void RegisterAllocationPass::Run(IRBuilder &builder) { +void RegisterAllocationPass::Run(IRBuilder &builder, bool debug) { PROFILER_RUNTIME("RegisterAllocationPass::Run"); Reset(); @@ -98,40 +100,34 @@ void RegisterAllocationPass::Run(IRBuilder &builder) { AssignOrdinals(builder); for (auto instr : builder.instrs()) { - Value *result = instr->result(); - // only allocate registers for results, assume constants can always be // encoded as immediates or that the backend has registers reserved // for storing the constants - if (!result) { + if (instr->type() == VALUE_V) { continue; } - // sort the value's ref list - result->refs().Sort([](const ValueRef *a, const ValueRef *b) { + // sort the instruction's ref list + instr->uses().Sort([](const Use *a, const Use *b) { return GetOrdinal(a->instr()) < GetOrdinal(b->instr()); }); - // get the live range of the value - ValueRef *start = result->refs().head(); - ValueRef *end = result->refs().tail(); - // expire any old intervals, freeing up the registers they claimed - ExpireOldIntervals(start->instr()); + ExpireOldIntervals(instr); // first, try and reuse the register of one of the incoming arguments - int reg = ReuuseArgRegister(instr, start, end); + int reg = ReuseArgRegister(builder, instr); if (reg == NO_REGISTER) { // else, allocate a new register for the result - reg = AllocFreeRegister(result, start, end); + reg = AllocFreeRegister(instr); if (reg == NO_REGISTER) { // if a register couldn't be allocated, spill a register and try again - reg = AllocBlockedRegister(builder, result, start, end); + reg = AllocBlockedRegister(builder, instr); CHECK_NE(reg, NO_REGISTER, "Failed to allocate register"); } } - result->set_reg(reg); + instr->set_reg(reg); } } @@ -180,7 +176,7 @@ void RegisterAllocationPass::AssignOrdinals(IRBuilder &builder) { } } -void RegisterAllocationPass::ExpireOldIntervals(Instr *start) { +void RegisterAllocationPass::ExpireOldIntervals(Instr *instr) { auto expire_set = [&](RegisterSet &set) { while (true) { Interval *interval = set.HeadInterval(); @@ -190,24 +186,35 @@ void RegisterAllocationPass::ExpireOldIntervals(Instr *start) { // intervals are sorted by their next use, once one fails to expire or // advance, they all will - if (GetOrdinal(interval->next->instr()) >= GetOrdinal(start)) { + if (GetOrdinal(interval->next->instr()) >= GetOrdinal(instr)) { break; } // remove interval from the sorted set set.PopHeadInterval(); - // if there are no other uses, free the register assigned to this - // interval - if (!interval->next->next()) { - set.PushRegister(interval->reg); - } // if there are more uses, advance the next use and reinsert the interval // into the correct position - else { + if (interval->next->next()) { interval->next = interval->next->next(); set.InsertInterval(interval); } + // if there are no more uses, but the register has been reused by + // ReuseArgRegister, requeue the interval at this time + else if (interval->reused) { + Instr *reused = interval->reused; + interval->instr = reused; + interval->reused = nullptr; + interval->start = reused->uses().head(); + interval->end = reused->uses().tail(); + interval->next = interval->start; + set.InsertInterval(interval); + } + // if there are no other uses, free the register assigned to this + // interval + else { + set.PushRegister(interval->reg); + } } }; @@ -220,8 +227,7 @@ void RegisterAllocationPass::ExpireOldIntervals(Instr *start) { // operations where the destination is the first argument. // TODO could reorder arguments for communicative binary ops and do this // with the second argument as well -int RegisterAllocationPass::ReuuseArgRegister(Instr *instr, ValueRef *start, - ValueRef *end) { +int RegisterAllocationPass::ReuseArgRegister(IRBuilder &builder, Instr *instr) { if (!instr->arg0() || instr->arg0()->constant()) { return NO_REGISTER; } @@ -233,7 +239,7 @@ int RegisterAllocationPass::ReuuseArgRegister(Instr *instr, ValueRef *start, // make sure the register can hold the result type const Register &r = registers_[prefered]; - if (!RegisterCanStore(r, instr->result()->type())) { + if (!RegisterCanStore(r, instr->type())) { return NO_REGISTER; } @@ -245,23 +251,18 @@ int RegisterAllocationPass::ReuuseArgRegister(Instr *instr, ValueRef *start, } // the argument's register is not used after the current instruction, so the - // register can be reused for the result. since the interval's current next - // use (arg0 of this instruction) and the next use of the new interval (the - // result of this instruction) share the same ordinal, the interval can be - // hijacked and overwritten without having to reinsert it into the register - // set's sorted interval list - CHECK_EQ(GetOrdinal(interval->next->instr()), GetOrdinal(start->instr())); - interval->start = start; - interval->next = start; - interval->value = instr->result(); - interval->end = end; + // register can be reused for the result. note, since the interval min/max + // heap does not support removal of an arbitrary interval, the interval + // removal must be deferred. since there are no more references, the interval + // will expire on the next call to ExpireOldIntervals, and then immediately + // requeued by setting the reused property + interval->reused = instr; return prefered; } -int RegisterAllocationPass::AllocFreeRegister(Value *value, ValueRef *start, - ValueRef *end) { - RegisterSet &set = GetRegisterSet(value->type()); +int RegisterAllocationPass::AllocFreeRegister(Instr *instr) { + RegisterSet &set = GetRegisterSet(instr->type()); // get the first free register for this value type int reg = set.PopRegister(); @@ -271,10 +272,11 @@ int RegisterAllocationPass::AllocFreeRegister(Value *value, ValueRef *start, // add interval Interval *interval = &intervals_[reg]; - interval->value = value; - interval->start = start; - interval->end = end; - interval->next = start; + interval->instr = instr; + interval->reused = nullptr; + interval->start = instr->uses().head(); + interval->end = instr->uses().tail(); + interval->next = interval->start; interval->reg = reg; set.InsertInterval(interval); @@ -282,75 +284,75 @@ int RegisterAllocationPass::AllocFreeRegister(Value *value, ValueRef *start, } int RegisterAllocationPass::AllocBlockedRegister(IRBuilder &builder, - Value *value, ValueRef *start, - ValueRef *end) { + Instr *instr) { InsertPoint insert_point = builder.GetInsertPoint(); - RegisterSet &set = GetRegisterSet(value->type()); + RegisterSet &set = GetRegisterSet(instr->type()); // spill the register who's next use is furthest away from start Interval *interval = set.TailInterval(); set.PopTailInterval(); - // find the next and prev use of the register. the interval's value needs - // to be spilled to the stack after the previous use, and filled back from - // from the stack before it's next use - ValueRef *next_ref = interval->next; - ValueRef *prev_ref = next_ref->prev(); + // the interval's value needs to be filled back from from the stack before + // its next use + Use *next_ref = interval->next; + Use *prev_ref = next_ref->prev(); CHECK(next_ref, "Register being spilled has no next use, why wasn't it expired?"); - CHECK(prev_ref, - "Register being spilled has no prev use, why is it already live?"); - CHECK_LT(GetOrdinal(prev_ref->instr()), GetOrdinal(next_ref->instr())); // allocate a place on the stack to spill the value - Local *local = builder.AllocLocal(interval->value->type()); + Local *local = builder.AllocLocal(interval->instr->type()); // insert load before next use builder.SetInsertPoint({next_ref->instr()->prev()}); - Value *load_local = builder.LoadLocal(local); - Instr *load_instr = builder.GetInsertPoint().instr; + Instr *load_instr = builder.LoadLocal(local); // assign the load a valid ordinal int load_ordinal = GetOrdinal(load_instr->prev()) + 1; CHECK_LT(load_ordinal, GetOrdinal(load_instr->next())); SetOrdinal(load_instr, load_ordinal); - // update references to interval->value after the next use to use the new + // update references to interval->instr after the next use to use the new // value filled from the stack. this code asssumes that the refs were // previously sorted inside of Run(). while (next_ref) { // cache off next next since calling set_value will modify the linked list // pointers - ValueRef *next_next_ref = next_ref->next(); - next_ref->set_value(load_local); + Use *next_next_ref = next_ref->next(); + next_ref->set_value(load_instr); next_ref = next_next_ref; } - // with all references >= next_ref using the new value, prev_ref->next - // should now be null - CHECK(!prev_ref->next(), "All future references should have been replaced"); - // insert spill after prev use, note that order here is extremely important. - // interval->value's ref list has already been sorted, and when the save + // interval->instr's ref list has already been sorted, and when the save // instruction is created and added as a reference, the sorted order will be // invalidated. because of this, the save instruction needs to be added after // the load instruction has updated the sorted references. - builder.SetInsertPoint({prev_ref->instr()}); - builder.StoreLocal(local, interval->value); - Instr *store_instr = builder.GetInsertPoint().instr; + Instr *after = nullptr; - // since the interval that this save belongs to has now expired, there's no + if (prev_ref) { + // there is a previous reference, insert store after it + CHECK(prev_ref->next() == nullptr, + "All future references should have been replaced"); + after = prev_ref->instr(); + } else { + // there is no previous reference, insert store immediately after definition + CHECK(interval->instr->uses().head() == nullptr, + "All future references should have been replaced"); + after = interval->instr; + } + + builder.SetInsertPoint({after}); + builder.StoreLocal(local, interval->instr); + + // since the interval that this store belongs to has now expired, there's no // need to assign an ordinal to it - // the new store should now be the final reference - CHECK(prev_ref->next() && prev_ref->next()->instr() == store_instr, - "Spill should be the final reference for the interval value"); - - // overwrite the old interval - interval->value = value; - interval->start = start; - interval->next = start; - interval->end = end; + // reuse the old interval + interval->instr = instr; + interval->reused = nullptr; + interval->start = instr->uses().head(); + interval->end = instr->uses().tail(); + interval->next = interval->start; set.InsertInterval(interval); // reset insert point diff --git a/src/jit/ir/passes/register_allocation_pass.h b/src/jit/ir/passes/register_allocation_pass.h index 408a744f..f623015c 100644 --- a/src/jit/ir/passes/register_allocation_pass.h +++ b/src/jit/ir/passes/register_allocation_pass.h @@ -11,10 +11,11 @@ namespace ir { namespace passes { struct Interval { - Value *value; - ValueRef *start; - ValueRef *next; - ValueRef *end; + Instr *instr; + Instr *reused; + Use *start; + Use *end; + Use *next; int reg; }; @@ -48,7 +49,9 @@ class RegisterAllocationPass : public Pass { RegisterAllocationPass(const backend::Backend &backend); ~RegisterAllocationPass(); - void Run(IRBuilder &builder); + const char *name() { return "Register Allocation Pass"; } + + void Run(IRBuilder &builder, bool debug); private: const backend::Register *registers_; @@ -64,11 +67,10 @@ class RegisterAllocationPass : public Pass { void Reset(); void AssignOrdinals(IRBuilder &builder); - void ExpireOldIntervals(Instr *start); - int ReuuseArgRegister(Instr *instr, ValueRef *start, ValueRef *end); - int AllocFreeRegister(Value *value, ValueRef *start, ValueRef *end); - int AllocBlockedRegister(IRBuilder &builder, Value *value, ValueRef *start, - ValueRef *end); + void ExpireOldIntervals(Instr *instr); + int ReuseArgRegister(IRBuilder &builder, Instr *instr); + int AllocFreeRegister(Instr *instr); + int AllocBlockedRegister(IRBuilder &builder, Instr *instr); }; } } diff --git a/src/jit/ir/passes/validate_pass.cc b/src/jit/ir/passes/validate_pass.cc deleted file mode 100644 index f71155f1..00000000 --- a/src/jit/ir/passes/validate_pass.cc +++ /dev/null @@ -1,9 +0,0 @@ -#include "emu/profiler.h" -#include "jit/ir/passes/validate_pass.h" - -using namespace re::jit::ir; -using namespace re::jit::ir::passes; - -void ValidatePass::Run(IRBuilder &builder) { - PROFILER_RUNTIME("ValidatePass::Run"); -} diff --git a/src/jit/ir/passes/validate_pass.h b/src/jit/ir/passes/validate_pass.h deleted file mode 100644 index 5c93d093..00000000 --- a/src/jit/ir/passes/validate_pass.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef VALIDATE_BLOCK_PASS_H -#define VALIDATE_BLOCK_PASS_H - -#include "jit/ir/passes/pass_runner.h" - -namespace re { -namespace jit { -namespace ir { -namespace passes { - -class ValidatePass : public Pass { - public: - void Run(IRBuilder &builder); -}; -} -} -} -} - -#endif diff --git a/test/asm/cmp.s b/test/asm/cmp.s index 476caffa..d1c7d0f9 100644 --- a/test/asm/cmp.s +++ b/test/asm/cmp.s @@ -1,118 +1,3 @@ -test_cmpeq_imm: - # REGISTER_IN r0 13 - cmp/eq #13, r0 - movt r1 - cmp/eq #17, r0 - movt r2 - rts - nop - # REGISTER_OUT r1 1 - # REGISTER_OUT r2 0 - -test_cmpeq: - # REGISTER_IN r0 13 - # REGISTER_IN r1 17 - cmp/eq r0, r0 - movt r2 - cmp/eq r0, r2 - movt r4 - rts - nop - # REGISTER_OUT r2 1 - # REGISTER_OUT r3 0 - -test_cmphs: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 13 - cmp/hs r1, r0 - movt r2 - cmp/hs r1, r1 - movt r3 - cmp/hs r0, r1 - movt r4 - rts - nop - # REGISTER_OUT r2 1 - # REGISTER_OUT r3 1 - # REGISTER_OUT r4 0 - -test_cmpge: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 13 - cmp/ge r1, r0 - movt r2 - cmp/ge r1, r1 - movt r3 - cmp/ge r0, r1 - movt r4 - rts - nop - # REGISTER_OUT r2 0 - # REGISTER_OUT r3 1 - # REGISTER_OUT r4 1 - -test_cmphi: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 13 - cmp/hi r1, r0 - movt r2 - cmp/hi r1, r1 - movt r3 - cmp/hi r0, r1 - movt r4 - rts - nop - # REGISTER_OUT r2 1 - # REGISTER_OUT r3 0 - # REGISTER_OUT r4 0 - -test_cmpgt: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 13 - cmp/gt r1, r0 - movt r2 - cmp/gt r1, r1 - movt r3 - cmp/gt r0, r1 - movt r4 - rts - nop - # REGISTER_OUT r2 0 - # REGISTER_OUT r3 0 - # REGISTER_OUT r4 1 - -test_cmppz: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 0 - # REGISTER_IN r2 1 - cmp/pz r0 - movt r3 - cmp/pz r1 - movt r4 - cmp/pz r2 - movt r5 - rts - nop - # REGISTER_OUT r3 0 - # REGISTER_OUT r4 1 - # REGISTER_OUT r5 1 - -test_cmppl: - # REGISTER_IN r0 -1 - # REGISTER_IN r1 0 - # REGISTER_IN r2 1 - cmp/pl r0 - movt r3 - cmp/pl r1 - movt r4 - cmp/pl r2 - movt r5 - rts - nop - # REGISTER_OUT r3 0 - # REGISTER_OUT r4 0 - # REGISTER_OUT r5 1 - test_cmpstr: # REGISTER_IN r0 0x00000000 # REGISTER_IN r1 0xffffffff @@ -120,12 +5,6 @@ test_cmpstr: # REGISTER_IN r3 0x00ff0000 cmp/str r0, r1 movt r4 - cmp/str r2, r1 - movt r5 - cmp/str r3, r1 - movt r6 rts nop # REGISTER_OUT r4 0 - # REGISTER_OUT r5 0 - # REGISTER_OUT r6 1 diff --git a/test/test_dead_code_elimination_pass.cc b/test/test_dead_code_elimination_pass.cc new file mode 100644 index 00000000..90b42dc7 --- /dev/null +++ b/test/test_dead_code_elimination_pass.cc @@ -0,0 +1,74 @@ +#include +#include +#include "jit/ir/passes/dead_code_elimination_pass.h" +#include "jit/ir/ir_builder.h" +#include "jit/ir/ir_reader.h" +#include "jit/ir/ir_writer.h" + +using namespace re::jit::ir; +using namespace re::jit::ir::passes; + +TEST(DeadCodeEliminationPassTest, Sanity) { + static const char *input = + "i32 %0 = load_context i32 0xbc\n" + "i32 %1 = load_guest i32 %0\n" + "i32 %2 = load_guest i32 0x8c000a10\n" + "i32 %3 = load_guest i32 %2\n" + "i32 %4 = load_context i32 0xc0\n" + "i32 %5 = and i32 %3, i32 %4\n" + "store_context i32 0xb0, i32 %5\n" + "store_guest i32 %2, i32 %5\n" + "i32 %6 = load_context i32 0xe4\n" + "i32 %7 = load_guest i32 %6\n" + "store_context i32 0xb4, i32 %7\n" + "i64 %8 = load_context i32 0x18\n" + "i32 %9 = load_context i32 0x38\n" + "store_context i32 0x38, i32 %7\n" + "i64 %10 = zext i32 %9\n" + "i32 %11 = load_context i32 0x28\n" + "i32 %12 = sub i32 %11, i32 0xa\n" + "store_context i32 0x28, i32 %12\n" + "i32 %13 = load_context i32 0x2c\n" + "i32 %14 = add i32 %13, i32 0x7\n" + "store_context i32 0x2c, i32 %14\n" + "call_external i64 %8, i64 %10\n" + "store_context i32 0x30, i32 0x8c000940\n"; + + static const char *output = + "i32 %0 = load_guest i32 0x8c000a10\n" + "i32 %1 = load_guest i32 %0\n" + "i32 %2 = load_context i32 0xc0\n" + "i32 %3 = and i32 %1, i32 %2\n" + "store_context i32 0xb0, i32 %3\n" + "store_guest i32 %0, i32 %3\n" + "i32 %4 = load_context i32 0xe4\n" + "i32 %5 = load_guest i32 %4\n" + "store_context i32 0xb4, i32 %5\n" + "i64 %6 = load_context i32 0x18\n" + "i32 %7 = load_context i32 0x38\n" + "store_context i32 0x38, i32 %5\n" + "i64 %8 = zext i32 %7\n" + "i32 %9 = load_context i32 0x28\n" + "i32 %10 = sub i32 %9, i32 0xa\n" + "store_context i32 0x28, i32 %10\n" + "i32 %11 = load_context i32 0x2c\n" + "i32 %12 = add i32 %11, i32 0x7\n" + "store_context i32 0x2c, i32 %12\n" + "call_external i64 %6, i64 %8\n" + "store_context i32 0x30, i32 0x8c000940\n"; + + IRBuilder builder; + + IRReader reader; + std::stringstream input_stream(input); + reader.Parse(input_stream, builder); + + DeadCodeEliminationPass pass; + pass.Run(builder, false); + + IRWriter writer; + std::stringstream output_stream; + writer.Print(builder, output_stream); + + ASSERT_STREQ(output_stream.str().c_str(), output); +} diff --git a/test/test_load_store_elimination_pass.cc b/test/test_load_store_elimination_pass.cc index 93e3df84..26171e6f 100644 --- a/test/test_load_store_elimination_pass.cc +++ b/test/test_load_store_elimination_pass.cc @@ -65,7 +65,7 @@ TEST(LoadStoreEliminationPassTest, Aliasing) { reader.Parse(input_stream, builder); LoadStoreEliminationPass pass; - pass.Run(builder); + pass.Run(builder, false); IRWriter writer; std::stringstream output_stream; diff --git a/test/test_sh4.cc b/test/test_sh4.cc index 5df759f1..9b446171 100644 --- a/test/test_sh4.cc +++ b/test/test_sh4.cc @@ -137,10 +137,6 @@ int sh4_num_test_regs = fr0_out, fr1_out, fr2_out, fr3_out, fr4_out, fr5_out, fr6_out, fr7_out, fr8_out, fr9_out, fr10_out, fr11_out, fr12_out, fr13_out, fr14_out, fr15_out, \ xf0_out, xf1_out, xf2_out, xf3_out, xf4_out, xf5_out, xf6_out, xf7_out, xf8_out, xf9_out, xf10_out, xf11_out, xf12_out, xf13_out, xf14_out, xf15_out) \ }; \ - TEST(sh4_interpreter, name) { \ - FLAGS_interpreter = true; \ - RunSH4Test(test_##name); \ - } \ TEST(sh4_x64, name) { \ FLAGS_interpreter = false; \ RunSH4Test(test_##name); \ diff --git a/test/test_sh4.inc b/test/test_sh4.inc index 047fdeac..1d126a8b 100644 --- a/test/test_sh4.inc +++ b/test/test_sh4.inc @@ -21,15 +21,7 @@ TEST_SH4(test_bsr,(uint8_t *)"\x22\x4f\x04\xb0\x01\x70\x03\x70\x26\x4f\x0b\x00\x TEST_SH4(test_bsrf,(uint8_t *)"\x22\x4f\x03\x00\x01\x71\x03\x71\x26\x4f\x0b\x00\x09\x00\x09\x71\x0b\x00\x09\x00",20,0x0,0xbaadf00d,0x8,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) TEST_SH4(test_bt,(uint8_t *)"\x07\x88\x01\x89\x0b\x00\x09\x00\x03\xe1\x0b\x00\x09\x00\x07\x88\x02\x8d\x06\x71\x0b\x00\x09\x00\x07\x71\x0b\x00\x09\x00",30,0x0,0xbaadf00d,0x7,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x3,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) TEST_SH4(test_bts,(uint8_t *)"\x07\x88\x01\x89\x0b\x00\x09\x00\x03\xe1\x0b\x00\x09\x00\x07\x88\x02\x8d\x06\x71\x0b\x00\x09\x00\x07\x71\x0b\x00\x09\x00",30,0xe,0xbaadf00d,0x7,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmpgt,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x48,0xbaadf00d,0xffffffff,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0x0,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmpstr,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x78,0xbaadf00d,0x0,0xffffffff,0xf00000,0xff0000,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0x0,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmphs,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x18,0xbaadf00d,0xffffffff,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x1,0x1,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmppz,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x58,0xbaadf00d,0xffffffff,0x0,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0x1,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmppl,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x68,0xbaadf00d,0xffffffff,0x0,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0x0,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmphi,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x38,0xbaadf00d,0xffffffff,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x1,0x0,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmpge,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x28,0xbaadf00d,0xffffffff,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0x1,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmpeq_imm,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0x0,0xbaadf00d,0xd,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x1,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) -TEST_SH4(test_cmpeq,(uint8_t *)"\x0d\x88\x29\x01\x11\x88\x29\x02\x0b\x00\x09\x00\x00\x30\x29\x02\x00\x32\x29\x04\x0b\x00\x09\x00\x12\x30\x29\x02\x12\x31\x29\x03\x02\x31\x29\x04\x0b\x00\x09\x00\x13\x30\x29\x02\x13\x31\x29\x03\x03\x31\x29\x04\x0b\x00\x09\x00\x16\x30\x29\x02\x16\x31\x29\x03\x06\x31\x29\x04\x0b\x00\x09\x00\x17\x30\x29\x02\x17\x31\x29\x03\x07\x31\x29\x04\x0b\x00\x09\x00\x11\x40\x29\x03\x11\x41\x29\x04\x11\x42\x29\x05\x0b\x00\x09\x00\x15\x40\x29\x03\x15\x41\x29\x04\x15\x42\x29\x05\x0b\x00\x09\x00\x0c\x21\x29\x04\x2c\x21\x29\x05\x3c\x21\x29\x06\x0b\x00\x09\x00",136,0xc,0xbaadf00d,0xd,0x11,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x1,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) +TEST_SH4(test_cmpstr,(uint8_t *)"\x0c\x21\x29\x04\x0b\x00\x09\x00",8,0x0,0xbaadf00d,0x0,0xffffffff,0xf00000,0xff0000,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) TEST_SH4(test_div0s_pdividend_pdivisor,(uint8_t *)"\x0e\x40\x19\x00\x29\x01\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00",50,0x14,0xbaadf00d,0x700000f0,0xfffffffe,0xfffffffc,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) TEST_SH4(test_div0s_ndividend_pdivisor,(uint8_t *)"\x0e\x40\x19\x00\x29\x01\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00",50,0x1e,0xbaadf00d,0x700000f0,0x2,0xfffffffc,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x1,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d) TEST_SH4(test_div0s_ndividend_ndivisor,(uint8_t *)"\x0e\x40\x19\x00\x29\x01\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00\x0e\x40\x17\x22\x29\x03\x0b\x00\x09\x00",50,0xa,0xbaadf00d,0x700000f0,0x2,0x4,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0x0,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d,0xbaadf00d)