mirror of https://github.com/inolen/redream.git
consolidated comparison ir ops into OP_ICMP and OP_FCMP
This commit is contained in:
parent
d26b7a092f
commit
8b94d8e9f6
|
@ -158,7 +158,7 @@ set(REDREAM_SOURCES
|
|||
src/jit/ir/ir_builder.cc
|
||||
src/jit/ir/ir_reader.cc
|
||||
src/jit/ir/ir_writer.cc
|
||||
src/jit/ir/passes/constant_propagation_pass.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
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include "jit/backend/x64/x64_backend.h"
|
||||
#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/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"
|
||||
|
@ -33,7 +33,7 @@ SH4CodeCache::SH4CodeCache(Memory *memory, void *guest_ctx,
|
|||
|
||||
// setup optimization passes
|
||||
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 ConstantPropagationPass()));
|
||||
pass_runner_.AddPass(std::unique_ptr<Pass>(new DeadCodeEliminationPass()));
|
||||
pass_runner_.AddPass(
|
||||
std::unique_ptr<Pass>(new RegisterAllocationPass(*backend_)));
|
||||
|
|
|
@ -786,18 +786,6 @@ EMITTER(STORE_LOCAL) {
|
|||
}
|
||||
}
|
||||
|
||||
EMITTER(BITCAST) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (result.getIdx() == a.getIdx()) {
|
||||
// noop if already the same register
|
||||
return;
|
||||
}
|
||||
|
||||
e.mov(result.cvt64(), a.cvt64());
|
||||
}
|
||||
|
||||
EMITTER(CAST) {
|
||||
if (IsFloatType(instr->type())) {
|
||||
const Xbyak::Xmm result = e.GetXMMRegister(instr);
|
||||
|
@ -869,6 +857,39 @@ EMITTER(ZEXT) {
|
|||
}
|
||||
}
|
||||
|
||||
EMITTER(TRUNC) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (result.getIdx() == a.getIdx()) {
|
||||
// noop if already the same register. note, this means the high order bits
|
||||
// of the result won't be cleared, but I believe that is fine
|
||||
return;
|
||||
}
|
||||
|
||||
Xbyak::Reg truncated = a;
|
||||
switch (instr->type()) {
|
||||
case VALUE_I8:
|
||||
truncated = a.cvt8();
|
||||
break;
|
||||
case VALUE_I16:
|
||||
truncated = a.cvt16();
|
||||
break;
|
||||
case VALUE_I32:
|
||||
truncated = a.cvt32();
|
||||
break;
|
||||
default:
|
||||
LOG_FATAL("Unexpected value type");
|
||||
}
|
||||
|
||||
if (truncated.isBit(32)) {
|
||||
// mov will automatically zero fill the upper 32-bits
|
||||
e.mov(result, truncated);
|
||||
} else {
|
||||
e.movzx(result.cvt32(), truncated);
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(SELECT) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg cond = e.GetRegister(instr->arg0());
|
||||
|
@ -880,224 +901,106 @@ EMITTER(SELECT) {
|
|||
e.cmovz(result.cvt32(), b);
|
||||
}
|
||||
|
||||
EMITTER(EQ) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
e.sete(result);
|
||||
}
|
||||
|
||||
EMITTER(NE) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
}
|
||||
|
||||
e.setne(result);
|
||||
}
|
||||
|
||||
EMITTER(SGE) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
|
||||
e.setae(result);
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
|
||||
e.setge(result);
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(SGT) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
|
||||
e.seta(result);
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
|
||||
e.setg(result);
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(UGE) {
|
||||
EMITTER(CMP) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
e.cmp(a, static_cast<uint32_t>(instr->arg1()->GetZExtValue()));
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
|
||||
e.setae(result);
|
||||
}
|
||||
CmpType cmp = static_cast<CmpType>(instr->arg2()->i32());
|
||||
|
||||
EMITTER(UGT) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
switch (cmp) {
|
||||
case CMP_EQ:
|
||||
e.sete(result);
|
||||
break;
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
case CMP_NE:
|
||||
e.setne(result);
|
||||
break;
|
||||
|
||||
e.seta(result);
|
||||
}
|
||||
case CMP_SGE:
|
||||
e.setge(result);
|
||||
break;
|
||||
|
||||
EMITTER(SLE) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
case CMP_SGT:
|
||||
e.setg(result);
|
||||
break;
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
case CMP_UGE:
|
||||
e.setae(result);
|
||||
break;
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
case CMP_UGT:
|
||||
e.seta(result);
|
||||
break;
|
||||
|
||||
e.setbe(result);
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
case CMP_SLE:
|
||||
e.setle(result);
|
||||
break;
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
case CMP_SLT:
|
||||
e.setl(result);
|
||||
break;
|
||||
|
||||
e.setle(result);
|
||||
case CMP_ULE:
|
||||
e.setbe(result);
|
||||
break;
|
||||
|
||||
case CMP_ULT:
|
||||
e.setb(result);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unexpected comparison type");
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(SLT) {
|
||||
EMITTER(FCMP) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (IsFloatType(instr->arg0()->type())) {
|
||||
const Xbyak::Xmm a = e.GetXMMRegister(instr->arg0());
|
||||
const Xbyak::Xmm b = e.GetXMMRegister(instr->arg1());
|
||||
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
e.comisd(a, b);
|
||||
}
|
||||
|
||||
e.setb(result);
|
||||
if (instr->arg0()->type() == VALUE_F32) {
|
||||
e.comiss(a, b);
|
||||
} else {
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
}
|
||||
|
||||
e.setl(result);
|
||||
}
|
||||
}
|
||||
|
||||
EMITTER(ULE) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
e.comisd(a, b);
|
||||
}
|
||||
|
||||
e.setbe(result);
|
||||
}
|
||||
CmpType cmp = static_cast<CmpType>(instr->arg2()->i32());
|
||||
|
||||
EMITTER(ULT) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||
switch (cmp) {
|
||||
case CMP_EQ:
|
||||
e.sete(result);
|
||||
break;
|
||||
|
||||
if (e.CanEncodeAsImmediate(instr->arg1())) {
|
||||
e.cmp(a, (uint32_t)instr->arg1()->GetZExtValue());
|
||||
} else {
|
||||
const Xbyak::Reg b = e.GetRegister(instr->arg1());
|
||||
e.cmp(a, b);
|
||||
case CMP_NE:
|
||||
e.setne(result);
|
||||
break;
|
||||
|
||||
case CMP_SGE:
|
||||
e.setae(result);
|
||||
break;
|
||||
|
||||
case CMP_SGT:
|
||||
e.seta(result);
|
||||
break;
|
||||
|
||||
case CMP_SLE:
|
||||
e.setbe(result);
|
||||
break;
|
||||
|
||||
case CMP_SLT:
|
||||
e.setb(result);
|
||||
break;
|
||||
|
||||
default:
|
||||
LOG_FATAL("Unexpected comparison type");
|
||||
}
|
||||
|
||||
e.setb(result);
|
||||
}
|
||||
|
||||
EMITTER(ADD) {
|
||||
|
|
|
@ -606,7 +606,7 @@ EMITTER(ADDV) {
|
|||
EMITTER(CMPEQI) {
|
||||
Value *imm = b.AllocConstant((uint32_t)(int32_t)(int8_t)i.imm);
|
||||
Value *r0 = b.LoadRegister(0, VALUE_I32);
|
||||
b.StoreT(b.EQ(r0, imm));
|
||||
b.StoreT(b.CmpEQ(r0, imm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -615,7 +615,7 @@ EMITTER(CMPEQI) {
|
|||
EMITTER(CMPEQ) {
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.EQ(rn, rm));
|
||||
b.StoreT(b.CmpEQ(rn, rm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -624,7 +624,7 @@ EMITTER(CMPEQ) {
|
|||
EMITTER(CMPHS) {
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.UGE(rn, rm));
|
||||
b.StoreT(b.CmpUGE(rn, rm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -633,7 +633,7 @@ EMITTER(CMPHS) {
|
|||
EMITTER(CMPGE) {
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.SGE(rn, rm));
|
||||
b.StoreT(b.CmpSGE(rn, rm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -642,7 +642,7 @@ EMITTER(CMPGE) {
|
|||
EMITTER(CMPHI) {
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.UGT(rn, rm));
|
||||
b.StoreT(b.CmpUGT(rn, rm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -651,7 +651,7 @@ EMITTER(CMPHI) {
|
|||
EMITTER(CMPGT) {
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.SGT(rn, rm));
|
||||
b.StoreT(b.CmpSGT(rn, rm));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -659,7 +659,7 @@ EMITTER(CMPGT) {
|
|||
// CMP/PZ Rn
|
||||
EMITTER(CMPPZ) {
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.SGE(rn, b.AllocConstant(0)));
|
||||
b.StoreT(b.CmpSGE(rn, b.AllocConstant(0)));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -667,7 +667,7 @@ EMITTER(CMPPZ) {
|
|||
// CMP/PL Rn
|
||||
EMITTER(CMPPL) {
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
b.StoreT(b.SGT(rn, b.AllocConstant(0)));
|
||||
b.StoreT(b.CmpSGT(rn, b.AllocConstant(0)));
|
||||
}
|
||||
|
||||
// code cycles t-bit
|
||||
|
@ -680,13 +680,13 @@ EMITTER(CMPSTR) {
|
|||
|
||||
// if any diff is zero, the bytes match
|
||||
Value *b4_eq =
|
||||
b.EQ(b.And(diff, b.AllocConstant(0xff000000)), b.AllocConstant(0));
|
||||
b.CmpEQ(b.And(diff, b.AllocConstant(0xff000000)), b.AllocConstant(0));
|
||||
Value *b3_eq =
|
||||
b.EQ(b.And(diff, b.AllocConstant(0x00ff0000)), b.AllocConstant(0));
|
||||
b.CmpEQ(b.And(diff, b.AllocConstant(0x00ff0000)), b.AllocConstant(0));
|
||||
Value *b2_eq =
|
||||
b.EQ(b.And(diff, b.AllocConstant(0x0000ff00)), b.AllocConstant(0));
|
||||
b.CmpEQ(b.And(diff, b.AllocConstant(0x0000ff00)), b.AllocConstant(0));
|
||||
Value *b1_eq =
|
||||
b.EQ(b.And(diff, b.AllocConstant(0x000000ff)), b.AllocConstant(0));
|
||||
b.CmpEQ(b.And(diff, b.AllocConstant(0x000000ff)), b.AllocConstant(0));
|
||||
|
||||
b.StoreT(b.Or(b.Or(b.Or(b1_eq, b2_eq), b3_eq), b4_eq));
|
||||
}
|
||||
|
@ -752,8 +752,8 @@ EMITTER(DMULS) {
|
|||
Value *rn = b.SExt(b.LoadRegister(i.Rn, VALUE_I32), VALUE_I64);
|
||||
|
||||
Value *p = b.SMul(rm, rn);
|
||||
Value *low = b.Bitcast(p, VALUE_I32);
|
||||
Value *high = b.Bitcast(b.LShr(p, 32), VALUE_I32);
|
||||
Value *low = b.Trunc(p, VALUE_I32);
|
||||
Value *high = b.Trunc(b.LShr(p, 32), VALUE_I32);
|
||||
|
||||
b.StoreContext(offsetof(SH4Context, macl), low);
|
||||
b.StoreContext(offsetof(SH4Context, mach), high);
|
||||
|
@ -765,8 +765,8 @@ EMITTER(DMULU) {
|
|||
Value *rn = b.ZExt(b.LoadRegister(i.Rn, VALUE_I32), VALUE_I64);
|
||||
|
||||
Value *p = b.UMul(rm, rn);
|
||||
Value *low = b.Bitcast(p, VALUE_I32);
|
||||
Value *high = b.Bitcast(b.LShr(p, 32), VALUE_I32);
|
||||
Value *low = b.Trunc(p, VALUE_I32);
|
||||
Value *high = b.Trunc(b.LShr(p, 32), VALUE_I32);
|
||||
|
||||
b.StoreContext(offsetof(SH4Context, macl), low);
|
||||
b.StoreContext(offsetof(SH4Context, mach), high);
|
||||
|
@ -777,7 +777,7 @@ EMITTER(DT) {
|
|||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *v = b.Sub(rn, b.AllocConstant(1));
|
||||
b.StoreRegister(i.Rn, v);
|
||||
b.StoreT(b.EQ(v, b.AllocConstant(0)));
|
||||
b.StoreT(b.CmpEQ(v, b.AllocConstant(0)));
|
||||
}
|
||||
|
||||
// EXTS.B Rm,Rn
|
||||
|
@ -934,21 +934,21 @@ EMITTER(TAS) {
|
|||
Value *addr = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *v = b.LoadGuest(addr, VALUE_I8);
|
||||
b.StoreGuest(addr, b.Or(v, b.AllocConstant((uint8_t)0x80)));
|
||||
b.StoreT(b.EQ(v, b.AllocConstant((uint8_t)0)));
|
||||
b.StoreT(b.CmpEQ(v, b.AllocConstant((uint8_t)0)));
|
||||
}
|
||||
|
||||
// TST Rm,Rn
|
||||
EMITTER(TST) {
|
||||
Value *rn = b.LoadRegister(i.Rn, VALUE_I32);
|
||||
Value *rm = b.LoadRegister(i.Rm, VALUE_I32);
|
||||
b.StoreT(b.EQ(b.And(rn, rm), b.AllocConstant(0)));
|
||||
b.StoreT(b.CmpEQ(b.And(rn, rm), b.AllocConstant(0)));
|
||||
}
|
||||
|
||||
// TST #imm,R0
|
||||
EMITTER(TSTI) {
|
||||
Value *r0 = b.LoadRegister(0, VALUE_I32);
|
||||
Value *imm = b.AllocConstant((uint32_t)i.imm);
|
||||
b.StoreT(b.EQ(b.And(r0, imm), b.AllocConstant((uint32_t)0)));
|
||||
b.StoreT(b.CmpEQ(b.And(r0, imm), b.AllocConstant((uint32_t)0)));
|
||||
}
|
||||
|
||||
// TST.B #imm,@(R0,GBR)
|
||||
|
@ -956,7 +956,7 @@ EMITTER(TSTB) {
|
|||
Value *addr = b.Add(b.LoadRegister(0, VALUE_I32), b.LoadGBR());
|
||||
Value *v = b.LoadGuest(addr, VALUE_I8);
|
||||
Value *imm = b.AllocConstant((uint8_t)i.imm);
|
||||
b.StoreT(b.EQ(b.And(v, imm), b.AllocConstant((uint8_t)0)));
|
||||
b.StoreT(b.CmpEQ(b.And(v, imm), b.AllocConstant((uint8_t)0)));
|
||||
}
|
||||
|
||||
// XOR Rm,Rn
|
||||
|
@ -1784,10 +1784,10 @@ EMITTER(FCMPEQ) {
|
|||
int n = i.Rn & 0xe;
|
||||
int m = i.Rm & 0xe;
|
||||
b.StoreT(
|
||||
b.EQ(b.LoadRegisterF(n, VALUE_F64), b.LoadRegisterF(m, VALUE_F64)));
|
||||
b.FCmpEQ(b.LoadRegisterF(n, VALUE_F64), b.LoadRegisterF(m, VALUE_F64)));
|
||||
} else {
|
||||
b.StoreT(b.EQ(b.LoadRegisterF(i.Rn, VALUE_F32),
|
||||
b.LoadRegisterF(i.Rm, VALUE_F32)));
|
||||
b.StoreT(b.FCmpEQ(b.LoadRegisterF(i.Rn, VALUE_F32),
|
||||
b.LoadRegisterF(i.Rm, VALUE_F32)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1798,10 +1798,10 @@ EMITTER(FCMPGT) {
|
|||
int n = i.Rn & 0xe;
|
||||
int m = i.Rm & 0xe;
|
||||
b.StoreT(
|
||||
b.SGT(b.LoadRegisterF(n, VALUE_F64), b.LoadRegisterF(m, VALUE_F64)));
|
||||
b.FCmpGT(b.LoadRegisterF(n, VALUE_F64), b.LoadRegisterF(m, VALUE_F64)));
|
||||
} else {
|
||||
b.StoreT(b.SGT(b.LoadRegisterF(i.Rn, VALUE_F32),
|
||||
b.LoadRegisterF(i.Rm, VALUE_F32)));
|
||||
b.StoreT(b.FCmpGT(b.LoadRegisterF(i.Rn, VALUE_F32),
|
||||
b.LoadRegisterF(i.Rm, VALUE_F32)));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1898,7 +1898,7 @@ EMITTER(FTRC) {
|
|||
if (fpu.double_pr) {
|
||||
int m = i.Rm & 0xe;
|
||||
Value *dpv =
|
||||
b.Bitcast(b.Cast(b.LoadRegisterF(m, VALUE_F64), VALUE_I64), VALUE_I32);
|
||||
b.Trunc(b.Cast(b.LoadRegisterF(m, VALUE_F64), VALUE_I64), VALUE_I32);
|
||||
b.StoreContext(offsetof(SH4Context, fpul), dpv);
|
||||
} else {
|
||||
Value *spv = b.Cast(b.LoadRegisterF(i.Rm, VALUE_F32), VALUE_I32);
|
||||
|
|
|
@ -160,15 +160,6 @@ void IRBuilder::StoreLocal(Local *local, Value *v) {
|
|||
instr->set_arg1(v);
|
||||
}
|
||||
|
||||
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, dest_type);
|
||||
instr->set_arg0(v);
|
||||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::Cast(Value *v, ValueType dest_type) {
|
||||
CHECK((IsIntType(v->type()) && IsFloatType(dest_type)) ||
|
||||
(IsFloatType(v->type()) && IsIntType(dest_type)));
|
||||
|
@ -194,11 +185,19 @@ Instr *IRBuilder::ZExt(Value *v, ValueType dest_type) {
|
|||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::Trunc(Value *v, ValueType dest_type) {
|
||||
CHECK(IsIntType(v->type()) && IsIntType(dest_type));
|
||||
|
||||
Instr *instr = AppendInstr(OP_TRUNC, dest_type);
|
||||
instr->set_arg0(v);
|
||||
return instr;
|
||||
}
|
||||
|
||||
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));
|
||||
cond = CmpNE(cond, AllocConstant(0));
|
||||
}
|
||||
|
||||
Instr *instr = AppendInstr(OP_SELECT, t->type());
|
||||
|
@ -208,99 +207,59 @@ Instr *IRBuilder::Select(Value *cond, Value *t, Value *f) {
|
|||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::EQ(Value *a, Value *b) {
|
||||
Instr *IRBuilder::Cmp(Value *a, Value *b, CmpType type) {
|
||||
CHECK(IsIntType(a->type()));
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
|
||||
Instr *instr = AppendInstr(OP_EQ, VALUE_I8);
|
||||
Instr *instr = AppendInstr(OP_CMP, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
instr->set_arg2(AllocConstant(type));
|
||||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::NE(Value *a, Value *b) {
|
||||
Instr *IRBuilder::CmpEQ(Value *a, Value *b) { return Cmp(a, b, CMP_EQ); }
|
||||
|
||||
Instr *IRBuilder::CmpNE(Value *a, Value *b) { return Cmp(a, b, CMP_NE); }
|
||||
|
||||
Instr *IRBuilder::CmpSGE(Value *a, Value *b) { return Cmp(a, b, CMP_SGE); }
|
||||
|
||||
Instr *IRBuilder::CmpSGT(Value *a, Value *b) { return Cmp(a, b, CMP_SGT); }
|
||||
|
||||
Instr *IRBuilder::CmpUGE(Value *a, Value *b) { return Cmp(a, b, CMP_UGE); }
|
||||
|
||||
Instr *IRBuilder::CmpUGT(Value *a, Value *b) { return Cmp(a, b, CMP_UGT); }
|
||||
|
||||
Instr *IRBuilder::CmpSLE(Value *a, Value *b) { return Cmp(a, b, CMP_SLE); }
|
||||
|
||||
Instr *IRBuilder::CmpSLT(Value *a, Value *b) { return Cmp(a, b, CMP_SLT); }
|
||||
|
||||
Instr *IRBuilder::CmpULE(Value *a, Value *b) { return Cmp(a, b, CMP_ULE); }
|
||||
|
||||
Instr *IRBuilder::CmpULT(Value *a, Value *b) { return Cmp(a, b, CMP_ULT); }
|
||||
|
||||
Instr *IRBuilder::FCmp(Value *a, Value *b, CmpType type) {
|
||||
CHECK(IsFloatType(a->type()));
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
|
||||
Instr *instr = AppendInstr(OP_NE, VALUE_I8);
|
||||
Instr *instr = AppendInstr(OP_FCMP, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
instr->set_arg2(AllocConstant(type));
|
||||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::SGE(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
Instr *IRBuilder::FCmpEQ(Value *a, Value *b) { return FCmp(a, b, CMP_EQ); }
|
||||
|
||||
Instr *instr = AppendInstr(OP_SGE, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
Instr *IRBuilder::FCmpNE(Value *a, Value *b) { return FCmp(a, b, CMP_NE); }
|
||||
|
||||
Instr *IRBuilder::SGT(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
Instr *IRBuilder::FCmpGE(Value *a, Value *b) { return FCmp(a, b, CMP_SGE); }
|
||||
|
||||
Instr *instr = AppendInstr(OP_SGT, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
Instr *IRBuilder::FCmpGT(Value *a, Value *b) { return FCmp(a, b, CMP_SGT); }
|
||||
|
||||
Instr *IRBuilder::UGE(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
CHECK_EQ(true, IsIntType(a->type()) && IsIntType(b->type()));
|
||||
Instr *IRBuilder::FCmpLE(Value *a, Value *b) { return FCmp(a, b, CMP_SLE); }
|
||||
|
||||
Instr *instr = AppendInstr(OP_UGE, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
|
||||
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_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::SLE(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
|
||||
Instr *instr = AppendInstr(OP_SLE, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
|
||||
Instr *IRBuilder::SLT(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
|
||||
Instr *instr = AppendInstr(OP_SLT, VALUE_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
|
||||
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_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
|
||||
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_I8);
|
||||
instr->set_arg0(a);
|
||||
instr->set_arg1(b);
|
||||
return instr;
|
||||
}
|
||||
Instr *IRBuilder::FCmpLT(Value *a, Value *b) { return FCmp(a, b, CMP_SLT); }
|
||||
|
||||
Instr *IRBuilder::Add(Value *a, Value *b) {
|
||||
CHECK_EQ(a->type(), b->type());
|
||||
|
|
|
@ -292,6 +292,19 @@ class Instr : public Value, public IntrusiveListNode<Instr> {
|
|||
//
|
||||
// IRBuilder
|
||||
//
|
||||
enum CmpType {
|
||||
CMP_EQ,
|
||||
CMP_NE,
|
||||
CMP_SGE,
|
||||
CMP_SGT,
|
||||
CMP_UGE,
|
||||
CMP_UGT,
|
||||
CMP_SLE,
|
||||
CMP_SLT,
|
||||
CMP_ULE,
|
||||
CMP_ULT
|
||||
};
|
||||
|
||||
typedef void (*ExternalFn)(void *);
|
||||
|
||||
struct InsertPoint {
|
||||
|
@ -333,23 +346,29 @@ class IRBuilder {
|
|||
void StoreLocal(Local *local, Value *v);
|
||||
|
||||
// cast / conversion operations
|
||||
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);
|
||||
Instr *Trunc(Value *v, ValueType dest_type);
|
||||
|
||||
// conditionals
|
||||
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);
|
||||
Instr *CmpEQ(Value *a, Value *b);
|
||||
Instr *CmpNE(Value *a, Value *b);
|
||||
Instr *CmpSGE(Value *a, Value *b);
|
||||
Instr *CmpSGT(Value *a, Value *b);
|
||||
Instr *CmpUGE(Value *a, Value *b);
|
||||
Instr *CmpUGT(Value *a, Value *b);
|
||||
Instr *CmpSLE(Value *a, Value *b);
|
||||
Instr *CmpSLT(Value *a, Value *b);
|
||||
Instr *CmpULE(Value *a, Value *b);
|
||||
Instr *CmpULT(Value *a, Value *b);
|
||||
Instr *FCmpEQ(Value *a, Value *b);
|
||||
Instr *FCmpNE(Value *a, Value *b);
|
||||
Instr *FCmpGE(Value *a, Value *b);
|
||||
Instr *FCmpGT(Value *a, Value *b);
|
||||
Instr *FCmpLE(Value *a, Value *b);
|
||||
Instr *FCmpLT(Value *a, Value *b);
|
||||
|
||||
// math operators
|
||||
Instr *Add(Value *a, Value *b);
|
||||
|
@ -397,6 +416,9 @@ class IRBuilder {
|
|||
Instr *AppendInstr(Op op);
|
||||
Instr *AppendInstr(Op op, ValueType result_type);
|
||||
|
||||
Instr *Cmp(Value *a, Value *b, CmpType type);
|
||||
Instr *FCmp(Value *a, Value *b, CmpType type);
|
||||
|
||||
Arena arena_;
|
||||
IntrusiveList<Instr> instrs_;
|
||||
Instr *current_instr_;
|
||||
|
|
|
@ -6,21 +6,13 @@ IR_OP(LOAD_CONTEXT)
|
|||
IR_OP(STORE_CONTEXT)
|
||||
IR_OP(LOAD_LOCAL)
|
||||
IR_OP(STORE_LOCAL)
|
||||
IR_OP(BITCAST)
|
||||
IR_OP(TRUNC)
|
||||
IR_OP(CAST)
|
||||
IR_OP(SEXT)
|
||||
IR_OP(ZEXT)
|
||||
IR_OP(SELECT)
|
||||
IR_OP(EQ)
|
||||
IR_OP(NE)
|
||||
IR_OP(SGE)
|
||||
IR_OP(SGT)
|
||||
IR_OP(UGE)
|
||||
IR_OP(UGT)
|
||||
IR_OP(SLE)
|
||||
IR_OP(SLT)
|
||||
IR_OP(ULE)
|
||||
IR_OP(ULT)
|
||||
IR_OP(CMP)
|
||||
IR_OP(FCMP)
|
||||
IR_OP(ADD)
|
||||
IR_OP(SUB)
|
||||
IR_OP(SMUL)
|
||||
|
|
Loading…
Reference in New Issue