basic vectored types support for FIPR and FTRV

This commit is contained in:
Anthony Pesch 2016-04-06 23:53:52 -07:00
parent 38597832e6
commit 4822ffab43
10 changed files with 605 additions and 450 deletions

View File

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

View File

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

View File

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

View File

@ -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];
}; };
} }

View File

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

View File

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

View File

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

View File

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

View File

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