mirror of https://github.com/inolen/redream.git
basic vectored types support for FIPR and FTRV
This commit is contained in:
parent
38597832e6
commit
4822ffab43
|
@ -73,8 +73,16 @@ const Register x64_registers[] = {
|
||||||
reinterpret_cast<const void *>(&Xbyak::util::xmm9)},
|
reinterpret_cast<const void *>(&Xbyak::util::xmm9)},
|
||||||
{"xmm10", ir::VALUE_FLOAT_MASK,
|
{"xmm10", ir::VALUE_FLOAT_MASK,
|
||||||
reinterpret_cast<const void *>(&Xbyak::util::xmm10)},
|
reinterpret_cast<const void *>(&Xbyak::util::xmm10)},
|
||||||
{"xmm11", ir::VALUE_FLOAT_MASK,
|
{"xmm11", ir::VALUE_VECTOR_MASK,
|
||||||
reinterpret_cast<const void *>(&Xbyak::util::xmm11)}};
|
reinterpret_cast<const void *>(&Xbyak::util::xmm11)},
|
||||||
|
{"xmm12", ir::VALUE_VECTOR_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm12)},
|
||||||
|
{"xmm13", ir::VALUE_VECTOR_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm13)},
|
||||||
|
{"xmm14", ir::VALUE_VECTOR_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm14)},
|
||||||
|
{"xmm15", ir::VALUE_VECTOR_MASK,
|
||||||
|
reinterpret_cast<const void *>(&Xbyak::util::xmm15)}};
|
||||||
|
|
||||||
const int x64_num_registers = sizeof(x64_registers) / sizeof(Register);
|
const int x64_num_registers = sizeof(x64_registers) / sizeof(Register);
|
||||||
|
|
||||||
|
|
|
@ -577,7 +577,18 @@ EMITTER(STORE_GUEST) {
|
||||||
EMITTER(LOAD_CONTEXT) {
|
EMITTER(LOAD_CONTEXT) {
|
||||||
int offset = instr->arg0()->i32();
|
int offset = instr->arg0()->i32();
|
||||||
|
|
||||||
if (IsFloatType(instr->type())) {
|
if (IsVectorType(instr->type())) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
|
||||||
|
switch (instr->type()) {
|
||||||
|
case VALUE_V128:
|
||||||
|
e.movups(result, e.ptr[e.r14 + offset]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_FATAL("Unexpected result type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (IsFloatType(instr->type())) {
|
||||||
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
|
||||||
switch (instr->type()) {
|
switch (instr->type()) {
|
||||||
|
@ -638,7 +649,18 @@ EMITTER(STORE_CONTEXT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (IsFloatType(instr->arg1()->type())) {
|
if (IsVectorType(instr->arg1()->type())) {
|
||||||
|
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
|
switch (instr->arg1()->type()) {
|
||||||
|
case VALUE_V128:
|
||||||
|
e.vmovups(e.ptr[e.r14 + offset], src);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_FATAL("Unexpected result type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (IsFloatType(instr->arg1()->type())) {
|
||||||
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
switch (instr->arg1()->type()) {
|
switch (instr->arg1()->type()) {
|
||||||
|
@ -679,7 +701,18 @@ EMITTER(STORE_CONTEXT) {
|
||||||
EMITTER(LOAD_LOCAL) {
|
EMITTER(LOAD_LOCAL) {
|
||||||
int offset = STACK_OFFSET_LOCALS + instr->arg0()->i32();
|
int offset = STACK_OFFSET_LOCALS + instr->arg0()->i32();
|
||||||
|
|
||||||
if (IsFloatType(instr->type())) {
|
if (IsVectorType(instr->type())) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
|
||||||
|
switch (instr->type()) {
|
||||||
|
case VALUE_V128:
|
||||||
|
e.movups(result, e.ptr[e.rsp + offset]);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_FATAL("Unexpected result type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (IsFloatType(instr->type())) {
|
||||||
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
|
||||||
switch (instr->type()) {
|
switch (instr->type()) {
|
||||||
|
@ -721,7 +754,18 @@ EMITTER(STORE_LOCAL) {
|
||||||
|
|
||||||
CHECK(!instr->arg1()->constant());
|
CHECK(!instr->arg1()->constant());
|
||||||
|
|
||||||
if (IsFloatType(instr->arg1()->type())) {
|
if (IsVectorType(instr->arg1()->type())) {
|
||||||
|
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
|
switch (instr->arg1()->type()) {
|
||||||
|
case VALUE_V128:
|
||||||
|
e.vmovups(e.ptr[e.rsp + offset], src);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_FATAL("Unexpected result type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (IsFloatType(instr->arg1()->type())) {
|
||||||
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
const Xbyak::Xmm src = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
switch (instr->arg1()->type()) {
|
switch (instr->arg1()->type()) {
|
||||||
|
@ -1152,6 +1196,37 @@ EMITTER(SQRT) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EMITTER(VBROADCAST) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
const Xbyak::Xmm a = e.GetXmmRegister(instr->arg0());
|
||||||
|
|
||||||
|
e.vbroadcastss(result, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMITTER(VADD) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
const Xbyak::Xmm a = e.GetXmmRegister(instr->arg0());
|
||||||
|
const Xbyak::Xmm b = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
|
e.vaddps(result, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMITTER(VDOT) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
const Xbyak::Xmm a = e.GetXmmRegister(instr->arg0());
|
||||||
|
const Xbyak::Xmm b = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
|
e.vdpps(result, a, b, 0b11110001);
|
||||||
|
}
|
||||||
|
|
||||||
|
EMITTER(VMUL) {
|
||||||
|
const Xbyak::Xmm result = e.GetXmmRegister(instr);
|
||||||
|
const Xbyak::Xmm a = e.GetXmmRegister(instr->arg0());
|
||||||
|
const Xbyak::Xmm b = e.GetXmmRegister(instr->arg1());
|
||||||
|
|
||||||
|
e.vmulps(result, a, b);
|
||||||
|
}
|
||||||
|
|
||||||
EMITTER(AND) {
|
EMITTER(AND) {
|
||||||
const Xbyak::Reg result = e.GetRegister(instr);
|
const Xbyak::Reg result = e.GetRegister(instr);
|
||||||
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
const Xbyak::Reg a = e.GetRegister(instr->arg0());
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -26,12 +26,12 @@ class SH4Builder : public ir::IRBuilder {
|
||||||
|
|
||||||
void Emit(uint32_t addr, int max_instrs);
|
void Emit(uint32_t addr, int max_instrs);
|
||||||
|
|
||||||
ir::Value *LoadRegister(int n, ir::ValueType type);
|
ir::Value *LoadGPR(int n, ir::ValueType type);
|
||||||
void StoreRegister(int n, ir::Value *v);
|
void StoreGPR(int n, ir::Value *v);
|
||||||
ir::Value *LoadRegisterF(int n, ir::ValueType type);
|
ir::Value *LoadFPR(int n, ir::ValueType type);
|
||||||
void StoreRegisterF(int n, ir::Value *v);
|
void StoreFPR(int n, ir::Value *v);
|
||||||
ir::Value *LoadRegisterXF(int n, ir::ValueType type);
|
ir::Value *LoadXFR(int n, ir::ValueType type);
|
||||||
void StoreRegisterXF(int n, ir::Value *v);
|
void StoreXFR(int n, ir::Value *v);
|
||||||
ir::Value *LoadSR();
|
ir::Value *LoadSR();
|
||||||
void StoreSR(ir::Value *v);
|
void StoreSR(ir::Value *v);
|
||||||
ir::Value *LoadT();
|
ir::Value *LoadT();
|
||||||
|
|
|
@ -74,6 +74,11 @@ struct SH4Context {
|
||||||
// mapping for each pair of single-precision registers is instead swapped by
|
// mapping for each pair of single-precision registers is instead swapped by
|
||||||
// XOR'ing the actual index with 1. for example, fr2 becomes fr[3] and fr3
|
// XOR'ing the actual index with 1. for example, fr2 becomes fr[3] and fr3
|
||||||
// becomes fr[2], enabling dr2 to perfectly alias fr[2]
|
// becomes fr[2], enabling dr2 to perfectly alias fr[2]
|
||||||
|
|
||||||
|
// note note, this incorrectly causes fv registers to be swizzled. fv0 should
|
||||||
|
// be loaded as {fr0, fr1, fr2, fr3} but it's actually loaded as
|
||||||
|
// {fr1, fr0, fr3, fr2}. however, due to the way the FV registers are
|
||||||
|
// used (FIPR and FTRV) this doesn't actually affect the results
|
||||||
uint32_t fr[16], xf[16];
|
uint32_t fr[16], xf[16];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -401,6 +401,44 @@ Instr *IRBuilder::Sqrt(Value *a) {
|
||||||
return instr;
|
return instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instr *IRBuilder::VBroadcast(Value *a) {
|
||||||
|
CHECK(a->type() == VALUE_F32);
|
||||||
|
|
||||||
|
Instr *instr = AppendInstr(OP_VBROADCAST, VALUE_V128);
|
||||||
|
instr->set_arg0(a);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instr *IRBuilder::VAdd(Value *a, Value *b, ValueType el_type) {
|
||||||
|
CHECK(IsVectorType(a->type()) && IsVectorType(b->type()));
|
||||||
|
CHECK_EQ(el_type, VALUE_F32);
|
||||||
|
|
||||||
|
Instr *instr = AppendInstr(OP_VADD, a->type());
|
||||||
|
instr->set_arg0(a);
|
||||||
|
instr->set_arg1(b);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instr *IRBuilder::VDot(Value *a, Value *b, ValueType el_type) {
|
||||||
|
CHECK(IsVectorType(a->type()) && IsVectorType(b->type()));
|
||||||
|
CHECK_EQ(el_type, VALUE_F32);
|
||||||
|
|
||||||
|
Instr *instr = AppendInstr(OP_VDOT, el_type);
|
||||||
|
instr->set_arg0(a);
|
||||||
|
instr->set_arg1(b);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Instr *IRBuilder::VMul(Value *a, Value *b, ValueType el_type) {
|
||||||
|
CHECK(IsVectorType(a->type()) && IsVectorType(b->type()));
|
||||||
|
CHECK_EQ(el_type, VALUE_F32);
|
||||||
|
|
||||||
|
Instr *instr = AppendInstr(OP_VMUL, a->type());
|
||||||
|
instr->set_arg0(a);
|
||||||
|
instr->set_arg1(b);
|
||||||
|
return instr;
|
||||||
|
}
|
||||||
|
|
||||||
Instr *IRBuilder::And(Value *a, Value *b) {
|
Instr *IRBuilder::And(Value *a, Value *b) {
|
||||||
CHECK(IsIntType(a->type()) && a->type() == b->type());
|
CHECK(IsIntType(a->type()) && a->type() == b->type());
|
||||||
|
|
||||||
|
|
|
@ -30,6 +30,7 @@ enum ValueType {
|
||||||
VALUE_I64,
|
VALUE_I64,
|
||||||
VALUE_F32,
|
VALUE_F32,
|
||||||
VALUE_F64,
|
VALUE_F64,
|
||||||
|
VALUE_V128,
|
||||||
VALUE_NUM,
|
VALUE_NUM,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -40,9 +41,11 @@ enum {
|
||||||
VALUE_I64_MASK = 1 << VALUE_I64,
|
VALUE_I64_MASK = 1 << VALUE_I64,
|
||||||
VALUE_F32_MASK = 1 << VALUE_F32,
|
VALUE_F32_MASK = 1 << VALUE_F32,
|
||||||
VALUE_F64_MASK = 1 << VALUE_F64,
|
VALUE_F64_MASK = 1 << VALUE_F64,
|
||||||
|
VALUE_V128_MASK = 1 << VALUE_V128,
|
||||||
VALUE_INT_MASK =
|
VALUE_INT_MASK =
|
||||||
VALUE_I8_MASK | VALUE_I16_MASK | VALUE_I32_MASK | VALUE_I64_MASK,
|
VALUE_I8_MASK | VALUE_I16_MASK | VALUE_I32_MASK | VALUE_I64_MASK,
|
||||||
VALUE_FLOAT_MASK = VALUE_F32_MASK | VALUE_F64_MASK,
|
VALUE_FLOAT_MASK = VALUE_F32_MASK | VALUE_F64_MASK,
|
||||||
|
VALUE_VECTOR_MASK = VALUE_V128_MASK,
|
||||||
VALUE_ALL_MASK = VALUE_INT_MASK | VALUE_FLOAT_MASK,
|
VALUE_ALL_MASK = VALUE_INT_MASK | VALUE_FLOAT_MASK,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -53,11 +56,16 @@ enum {
|
||||||
class Instr;
|
class Instr;
|
||||||
class Use;
|
class Use;
|
||||||
|
|
||||||
|
static inline bool IsIntType(ValueType type) {
|
||||||
|
return type == VALUE_I8 || type == VALUE_I16 || type == VALUE_I32 ||
|
||||||
|
type == VALUE_I64;
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool IsFloatType(ValueType type) {
|
static inline bool IsFloatType(ValueType type) {
|
||||||
return type == VALUE_F32 || type == VALUE_F64;
|
return type == VALUE_F32 || type == VALUE_F64;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool IsIntType(ValueType type) { return !IsFloatType(type); }
|
static inline bool IsVectorType(ValueType type) { return type == VALUE_V128; }
|
||||||
|
|
||||||
static inline int SizeForType(ValueType type) {
|
static inline int SizeForType(ValueType type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
|
@ -73,6 +81,8 @@ static inline int SizeForType(ValueType type) {
|
||||||
return 4;
|
return 4;
|
||||||
case VALUE_F64:
|
case VALUE_F64:
|
||||||
return 8;
|
return 8;
|
||||||
|
case VALUE_V128:
|
||||||
|
return 16;
|
||||||
default:
|
default:
|
||||||
LOG_FATAL("Unexpected value type");
|
LOG_FATAL("Unexpected value type");
|
||||||
break;
|
break;
|
||||||
|
@ -373,7 +383,7 @@ class IRBuilder {
|
||||||
Instr *FCmpLE(Value *a, Value *b);
|
Instr *FCmpLE(Value *a, Value *b);
|
||||||
Instr *FCmpLT(Value *a, Value *b);
|
Instr *FCmpLT(Value *a, Value *b);
|
||||||
|
|
||||||
// math operators
|
// integer math operators
|
||||||
Instr *Add(Value *a, Value *b);
|
Instr *Add(Value *a, Value *b);
|
||||||
Instr *Sub(Value *a, Value *b);
|
Instr *Sub(Value *a, Value *b);
|
||||||
Instr *SMul(Value *a, Value *b);
|
Instr *SMul(Value *a, Value *b);
|
||||||
|
@ -381,6 +391,8 @@ class IRBuilder {
|
||||||
Instr *Div(Value *a, Value *b);
|
Instr *Div(Value *a, Value *b);
|
||||||
Instr *Neg(Value *a);
|
Instr *Neg(Value *a);
|
||||||
Instr *Abs(Value *a);
|
Instr *Abs(Value *a);
|
||||||
|
|
||||||
|
// floating point math operators
|
||||||
Instr *FAdd(Value *a, Value *b);
|
Instr *FAdd(Value *a, Value *b);
|
||||||
Instr *FSub(Value *a, Value *b);
|
Instr *FSub(Value *a, Value *b);
|
||||||
Instr *FMul(Value *a, Value *b);
|
Instr *FMul(Value *a, Value *b);
|
||||||
|
@ -389,6 +401,12 @@ class IRBuilder {
|
||||||
Instr *FAbs(Value *a);
|
Instr *FAbs(Value *a);
|
||||||
Instr *Sqrt(Value *a);
|
Instr *Sqrt(Value *a);
|
||||||
|
|
||||||
|
// vector math operators
|
||||||
|
Instr *VBroadcast(Value *a);
|
||||||
|
Instr *VAdd(Value *a, Value *b, ValueType el_type);
|
||||||
|
Instr *VDot(Value *a, Value *b, ValueType el_type);
|
||||||
|
Instr *VMul(Value *a, Value *b, ValueType el_type);
|
||||||
|
|
||||||
// bitwise operations
|
// bitwise operations
|
||||||
Instr *And(Value *a, Value *b);
|
Instr *And(Value *a, Value *b);
|
||||||
Instr *Or(Value *a, Value *b);
|
Instr *Or(Value *a, Value *b);
|
||||||
|
|
|
@ -30,6 +30,10 @@ IR_OP(FDIV)
|
||||||
IR_OP(FNEG)
|
IR_OP(FNEG)
|
||||||
IR_OP(FABS)
|
IR_OP(FABS)
|
||||||
IR_OP(SQRT)
|
IR_OP(SQRT)
|
||||||
|
IR_OP(VBROADCAST)
|
||||||
|
IR_OP(VADD)
|
||||||
|
IR_OP(VDOT)
|
||||||
|
IR_OP(VMUL)
|
||||||
IR_OP(AND)
|
IR_OP(AND)
|
||||||
IR_OP(OR)
|
IR_OP(OR)
|
||||||
IR_OP(XOR)
|
IR_OP(XOR)
|
||||||
|
|
|
@ -82,7 +82,8 @@ void RegisterSet::InsertInterval(Interval *interval) {
|
||||||
|
|
||||||
RegisterAllocationPass::RegisterAllocationPass(const Backend &backend)
|
RegisterAllocationPass::RegisterAllocationPass(const Backend &backend)
|
||||||
: int_registers_(backend.num_registers()),
|
: int_registers_(backend.num_registers()),
|
||||||
float_registers_(backend.num_registers()) {
|
float_registers_(backend.num_registers()),
|
||||||
|
vector_registers_(backend.num_registers()) {
|
||||||
registers_ = backend.registers();
|
registers_ = backend.registers();
|
||||||
num_registers_ = backend.num_registers();
|
num_registers_ = backend.num_registers();
|
||||||
|
|
||||||
|
@ -139,12 +140,17 @@ RegisterSet &RegisterAllocationPass::GetRegisterSet(ValueType type) {
|
||||||
return float_registers_;
|
return float_registers_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsVectorType(type)) {
|
||||||
|
return vector_registers_;
|
||||||
|
}
|
||||||
|
|
||||||
LOG_FATAL("Unexpected value type");
|
LOG_FATAL("Unexpected value type");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterAllocationPass::Reset() {
|
void RegisterAllocationPass::Reset() {
|
||||||
int_registers_.Clear();
|
int_registers_.Clear();
|
||||||
float_registers_.Clear();
|
float_registers_.Clear();
|
||||||
|
vector_registers_.Clear();
|
||||||
|
|
||||||
for (int i = 0; i < num_registers_; i++) {
|
for (int i = 0; i < num_registers_; i++) {
|
||||||
const Register &r = registers_[i];
|
const Register &r = registers_[i];
|
||||||
|
@ -153,10 +159,10 @@ void RegisterAllocationPass::Reset() {
|
||||||
int_registers_.PushRegister(i);
|
int_registers_.PushRegister(i);
|
||||||
} else if (r.value_types == VALUE_FLOAT_MASK) {
|
} else if (r.value_types == VALUE_FLOAT_MASK) {
|
||||||
float_registers_.PushRegister(i);
|
float_registers_.PushRegister(i);
|
||||||
|
} else if (r.value_types == VALUE_VECTOR_MASK) {
|
||||||
|
vector_registers_.PushRegister(i);
|
||||||
} else {
|
} else {
|
||||||
LOG_FATAL(
|
LOG_FATAL("Unsupported register value mask");
|
||||||
"Unsupported register value mask, expected VALUE_INT_MASK or "
|
|
||||||
"VALUE_FLOAT_MASK");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,6 +226,7 @@ void RegisterAllocationPass::ExpireOldIntervals(Instr *instr) {
|
||||||
|
|
||||||
expire_set(int_registers_);
|
expire_set(int_registers_);
|
||||||
expire_set(float_registers_);
|
expire_set(float_registers_);
|
||||||
|
expire_set(vector_registers_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the first argument isn't used after this instruction, its register
|
// If the first argument isn't used after this instruction, its register
|
||||||
|
|
|
@ -59,6 +59,7 @@ class RegisterAllocationPass : public Pass {
|
||||||
|
|
||||||
RegisterSet int_registers_;
|
RegisterSet int_registers_;
|
||||||
RegisterSet float_registers_;
|
RegisterSet float_registers_;
|
||||||
|
RegisterSet vector_registers_;
|
||||||
|
|
||||||
// intervals, keyed by register
|
// intervals, keyed by register
|
||||||
Interval *intervals_;
|
Interval *intervals_;
|
||||||
|
|
Loading…
Reference in New Issue