consolidated comparison ir ops into OP_ICMP and OP_FCMP

This commit is contained in:
Anthony Pesch 2016-03-23 01:37:27 -07:00
parent d26b7a092f
commit 8b94d8e9f6
7 changed files with 214 additions and 338 deletions

View File

@ -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

View File

@ -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_)));

View File

@ -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) {

View File

@ -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);

View File

@ -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());

View File

@ -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_;

View File

@ -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)