Propagate vector constants.
This commit is contained in:
parent
4b7a403337
commit
3ccb2a978d
|
@ -161,6 +161,13 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
i->Remove();
|
i->Remove();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case OPCODE_ROUND:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->Round(RoundMode(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPCODE_ZERO_EXTEND:
|
case OPCODE_ZERO_EXTEND:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
TypeName target_type = v->type;
|
TypeName target_type = v->type;
|
||||||
|
@ -188,6 +195,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
|
|
||||||
case OPCODE_LOAD:
|
case OPCODE_LOAD:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
|
assert_false(i->flags & LOAD_STORE_BYTE_SWAP);
|
||||||
auto memory = processor_->memory();
|
auto memory = processor_->memory();
|
||||||
auto address = i->src1.value->constant.i32;
|
auto address = i->src1.value->constant.i32;
|
||||||
auto mmio_range =
|
auto mmio_range =
|
||||||
|
@ -253,12 +261,23 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
|
|
||||||
case OPCODE_SELECT:
|
case OPCODE_SELECT:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
|
if (i->src1.value->type != VEC128_TYPE) {
|
||||||
if (i->src1.value->IsConstantTrue()) {
|
if (i->src1.value->IsConstantTrue()) {
|
||||||
v->set_from(i->src2.value);
|
v->set_from(i->src2.value);
|
||||||
} else {
|
|
||||||
v->set_from(i->src3.value);
|
|
||||||
}
|
|
||||||
i->Remove();
|
i->Remove();
|
||||||
|
} else if (i->src1.value->IsConstantFalse()) {
|
||||||
|
v->set_from(i->src3.value);
|
||||||
|
i->Remove();
|
||||||
|
} else if (i->src2.value->IsConstant() &&
|
||||||
|
i->src3.value->IsConstant()) {
|
||||||
|
// TODO
|
||||||
|
// v->set_from(i->src2.value);
|
||||||
|
// v->Select(i->src3.value, i->src1.value);
|
||||||
|
// i->Remove();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case OPCODE_IS_TRUE:
|
case OPCODE_IS_TRUE:
|
||||||
|
@ -355,7 +374,7 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_DID_SATURATE:
|
case OPCODE_DID_SATURATE:
|
||||||
assert_true(!i->src1.value->IsConstant());
|
// assert_true(!i->src1.value->IsConstant());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case OPCODE_ADD:
|
case OPCODE_ADD:
|
||||||
|
@ -413,8 +432,33 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
i->Remove();
|
i->Remove();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// case OPCODE_MUL_ADD:
|
case OPCODE_MUL_ADD:
|
||||||
// case OPCODE_MUL_SUB
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
// Multiply part is constant.
|
||||||
|
if (i->src3.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
Value::MulAdd(v, i->src1.value, i->src2.value, i->src3.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_MUL_SUB:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
// Multiply part is constant.
|
||||||
|
if (i->src3.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
Value::MulSub(v, i->src1.value, i->src2.value, i->src3.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_MAX:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->Max(i->src2.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case OPCODE_NEG:
|
case OPCODE_NEG:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant()) {
|
||||||
v->set_from(i->src1.value);
|
v->set_from(i->src1.value);
|
||||||
|
@ -484,7 +528,6 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
i->Remove();
|
i->Remove();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// TODO(benvanik): VECTOR_SHL
|
|
||||||
case OPCODE_SHR:
|
case OPCODE_SHR:
|
||||||
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
v->set_from(i->src1.value);
|
v->set_from(i->src1.value);
|
||||||
|
@ -515,13 +558,80 @@ bool ConstantPropagationPass::Run(HIRBuilder* builder) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
// TODO(benvanik): INSERT/EXTRACT
|
// TODO(benvanik): INSERT/EXTRACT
|
||||||
// TODO(benvanik): SPLAT/PERMUTE/SWIZZLE
|
// TODO(benvanik): PERMUTE/SWIZZLE
|
||||||
case OPCODE_SPLAT:
|
case OPCODE_EXTRACT:
|
||||||
if (i->src1.value->IsConstant()) {
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
// Quite a few of these, from building vec128s.
|
v->set_zero(v->type);
|
||||||
|
v->Extract(i->src1.value, i->src2.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_SPLAT:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
v->set_zero(v->type);
|
||||||
|
v->Splat(i->src1.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_COMPARE_EQ:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->VectorCompareEQ(i->src2.value, hir::TypeName(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_COMPARE_SGT:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->VectorCompareSGT(i->src2.value, hir::TypeName(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_CONVERT_F2I:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
v->set_zero(VEC128_TYPE);
|
||||||
|
v->VectorConvertF2I(i->src1.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_CONVERT_I2F:
|
||||||
|
if (i->src1.value->IsConstant()) {
|
||||||
|
v->set_zero(VEC128_TYPE);
|
||||||
|
v->VectorConvertI2F(i->src1.value);
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_SHL:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->VectorShl(i->src2.value, hir::TypeName(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_SHR:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->VectorShr(i->src2.value, hir::TypeName(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_ROTATE_LEFT:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
v->VectorRol(i->src2.value, hir::TypeName(i->flags));
|
||||||
|
i->Remove();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case OPCODE_VECTOR_SUB:
|
||||||
|
if (i->src1.value->IsConstant() && i->src2.value->IsConstant()) {
|
||||||
|
v->set_from(i->src1.value);
|
||||||
|
uint32_t arith_flags = i->flags >> 8;
|
||||||
|
v->VectorSub(i->src2.value, hir::TypeName(i->flags & 0xFF),
|
||||||
|
!!(arith_flags & ARITHMETIC_UNSIGNED),
|
||||||
|
!!(arith_flags & ARITHMETIC_SATURATE));
|
||||||
|
i->Remove();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Ignored.
|
// Ignored.
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -46,13 +46,13 @@ uint32_t Value::AsUint32() {
|
||||||
assert_true(IsConstant());
|
assert_true(IsConstant());
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
return constant.i8;
|
return constant.u8;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
return constant.i16;
|
return constant.u16;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
return constant.i32;
|
return constant.u32;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
return (uint32_t)constant.i64;
|
return (uint32_t)constant.u64;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -63,13 +63,13 @@ uint64_t Value::AsUint64() {
|
||||||
assert_true(IsConstant());
|
assert_true(IsConstant());
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
return constant.i8;
|
return constant.u8;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
return constant.i16;
|
return constant.u16;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
return constant.i32;
|
return constant.u32;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
return constant.i64;
|
return constant.u64;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -85,15 +85,15 @@ void Value::ZeroExtend(TypeName target_type) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
type = target_type;
|
type = target_type;
|
||||||
constant.i64 = constant.i64 & 0xFF;
|
constant.u64 = constant.u8;
|
||||||
return;
|
return;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
type = target_type;
|
type = target_type;
|
||||||
constant.i64 = constant.i64 & 0xFFFF;
|
constant.u64 = constant.u16;
|
||||||
return;
|
return;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
type = target_type;
|
type = target_type;
|
||||||
constant.i64 = constant.i64 & 0xFFFFFFFF;
|
constant.u64 = constant.u32;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
|
@ -210,12 +210,30 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) {
|
||||||
assert_unhandled_case(target_type);
|
assert_unhandled_case(target_type);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case INT64_TYPE:
|
||||||
|
switch (target_type) {
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
type = target_type;
|
||||||
|
constant.f64 = (double)constant.i64;
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(target_type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
switch (target_type) {
|
switch (target_type) {
|
||||||
case FLOAT32_TYPE:
|
case FLOAT32_TYPE:
|
||||||
type = target_type;
|
type = target_type;
|
||||||
constant.f32 = (float)constant.f64;
|
constant.f32 = (float)constant.f64;
|
||||||
return;
|
return;
|
||||||
|
case INT32_TYPE:
|
||||||
|
type = target_type;
|
||||||
|
constant.i32 = (int32_t)constant.f64;
|
||||||
|
return;
|
||||||
|
case INT64_TYPE:
|
||||||
|
type = target_type;
|
||||||
|
constant.i64 = (int64_t)constant.f64;
|
||||||
|
return;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(target_type);
|
assert_unhandled_case(target_type);
|
||||||
return;
|
return;
|
||||||
|
@ -227,8 +245,28 @@ void Value::Convert(TypeName target_type, RoundMode round_mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::Round(RoundMode round_mode) {
|
void Value::Round(RoundMode round_mode) {
|
||||||
// TODO(benvanik): big matrix.
|
switch (type) {
|
||||||
assert_always();
|
case FLOAT32_TYPE:
|
||||||
|
switch (round_mode) {
|
||||||
|
case ROUND_TO_NEAREST:
|
||||||
|
constant.f32 = std::round(constant.f32);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
return;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
switch (round_mode) {
|
||||||
|
case ROUND_TO_NEAREST:
|
||||||
|
constant.v128.f32[i] = std::round(constant.v128.f32[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Value::Add(Value* other) {
|
bool Value::Add(Value* other) {
|
||||||
|
@ -325,6 +363,11 @@ void Value::Mul(Value* other) {
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
constant.f64 *= other->constant.f64;
|
constant.f64 *= other->constant.f64;
|
||||||
break;
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.f32[i] *= other->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
@ -406,6 +449,32 @@ void Value::Div(Value* other, bool is_unsigned) {
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
constant.f64 /= other->constant.f64;
|
constant.f64 /= other->constant.f64;
|
||||||
break;
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.f32[i] /= other->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::Max(Value* other) {
|
||||||
|
assert_true(type == other->type);
|
||||||
|
switch (type) {
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
constant.f32 = std::max(constant.f32, other->constant.f32);
|
||||||
|
break;
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
constant.f64 = std::max(constant.f64, other->constant.f64);
|
||||||
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.f32[i] =
|
||||||
|
std::max(constant.v128.f32[i], other->constant.v128.f32[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
@ -413,13 +482,49 @@ void Value::Div(Value* other, bool is_unsigned) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::MulAdd(Value* dest, Value* value1, Value* value2, Value* value3) {
|
void Value::MulAdd(Value* dest, Value* value1, Value* value2, Value* value3) {
|
||||||
// TODO(benvanik): big matrix.
|
switch (dest->type) {
|
||||||
assert_always();
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
dest->constant.v128.f32[i] =
|
||||||
|
(value1->constant.v128.f32[i] * value2->constant.v128.f32[i]) +
|
||||||
|
value3->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
dest->constant.f32 =
|
||||||
|
(value1->constant.f32 * value2->constant.f32) + value3->constant.f32;
|
||||||
|
break;
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
dest->constant.f64 =
|
||||||
|
(value1->constant.f64 * value2->constant.f64) + value3->constant.f64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(dest->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
|
void Value::MulSub(Value* dest, Value* value1, Value* value2, Value* value3) {
|
||||||
// TODO(benvanik): big matrix.
|
switch (dest->type) {
|
||||||
assert_always();
|
case VEC128_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
dest->constant.v128.f32[i] =
|
||||||
|
(value1->constant.v128.f32[i] * value2->constant.v128.f32[i]) -
|
||||||
|
value3->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
dest->constant.f32 =
|
||||||
|
(value1->constant.f32 * value2->constant.f32) - value3->constant.f32;
|
||||||
|
break;
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
dest->constant.f64 =
|
||||||
|
(value1->constant.f64 * value2->constant.f64) - value3->constant.f64;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(dest->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Value::Neg() {
|
void Value::Neg() {
|
||||||
|
@ -527,6 +632,9 @@ void Value::And(Value* other) {
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 &= other->constant.i64;
|
constant.i64 &= other->constant.i64;
|
||||||
break;
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
constant.v128 &= other->constant.v128;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
@ -548,6 +656,9 @@ void Value::Or(Value* other) {
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 |= other->constant.i64;
|
constant.i64 |= other->constant.i64;
|
||||||
break;
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
constant.v128 |= other->constant.v128;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
@ -569,6 +680,9 @@ void Value::Xor(Value* other) {
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 ^= other->constant.i64;
|
constant.i64 ^= other->constant.i64;
|
||||||
break;
|
break;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
constant.v128 ^= other->constant.v128;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
break;
|
break;
|
||||||
|
@ -603,16 +717,16 @@ void Value::Shl(Value* other) {
|
||||||
assert_true(other->type == INT8_TYPE);
|
assert_true(other->type == INT8_TYPE);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
constant.i8 <<= other->constant.i8;
|
constant.u8 <<= other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
constant.i16 <<= other->constant.i8;
|
constant.u16 <<= other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
constant.i32 <<= other->constant.i8;
|
constant.u32 <<= other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 <<= other->constant.i8;
|
constant.u64 <<= other->constant.u8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
|
@ -624,16 +738,16 @@ void Value::Shr(Value* other) {
|
||||||
assert_true(other->type == INT8_TYPE);
|
assert_true(other->type == INT8_TYPE);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
constant.i8 = (uint8_t)constant.i8 >> other->constant.i8;
|
constant.u8 = constant.u8 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
constant.i16 = (uint16_t)constant.i16 >> other->constant.i8;
|
constant.u16 = constant.u16 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
constant.i32 = (uint32_t)constant.i32 >> other->constant.i8;
|
constant.u32 = constant.u32 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 = (uint64_t)constant.i64 >> other->constant.i8;
|
constant.u64 = constant.u64 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
|
@ -645,16 +759,16 @@ void Value::Sha(Value* other) {
|
||||||
assert_true(other->type == INT8_TYPE);
|
assert_true(other->type == INT8_TYPE);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
constant.i8 = constant.i8 >> other->constant.i8;
|
constant.i8 = constant.i8 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT16_TYPE:
|
case INT16_TYPE:
|
||||||
constant.i16 = constant.i16 >> other->constant.i8;
|
constant.i16 = constant.i16 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT32_TYPE:
|
case INT32_TYPE:
|
||||||
constant.i32 = constant.i32 >> other->constant.i8;
|
constant.i32 = constant.i32 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
case INT64_TYPE:
|
case INT64_TYPE:
|
||||||
constant.i64 = constant.i64 >> other->constant.i8;
|
constant.i64 = constant.i64 >> other->constant.u8;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
|
@ -662,6 +776,246 @@ void Value::Sha(Value* other) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Value::Extract(Value* vec, Value* index) {
|
||||||
|
assert_true(vec->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
constant.u8 = vec->constant.v128.u8[index->constant.u8];
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
constant.u16 = vec->constant.v128.u16[index->constant.u16];
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
constant.u32 = vec->constant.v128.u32[index->constant.u32];
|
||||||
|
break;
|
||||||
|
case INT64_TYPE:
|
||||||
|
constant.u64 = vec->constant.v128.u64[index->constant.u64];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::Select(Value* other, Value* ctrl) {
|
||||||
|
// TODO
|
||||||
|
assert_always();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::Splat(Value* other) {
|
||||||
|
assert_true(type == VEC128_TYPE);
|
||||||
|
switch (other->type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.i8[i] = other->constant.i8;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.i16[i] = other->constant.i16;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.i32[i] = other->constant.i32;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT64_TYPE:
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
constant.v128.i64[i] = other->constant.i64;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(other->type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorCompareEQ(Value* other, TypeName type) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.u8[i] =
|
||||||
|
constant.v128.u8[i] == other->constant.v128.u8[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.u16[i] =
|
||||||
|
constant.v128.u16[i] == other->constant.v128.u16[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] =
|
||||||
|
constant.v128.u32[i] == other->constant.v128.u32[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT64_TYPE:
|
||||||
|
case FLOAT64_TYPE:
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
constant.v128.u64[i] =
|
||||||
|
constant.v128.u64[i] == other->constant.v128.u64[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorCompareSGT(Value* other, TypeName type) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.u8[i] =
|
||||||
|
constant.v128.i8[i] > other->constant.v128.i8[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.u16[i] =
|
||||||
|
constant.v128.i16[i] > other->constant.v128.i16[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] =
|
||||||
|
constant.v128.i32[i] > other->constant.v128.i32[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case FLOAT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] =
|
||||||
|
constant.v128.f32[i] > other->constant.v128.f32[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT64_TYPE:
|
||||||
|
for (int i = 0; i < 2; i++) {
|
||||||
|
constant.v128.u64[i] =
|
||||||
|
constant.v128.i64[i] > other->constant.v128.i64[i] ? -1 : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorConvertI2F(Value* other) {
|
||||||
|
assert_true(type == VEC128_TYPE);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.f32[i] = (float)other->constant.v128.i32[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorConvertF2I(Value* other) {
|
||||||
|
assert_true(type == VEC128_TYPE);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.i32[i] = (int32_t)other->constant.v128.f32[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorShl(Value* other, TypeName type) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.u8[i] <<= other->constant.v128.u8[i] & 0x7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.u16[i] <<= other->constant.v128.u16[i] & 0xF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] <<= other->constant.v128.u32[i] & 0x1F;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorShr(Value* other, TypeName type) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.u8[i] >>= other->constant.v128.u8[i] & 0x7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.u16[i] >>= other->constant.v128.u16[i] & 0xF;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] >>= other->constant.v128.u32[i] & 0x1F;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorRol(Value* other, TypeName type) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT8_TYPE:
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
constant.v128.u8[i] = xe::rotate_left(constant.v128.u8[i],
|
||||||
|
other->constant.v128.i8[i] & 0x7);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT16_TYPE:
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
constant.v128.u16[i] = xe::rotate_left(
|
||||||
|
constant.v128.u16[i], other->constant.v128.u16[i] & 0xF);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
constant.v128.u32[i] = xe::rotate_left(
|
||||||
|
constant.v128.u32[i], other->constant.v128.u32[i] & 0x1F);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_unhandled_case(type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Value::VectorSub(Value* other, TypeName type, bool is_unsigned,
|
||||||
|
bool saturate) {
|
||||||
|
assert_true(this->type == VEC128_TYPE && other->type == VEC128_TYPE);
|
||||||
|
switch (type) {
|
||||||
|
case INT32_TYPE:
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
if (is_unsigned) {
|
||||||
|
if (saturate) {
|
||||||
|
assert_always();
|
||||||
|
} else {
|
||||||
|
constant.v128.u32[i] -= other->constant.v128.u32[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (saturate) {
|
||||||
|
assert_always();
|
||||||
|
} else {
|
||||||
|
constant.v128.i32[i] -= other->constant.v128.i32[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Value::ByteSwap() {
|
void Value::ByteSwap() {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
|
|
|
@ -77,9 +77,13 @@ class Value {
|
||||||
} Use;
|
} Use;
|
||||||
typedef union {
|
typedef union {
|
||||||
int8_t i8;
|
int8_t i8;
|
||||||
|
uint8_t u8;
|
||||||
int16_t i16;
|
int16_t i16;
|
||||||
|
uint16_t u16;
|
||||||
int32_t i32;
|
int32_t i32;
|
||||||
|
uint32_t u32;
|
||||||
int64_t i64;
|
int64_t i64;
|
||||||
|
uint64_t u64;
|
||||||
float f32;
|
float f32;
|
||||||
double f64;
|
double f64;
|
||||||
vec128_t v128;
|
vec128_t v128;
|
||||||
|
@ -190,6 +194,8 @@ class Value {
|
||||||
return !!constant.f32;
|
return !!constant.f32;
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
return !!constant.f64;
|
return !!constant.f64;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
return constant.v128.low || constant.v128.high;
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
return false;
|
return false;
|
||||||
|
@ -199,9 +205,6 @@ class Value {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool IsConstantFalse() const {
|
bool IsConstantFalse() const {
|
||||||
if (type == VEC128_TYPE) {
|
|
||||||
assert_always();
|
|
||||||
}
|
|
||||||
if (flags & VALUE_IS_CONSTANT) {
|
if (flags & VALUE_IS_CONSTANT) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case INT8_TYPE:
|
case INT8_TYPE:
|
||||||
|
@ -216,6 +219,8 @@ class Value {
|
||||||
return !constant.f32;
|
return !constant.f32;
|
||||||
case FLOAT64_TYPE:
|
case FLOAT64_TYPE:
|
||||||
return !constant.f64;
|
return !constant.f64;
|
||||||
|
case VEC128_TYPE:
|
||||||
|
return !(constant.v128.low || constant.v128.high);
|
||||||
default:
|
default:
|
||||||
assert_unhandled_case(type);
|
assert_unhandled_case(type);
|
||||||
return false;
|
return false;
|
||||||
|
@ -475,6 +480,7 @@ class Value {
|
||||||
void Mul(Value* other);
|
void Mul(Value* other);
|
||||||
void MulHi(Value* other, bool is_unsigned);
|
void MulHi(Value* other, bool is_unsigned);
|
||||||
void Div(Value* other, bool is_unsigned);
|
void Div(Value* other, bool is_unsigned);
|
||||||
|
void Max(Value* other);
|
||||||
static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3);
|
static void MulAdd(Value* dest, Value* value1, Value* value2, Value* value3);
|
||||||
static void MulSub(Value* dest, Value* value1, Value* value2, Value* value3);
|
static void MulSub(Value* dest, Value* value1, Value* value2, Value* value3);
|
||||||
void Neg();
|
void Neg();
|
||||||
|
@ -488,6 +494,17 @@ class Value {
|
||||||
void Shl(Value* other);
|
void Shl(Value* other);
|
||||||
void Shr(Value* other);
|
void Shr(Value* other);
|
||||||
void Sha(Value* other);
|
void Sha(Value* other);
|
||||||
|
void Extract(Value* vec, Value* index);
|
||||||
|
void Select(Value* other, Value* ctrl);
|
||||||
|
void Splat(Value* other);
|
||||||
|
void VectorCompareEQ(Value* other, TypeName type);
|
||||||
|
void VectorCompareSGT(Value* other, TypeName type);
|
||||||
|
void VectorConvertI2F(Value* other);
|
||||||
|
void VectorConvertF2I(Value* other);
|
||||||
|
void VectorShl(Value* other, TypeName type);
|
||||||
|
void VectorShr(Value* other, TypeName type);
|
||||||
|
void VectorRol(Value* other, TypeName type);
|
||||||
|
void VectorSub(Value* other, TypeName type, bool is_unsigned, bool saturate);
|
||||||
void ByteSwap();
|
void ByteSwap();
|
||||||
void CountLeadingZeros(const Value* other);
|
void CountLeadingZeros(const Value* other);
|
||||||
bool Compare(Opcode opcode, Value* other);
|
bool Compare(Opcode opcode, Value* other);
|
||||||
|
|
Loading…
Reference in New Issue