mirror of https://github.com/inolen/redream.git
make Instr inherit from value, removing result property
updated register allocation to account for the fact that the result is no longer a part of the reference set added basic dead code elimination pass
This commit is contained in:
parent
f936b47b2b
commit
d234f630f1
|
@ -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
|
||||
|
|
|
@ -7,22 +7,19 @@
|
|||
namespace re {
|
||||
|
||||
template <typename T>
|
||||
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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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<Pass>(new ValidatePass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new LoadStoreEliminationPass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new ConstantPropagationPass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new DeadCodeEliminationPass()));
|
||||
pass_runner_.AddPass(
|
||||
std::unique_ptr<Pass>(new RegisterAllocationPass(*backend_)));
|
||||
|
||||
|
@ -90,7 +90,7 @@ SH4BlockEntry *SH4CodeCache::CompileBlock(uint32_t addr, int max_instrs) {
|
|||
// compile the SH4 into IR
|
||||
std::unique_ptr<IRBuilder> 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);
|
||||
|
|
|
@ -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<uint64_t>(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<void *>(
|
||||
static_cast<uint8_t (*)(Memory *, uint32_t)>(&Memory::R8));
|
||||
|
@ -499,7 +494,7 @@ EMITTER(LOAD_GUEST) {
|
|||
e.mov(e.r10, reinterpret_cast<uint64_t>(e.guest_ctx()));
|
||||
e.mov(e.r11, reinterpret_cast<uint64_t>(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());
|
||||
|
||||
|
|
|
@ -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<Instr>();
|
||||
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;
|
||||
|
|
|
@ -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<const Value *>(this)->f64(); }
|
||||
|
||||
const IntrusiveList<ValueRef> &refs() const { return refs_; }
|
||||
IntrusiveList<ValueRef> &refs() { return refs_; }
|
||||
const IntrusiveList<Use> &uses() const { return refs_; }
|
||||
IntrusiveList<Use> &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<ValueRef> refs_;
|
||||
IntrusiveList<Use> 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<ValueRef> {
|
||||
// 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<Use> {
|
||||
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<VALUE_F64> {
|
|||
};
|
||||
|
||||
// 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<Local> {
|
||||
public:
|
||||
Local(ValueType ty, Value *offset);
|
||||
|
@ -252,9 +255,9 @@ class Local : public IntrusiveListNode<Local> {
|
|||
//
|
||||
// instructions
|
||||
//
|
||||
class Instr : public IntrusiveListNode<Instr> {
|
||||
class Instr : public Value, public IntrusiveListNode<Instr> {
|
||||
public:
|
||||
Instr(Op op);
|
||||
Instr(Op op, ValueType result_type);
|
||||
~Instr();
|
||||
|
||||
Op op() const { return op_; }
|
||||
|
@ -271,20 +274,25 @@ class Instr : public IntrusiveListNode<Instr> {
|
|||
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<Instr> instrs_;
|
||||
IntrusiveList<Local> locals_;
|
||||
Instr *current_instr_;
|
||||
};
|
||||
|
||||
inline const Instr *Value::def() const {
|
||||
CHECK(!constant_);
|
||||
return static_cast<const Instr *>(this);
|
||||
}
|
||||
|
||||
inline Instr *Value::def() {
|
||||
CHECK(!constant_);
|
||||
return static_cast<Instr *>(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -55,15 +55,15 @@ int fold_masks[NUM_OPS];
|
|||
#define ARG1_UNSIGNED() static_cast<typename A1::unsigned_type>(ARG1())
|
||||
#define ARG2_UNSIGNED() static_cast<typename A1::unsigned_type>(ARG2())
|
||||
#define RESULT(expr) \
|
||||
instr->result()->ReplaceRefsWith( \
|
||||
instr->ReplaceRefsWith( \
|
||||
builder.AllocConstant(static_cast<typename R::signed_type>(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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -11,10 +11,20 @@ void PassRunner::AddPass(std::unique_ptr<Pass> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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> pass);
|
||||
void Run(IRBuilder &builder);
|
||||
void Run(IRBuilder &builder, bool debug);
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<Pass>> passes_;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
|
@ -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
|
121
test/asm/cmp.s
121
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
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
#include <sstream>
|
||||
#include <gtest/gtest.h>
|
||||
#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);
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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); \
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue