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)},
|
||||
{"xmm10", ir::VALUE_FLOAT_MASK,
|
||||
reinterpret_cast<const void *>(&Xbyak::util::xmm10)},
|
||||
{"xmm11", ir::VALUE_FLOAT_MASK,
|
||||
reinterpret_cast<const void *>(&Xbyak::util::xmm11)}};
|
||||
{"xmm11", ir::VALUE_VECTOR_MASK,
|
||||
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);
|
||||
|
||||
|
|
|
@ -577,7 +577,18 @@ EMITTER(STORE_GUEST) {
|
|||
EMITTER(LOAD_CONTEXT) {
|
||||
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);
|
||||
|
||||
switch (instr->type()) {
|
||||
|
@ -638,7 +649,18 @@ EMITTER(STORE_CONTEXT) {
|
|||
break;
|
||||
}
|
||||
} 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());
|
||||
|
||||
switch (instr->arg1()->type()) {
|
||||
|
@ -679,7 +701,18 @@ EMITTER(STORE_CONTEXT) {
|
|||
EMITTER(LOAD_LOCAL) {
|
||||
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);
|
||||
|
||||
switch (instr->type()) {
|
||||
|
@ -721,7 +754,18 @@ EMITTER(STORE_LOCAL) {
|
|||
|
||||
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());
|
||||
|
||||
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) {
|
||||
const Xbyak::Reg result = e.GetRegister(instr);
|
||||
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);
|
||||
|
||||
ir::Value *LoadRegister(int n, ir::ValueType type);
|
||||
void StoreRegister(int n, ir::Value *v);
|
||||
ir::Value *LoadRegisterF(int n, ir::ValueType type);
|
||||
void StoreRegisterF(int n, ir::Value *v);
|
||||
ir::Value *LoadRegisterXF(int n, ir::ValueType type);
|
||||
void StoreRegisterXF(int n, ir::Value *v);
|
||||
ir::Value *LoadGPR(int n, ir::ValueType type);
|
||||
void StoreGPR(int n, ir::Value *v);
|
||||
ir::Value *LoadFPR(int n, ir::ValueType type);
|
||||
void StoreFPR(int n, ir::Value *v);
|
||||
ir::Value *LoadXFR(int n, ir::ValueType type);
|
||||
void StoreXFR(int n, ir::Value *v);
|
||||
ir::Value *LoadSR();
|
||||
void StoreSR(ir::Value *v);
|
||||
ir::Value *LoadT();
|
||||
|
|
|
@ -74,6 +74,11 @@ struct SH4Context {
|
|||
// 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
|
||||
// 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];
|
||||
};
|
||||
}
|
||||
|
|
|
@ -401,6 +401,44 @@ Instr *IRBuilder::Sqrt(Value *a) {
|
|||
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) {
|
||||
CHECK(IsIntType(a->type()) && a->type() == b->type());
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ enum ValueType {
|
|||
VALUE_I64,
|
||||
VALUE_F32,
|
||||
VALUE_F64,
|
||||
VALUE_V128,
|
||||
VALUE_NUM,
|
||||
};
|
||||
|
||||
|
@ -40,9 +41,11 @@ enum {
|
|||
VALUE_I64_MASK = 1 << VALUE_I64,
|
||||
VALUE_F32_MASK = 1 << VALUE_F32,
|
||||
VALUE_F64_MASK = 1 << VALUE_F64,
|
||||
VALUE_V128_MASK = 1 << VALUE_V128,
|
||||
VALUE_INT_MASK =
|
||||
VALUE_I8_MASK | VALUE_I16_MASK | VALUE_I32_MASK | VALUE_I64_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,
|
||||
};
|
||||
|
||||
|
@ -53,11 +56,16 @@ enum {
|
|||
class Instr;
|
||||
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) {
|
||||
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) {
|
||||
switch (type) {
|
||||
|
@ -73,6 +81,8 @@ static inline int SizeForType(ValueType type) {
|
|||
return 4;
|
||||
case VALUE_F64:
|
||||
return 8;
|
||||
case VALUE_V128:
|
||||
return 16;
|
||||
default:
|
||||
LOG_FATAL("Unexpected value type");
|
||||
break;
|
||||
|
@ -373,7 +383,7 @@ class IRBuilder {
|
|||
Instr *FCmpLE(Value *a, Value *b);
|
||||
Instr *FCmpLT(Value *a, Value *b);
|
||||
|
||||
// math operators
|
||||
// integer math operators
|
||||
Instr *Add(Value *a, Value *b);
|
||||
Instr *Sub(Value *a, Value *b);
|
||||
Instr *SMul(Value *a, Value *b);
|
||||
|
@ -381,6 +391,8 @@ class IRBuilder {
|
|||
Instr *Div(Value *a, Value *b);
|
||||
Instr *Neg(Value *a);
|
||||
Instr *Abs(Value *a);
|
||||
|
||||
// floating point math operators
|
||||
Instr *FAdd(Value *a, Value *b);
|
||||
Instr *FSub(Value *a, Value *b);
|
||||
Instr *FMul(Value *a, Value *b);
|
||||
|
@ -389,6 +401,12 @@ class IRBuilder {
|
|||
Instr *FAbs(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
|
||||
Instr *And(Value *a, Value *b);
|
||||
Instr *Or(Value *a, Value *b);
|
||||
|
|
|
@ -30,6 +30,10 @@ IR_OP(FDIV)
|
|||
IR_OP(FNEG)
|
||||
IR_OP(FABS)
|
||||
IR_OP(SQRT)
|
||||
IR_OP(VBROADCAST)
|
||||
IR_OP(VADD)
|
||||
IR_OP(VDOT)
|
||||
IR_OP(VMUL)
|
||||
IR_OP(AND)
|
||||
IR_OP(OR)
|
||||
IR_OP(XOR)
|
||||
|
|
|
@ -82,7 +82,8 @@ void RegisterSet::InsertInterval(Interval *interval) {
|
|||
|
||||
RegisterAllocationPass::RegisterAllocationPass(const Backend &backend)
|
||||
: int_registers_(backend.num_registers()),
|
||||
float_registers_(backend.num_registers()) {
|
||||
float_registers_(backend.num_registers()),
|
||||
vector_registers_(backend.num_registers()) {
|
||||
registers_ = backend.registers();
|
||||
num_registers_ = backend.num_registers();
|
||||
|
||||
|
@ -139,12 +140,17 @@ RegisterSet &RegisterAllocationPass::GetRegisterSet(ValueType type) {
|
|||
return float_registers_;
|
||||
}
|
||||
|
||||
if (IsVectorType(type)) {
|
||||
return vector_registers_;
|
||||
}
|
||||
|
||||
LOG_FATAL("Unexpected value type");
|
||||
}
|
||||
|
||||
void RegisterAllocationPass::Reset() {
|
||||
int_registers_.Clear();
|
||||
float_registers_.Clear();
|
||||
vector_registers_.Clear();
|
||||
|
||||
for (int i = 0; i < num_registers_; i++) {
|
||||
const Register &r = registers_[i];
|
||||
|
@ -153,10 +159,10 @@ void RegisterAllocationPass::Reset() {
|
|||
int_registers_.PushRegister(i);
|
||||
} else if (r.value_types == VALUE_FLOAT_MASK) {
|
||||
float_registers_.PushRegister(i);
|
||||
} else if (r.value_types == VALUE_VECTOR_MASK) {
|
||||
vector_registers_.PushRegister(i);
|
||||
} else {
|
||||
LOG_FATAL(
|
||||
"Unsupported register value mask, expected VALUE_INT_MASK or "
|
||||
"VALUE_FLOAT_MASK");
|
||||
LOG_FATAL("Unsupported register value mask");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -220,6 +226,7 @@ void RegisterAllocationPass::ExpireOldIntervals(Instr *instr) {
|
|||
|
||||
expire_set(int_registers_);
|
||||
expire_set(float_registers_);
|
||||
expire_set(vector_registers_);
|
||||
}
|
||||
|
||||
// If the first argument isn't used after this instruction, its register
|
||||
|
|
|
@ -59,6 +59,7 @@ class RegisterAllocationPass : public Pass {
|
|||
|
||||
RegisterSet int_registers_;
|
||||
RegisterSet float_registers_;
|
||||
RegisterSet vector_registers_;
|
||||
|
||||
// intervals, keyed by register
|
||||
Interval *intervals_;
|
||||
|
|
Loading…
Reference in New Issue