remove SkVM Q14 support
Now that I've been reminded that half-float compute is real and no
longer just a dream, Q14 kind of pales in comparison, and just gets in
my way when working on SkVM.
As usual I've left in assembler support and unit tests for those
instructions. The instructions are all pretty easy to keep working and
tested and don't get in the way, unlike the real "let's do Q14" stuff.
None of this Q14 code was hooked up to anything but unit tests, so no
capability lost here, and no diffs. As always, it'll be easy to restore
should we ever want to by looking at this CL.
Change-Id: Ia42a96652b381267a7c3ec563b5978efcfc717a7
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/338630
Auto-Submit: Mike Klein <mtklein@google.com>
Commit-Queue: Mike Reed <reed@google.com>
Reviewed-by: Mike Reed <reed@google.com>
diff --git a/src/core/SkVM.cpp b/src/core/SkVM.cpp
index 52e53c7..514c372 100644
--- a/src/core/SkVM.cpp
+++ b/src/core/SkVM.cpp
@@ -246,8 +246,7 @@
case Op::uniform16: write(o, V{id}, "=", op, Arg{immy}, Hex{immz}); break;
case Op::uniform32: write(o, V{id}, "=", op, Arg{immy}, Hex{immz}); break;
- case Op::splat: write(o, V{id}, "=", op, Splat{immy}); break;
- case Op::splat_q14: write(o, V{id}, "=", op, Splat{immy}); break;
+ case Op::splat: write(o, V{id}, "=", op, Splat{immy}); break;
case Op:: add_f32: write(o, V{id}, "=", op, V{x}, V{y} ); break;
case Op:: sub_f32: write(o, V{id}, "=", op, V{x}, V{y} ); break;
@@ -280,36 +279,12 @@
case Op::gt_i32: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::add_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::sub_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::mul_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
-
- case Op::shl_q14: write(o, V{id}, "=", op, V{x}, Shift{immy}); break;
- case Op::shr_q14: write(o, V{id}, "=", op, V{x}, Shift{immy}); break;
- case Op::sra_q14: write(o, V{id}, "=", op, V{x}, Shift{immy}); break;
-
- case Op:: min_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op:: max_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::uavg_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
-
- case Op::eq_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::gt_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
-
- case Op::bit_and_q14 : write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::bit_or_q14 : write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::bit_xor_q14 : write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::bit_clear_q14: write(o, V{id}, "=", op, V{x}, V{y}); break;
-
- case Op::from_q14: write(o, V{id}, "=", op, V{x}); break;
- case Op:: to_q14: write(o, V{id}, "=", op, V{x}); break;
-
case Op::bit_and : write(o, V{id}, "=", op, V{x}, V{y}); break;
case Op::bit_or : write(o, V{id}, "=", op, V{x}, V{y}); break;
case Op::bit_xor : write(o, V{id}, "=", op, V{x}, V{y}); break;
case Op::bit_clear: write(o, V{id}, "=", op, V{x}, V{y}); break;
- case Op::select: write(o, V{id}, "=", op, V{x}, V{y}, V{z}); break;
- case Op::select_q14: write(o, V{id}, "=", op, V{x}, V{y}, V{z}); break;
+ case Op::select: write(o, V{id}, "=", op, V{x}, V{y}, V{z}); break;
case Op::ceil: write(o, V{id}, "=", op, V{x}); break;
case Op::floor: write(o, V{id}, "=", op, V{x}); break;
@@ -386,8 +361,6 @@
case Op::uniform32: write(o, R{d}, "=", op, Arg{immy}, Hex{immz}); break;
case Op::splat: write(o, R{d}, "=", op, Splat{immy}); break;
- case Op::splat_q14: write(o, R{d}, "=", op, Splat{immy}); break;
-
case Op::add_f32: write(o, R{d}, "=", op, R{x}, R{y} ); break;
case Op::sub_f32: write(o, R{d}, "=", op, R{x}, R{y} ); break;
@@ -418,37 +391,12 @@
case Op::eq_i32: write(o, R{d}, "=", op, R{x}, R{y}); break;
case Op::gt_i32: write(o, R{d}, "=", op, R{x}, R{y}); break;
-
- case Op::add_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::sub_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::mul_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
-
- case Op::shl_q14: write(o, R{d}, "=", op, R{x}, Shift{immy}); break;
- case Op::shr_q14: write(o, R{d}, "=", op, R{x}, Shift{immy}); break;
- case Op::sra_q14: write(o, R{d}, "=", op, R{x}, Shift{immy}); break;
-
- case Op:: min_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op:: max_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::uavg_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
-
- case Op::eq_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::gt_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
-
- case Op::bit_and_q14 : write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::bit_or_q14 : write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::bit_xor_q14 : write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::bit_clear_q14: write(o, R{d}, "=", op, R{x}, R{y}); break;
-
- case Op::from_q14: write(o, R{d}, "=", op, R{x}); break;
- case Op:: to_q14: write(o, R{d}, "=", op, R{x}); break;
-
case Op::bit_and : write(o, R{d}, "=", op, R{x}, R{y}); break;
case Op::bit_or : write(o, R{d}, "=", op, R{x}, R{y}); break;
case Op::bit_xor : write(o, R{d}, "=", op, R{x}, R{y}); break;
case Op::bit_clear: write(o, R{d}, "=", op, R{x}, R{y}); break;
- case Op::select: write(o, R{d}, "=", op, R{x}, R{y}, R{z}); break;
- case Op::select_q14: write(o, R{d}, "=", op, R{x}, R{y}, R{z}); break;
+ case Op::select: write(o, R{d}, "=", op, R{x}, R{y}, R{z}); break;
case Op::ceil: write(o, R{d}, "=", op, R{x}); break;
case Op::floor: write(o, R{d}, "=", op, R{x}); break;
@@ -667,7 +615,6 @@
memcpy(imm, &fProgram[id].immy, 4);
return this->allImm(rest...);
}
- // TODO: Op::splat_q14
return false;
}
@@ -727,8 +674,7 @@
return {this, push(Op::uniform32, NA,NA,NA, ptr.ix, offset)};
}
- I32 Builder::splat (int n) { return {this, push(Op::splat , NA,NA,NA, n) }; }
- Q14 Builder::splat_q14(int n) { return {this, push(Op::splat_q14, NA,NA,NA, n) }; }
+ I32 Builder::splat(int n) { return {this, push(Op::splat , NA,NA,NA, n) }; }
bool fma_supported() {
static const bool supported =
@@ -972,45 +918,6 @@
return {this, this->push(Op::max_f32, x.id, y.id)};
}
- // TODO: constant propagation and strength reduction for all these Q14 ops
- Q14 Builder::add(Q14 x, Q14 y) { return {this, this->push(Op::add_q14, x.id, y.id)}; }
- Q14 Builder::sub(Q14 x, Q14 y) { return {this, this->push(Op::sub_q14, x.id, y.id)}; }
- Q14 Builder::mul(Q14 x, Q14 y) { return {this, this->push(Op::mul_q14, x.id, y.id)}; }
-
- Q14 Builder::shl(Q14 x, int k) { return {this, this->push(Op::shl_q14, x.id,NA,NA,k)}; }
- Q14 Builder::shr(Q14 x, int k) { return {this, this->push(Op::shr_q14, x.id,NA,NA,k)}; }
- Q14 Builder::sra(Q14 x, int k) { return {this, this->push(Op::sra_q14, x.id,NA,NA,k)}; }
-
- Q14 Builder:: eq(Q14 x, Q14 y) { return {this, this->push(Op::eq_q14, x.id, y.id)}; }
- Q14 Builder::gt (Q14 x, Q14 y) { return {this, this->push(Op::gt_q14, x.id, y.id)}; }
- Q14 Builder::lt (Q14 x, Q14 y) { return gt(y,x); }
- Q14 Builder::neq(Q14 x, Q14 y) { return ~eq(x,y); }
- Q14 Builder::gte(Q14 x, Q14 y) { return ~lt(x,y); }
- Q14 Builder::lte(Q14 x, Q14 y) { return ~gt(x,y); }
-
- Q14 Builder::min(Q14 x, Q14 y) { return {this, this->push(Op::min_q14, x.id, y.id)}; }
- Q14 Builder::max(Q14 x, Q14 y) { return {this, this->push(Op::max_q14, x.id, y.id)}; }
-
- Q14 Builder::bit_and (Q14 x, Q14 y) { return {this, this->push(Op::bit_and_q14 ,x.id,y.id)}; }
- Q14 Builder::bit_or (Q14 x, Q14 y) { return {this, this->push(Op::bit_or_q14 ,x.id,y.id)}; }
- Q14 Builder::bit_xor (Q14 x, Q14 y) { return {this, this->push(Op::bit_xor_q14 ,x.id,y.id)}; }
- Q14 Builder::bit_clear(Q14 x, Q14 y) { return {this, this->push(Op::bit_clear_q14,x.id,y.id)}; }
-
- Q14 Builder::select(Q14 cond, Q14 t, Q14 f) {
- return {this, this->push(Op::select_q14, cond.id, t.id, f.id)};
- }
-
- Q14 Builder::to_Q14(I32 x) { return {this, this->push(Op:: to_q14, x.id) }; }
- I32 Builder::to_I32(Q14 x) { return {this, this->push(Op::from_q14, x.id) }; }
-
- // TODO: open question in general whether float -> q14 should round() or trunc().
- Q14 Builder::to_Q14(F32 x) { return to_Q14(trunc(x * 16384.0f)); }
- F32 Builder::to_F32(Q14 x) { return to_F32(to_I32(x)) * (1/16384.0f); }
-
- Q14 Builder::unsigned_avg(Q14 x, Q14 y) {
- return {this, this->push(Op::uavg_q14, x.id, y.id)};
- }
-
I32 Builder::add(I32 x, I32 y) {
if (int X,Y; this->allImm(x.id,&X, y.id,&Y)) { return splat(X+Y); }
if (this->isImm(x.id, 0)) { return y; }
@@ -3255,7 +3162,7 @@
#endif
auto load_from_memory = [&](Reg r, Val v) {
- if (instructions[v].op == Op::splat || instructions[v].op == Op::splat_q14) {
+ if (instructions[v].op == Op::splat) {
if (instructions[v].immy == 0) {
a->vpxor(r,r,r);
} else {
@@ -3292,7 +3199,7 @@
a->ret(A::x30); };
auto load_from_memory = [&](Reg r, Val v) {
- if (instructions[v].op == Op::splat || instructions[v].op == Op::splat_q14) {
+ if (instructions[v].op == Op::splat) {
if (instructions[v].immy == 0) {
a->eor16b(r,r,r);
} else {
@@ -3355,8 +3262,7 @@
SkASSERT(v == NA || v >= 0);
if (v >= 0) {
- if (stack_slot[v] == NA && instructions[v].op != Op::splat
- && instructions[v].op != Op::splat_q14) {
+ if (stack_slot[v] == NA && instructions[v].op != Op::splat) {
store_to_stack(r, v);
}
v = NA;
@@ -3460,7 +3366,7 @@
if (int found = find_existing_reg(v); found != NA) {
return (Reg)found;
}
- if (instructions[v].op == Op::splat || instructions[v].op == Op::splat_q14) {
+ if (instructions[v].op == Op::splat) {
return constants.find(instructions[v].immy);
}
return A::Mem{A::rsp, stack_slot[v]*K*4};
@@ -3476,7 +3382,6 @@
switch (op) {
// Make sure splat constants can be found by load_from_memory() or any().
case Op::splat:
- case Op::splat_q14:
(void)constants[immy];
break;
@@ -3741,85 +3646,43 @@
else { a->vpaddd(dst(y), r(y), any(x)); }
break;
- case Op::add_q14:
- if (in_reg(x)) { a->vpaddw(dst(x), r(x), any(y)); }
- else { a->vpaddw(dst(y), r(y), any(x)); }
- break;
-
case Op::mul_i32:
if (in_reg(x)) { a->vpmulld(dst(x), r(x), any(y)); }
else { a->vpmulld(dst(y), r(y), any(x)); }
break;
- case Op::mul_q14:
- if (in_reg(x)) { a->vpmulhrsw(dst(x), r(x), any(y)); }
- else { a->vpmulhrsw(dst(y), r(y), any(x)); }
- a->vpaddw(dst(), dst(), dst()); // << 1
- break;
-
case Op::sub_i32: a->vpsubd(dst(x), r(x), any(y)); break;
- case Op::sub_q14: a->vpsubw(dst(x), r(x), any(y)); break;
case Op::bit_and:
- case Op::bit_and_q14:
if (in_reg(x)) { a->vpand(dst(x), r(x), any(y)); }
else { a->vpand(dst(y), r(y), any(x)); }
break;
case Op::bit_or:
- case Op::bit_or_q14:
if (in_reg(x)) { a->vpor(dst(x), r(x), any(y)); }
else { a->vpor(dst(y), r(y), any(x)); }
break;
case Op::bit_xor:
- case Op::bit_xor_q14:
if (in_reg(x)) { a->vpxor(dst(x), r(x), any(y)); }
else { a->vpxor(dst(y), r(y), any(x)); }
break;
- case Op::bit_clear:
- case Op::bit_clear_q14: a->vpandn(dst(y), r(y), any(x)); break; // Notice, y then x.
+ case Op::bit_clear: a->vpandn(dst(y), r(y), any(x)); break; // Notice, y then x.
case Op::select:
- case Op::select_q14:
if (try_alias(z)) { a->vpblendvb(dst(z), r(z), any(y), r(x)); }
else { a->vpblendvb(dst(x), r(z), any(y), r(x)); }
break;
- case Op::min_q14:
- if (in_reg(x)) { a->vpminsw(dst(x), r(x), any(y)); }
- else { a->vpminsw(dst(y), r(y), any(x)); }
- break;
-
- case Op::max_q14:
- if (in_reg(x)) { a->vpmaxsw(dst(x), r(x), any(y)); }
- else { a->vpmaxsw(dst(y), r(y), any(x)); }
- break;
-
- case Op::uavg_q14:
- if (in_reg(x)) { a->vpavgw(dst(x), r(x), any(y)); }
- else { a->vpavgw(dst(y), r(y), any(x)); }
- break;
-
case Op::shl_i32: a->vpslld(dst(x), r(x), immy); break;
case Op::shr_i32: a->vpsrld(dst(x), r(x), immy); break;
case Op::sra_i32: a->vpsrad(dst(x), r(x), immy); break;
- case Op::shl_q14: a->vpsllw(dst(x), r(x), immy); break;
- case Op::shr_q14: a->vpsrlw(dst(x), r(x), immy); break;
- case Op::sra_q14: a->vpsraw(dst(x), r(x), immy); break;
-
case Op::eq_i32:
if (in_reg(x)) { a->vpcmpeqd(dst(x), r(x), any(y)); }
else { a->vpcmpeqd(dst(y), r(y), any(x)); }
break;
- case Op::eq_q14:
- if (in_reg(x)) { a->vpcmpeqw(dst(x), r(x), any(y)); }
- else { a->vpcmpeqw(dst(y), r(y), any(x)); }
- break;
-
case Op::gt_i32: a->vpcmpgtd(dst(), r(x), any(y)); break;
- case Op::gt_q14: a->vpcmpgtw(dst(), r(x), any(y)); break;
case Op::eq_f32:
if (in_reg(x)) { a->vcmpeqps(dst(x), r(x), any(y)); }
@@ -3869,10 +3732,6 @@
a->vcvtph2ps(dst(), dst()); // f16 xmm -> f32 ymm
break;
- // These are both no-ops because we're storing Q14 values in even lanes.
- case Op::from_q14: if (!try_alias(x)) { a->vmovdqa(dst(), any(x)); } break;
- case Op::to_q14: if (!try_alias(x)) { a->vmovdqa(dst(), any(x)); } break;
-
#elif defined(__aarch64__)
default: // TODO
if (false) {
diff --git a/src/core/SkVM.h b/src/core/SkVM.h
index a707263..b864252 100644
--- a/src/core/SkVM.h
+++ b/src/core/SkVM.h
@@ -424,24 +424,21 @@
M(load8) M(load16) M(load32) M(load64) M(load128) \
M(gather8) M(gather16) M(gather32) \
M(uniform8) M(uniform16) M(uniform32) \
- M(splat) M(splat_q14) \
- M(add_f32) M(add_i32) M(add_q14) \
- M(sub_f32) M(sub_i32) M(sub_q14) \
- M(mul_f32) M(mul_i32) M(mul_q14) \
+ M(splat) \
+ M(add_f32) M(add_i32) \
+ M(sub_f32) M(sub_i32) \
+ M(mul_f32) M(mul_i32) \
M(div_f32) \
M(min_f32) M(max_f32) \
- M(min_q14) M(max_q14) M(uavg_q14) \
M(fma_f32) M(fms_f32) M(fnma_f32) \
M(sqrt_f32) \
M(shl_i32) M(shr_i32) M(sra_i32) \
- M(shl_q14) M(shr_q14) M(sra_q14) \
M(ceil) M(floor) M(trunc) M(round) M(to_half) M(from_half) \
- M(to_f32) M(to_q14) M(from_q14) \
- M(neq_f32) M(eq_f32) M(eq_i32) M(eq_q14) \
- M(gte_f32) M(gt_f32) M(gt_i32) M(gt_q14) \
+ M(to_f32) \
+ M(neq_f32) M(eq_f32) M(eq_i32) \
+ M(gte_f32) M(gt_f32) M(gt_i32) \
M(bit_and) M(bit_or) M(bit_xor) M(bit_clear) \
- M(bit_and_q14) M(bit_or_q14) M(bit_xor_q14) M(bit_clear_q14) \
- M(select) M(select_q14)
+ M(select)
// End of SKVM_OPS
enum class Op : int {
@@ -478,13 +475,6 @@
Builder* operator->() const { return builder; }
};
- struct Q14 {
- Builder* builder = nullptr;
- Val id = NA;
- explicit operator bool() const { return id != NA; }
- Builder* operator->() const { return builder; }
- };
-
// Some operations make sense with immediate arguments,
// so we use I32a and F32a to receive them transparently.
//
@@ -516,16 +506,6 @@
float imm = 0;
};
- struct Q14a {
- Q14a(Q14 v) : SkDEBUGCODE(builder(v.builder),) id(v.id) {}
- Q14a(int bits) : imm{SkTo<int16_t>(bits)} {} // 0x0000'4000 -> 0x4000
- Q14a(float f) : Q14a{(int)(f * 16384.0f)} {} // 1.0f -> 0x4000
-
- SkDEBUGCODE(Builder* builder = nullptr;)
- Val id = NA;
- int16_t imm = 0;
- };
-
struct Color {
F32 r,g,b,a;
explicit operator bool() const { return r && g && b && a; }
@@ -538,12 +518,6 @@
Builder* operator->() const { return a.operator->(); }
};
- struct Color_Q14 {
- Q14 r,g,b,a;
- explicit operator bool() const { return r && g && b && a; }
- Builder* operator->() const { return a.operator->(); }
- };
-
struct Coord {
F32 x,y;
explicit operator bool() const { return x && y; }
@@ -693,11 +667,6 @@
return bit_cast(splat(bits));
}
- // Load an immediate Q14, expressed as either integer (16384, 0x4000) or float (1.0f).
- Q14 splat_q14(int n);
- Q14 splat_q14(unsigned u) { return splat_q14((int)u); }
- Q14 splat_q14(float f) { return splat_q14(Q14a{f}.imm); }
-
// float math, comparisons, etc.
F32 add(F32, F32); F32 add(F32a x, F32a y) { return add(_(x), _(y)); }
F32 sub(F32, F32); F32 sub(F32a x, F32a y) { return sub(_(x), _(y)); }
@@ -797,11 +766,8 @@
return bit_cast(select(cond, bit_cast(t)
, bit_cast(f)));
}
- Q14 select(Q14 cond, Q14 t, Q14 f);
-
I32 select(I32a cond, I32a t, I32a f) { return select(_(cond), _(t), _(f)); }
F32 select(I32a cond, F32a t, F32a f) { return select(_(cond), _(t), _(f)); }
- Q14 select(Q14a cond, Q14a t, Q14a f) { return select(_(cond), _(t), _(f)); }
I32 extract(I32 x, int bits, I32 z); // (x>>bits) & z
I32 pack (I32 x, I32 y, int bits); // x | (y<<bits)
@@ -809,35 +775,6 @@
I32 extract(I32a x, int bits, I32a z) { return extract(_(x), bits, _(z)); }
I32 pack (I32a x, I32a y, int bits) { return pack (_(x), _(y), bits); }
- Q14 add(Q14, Q14); Q14 add(Q14a x, Q14a y) { return add(_(x), _(y)); }
- Q14 sub(Q14, Q14); Q14 sub(Q14a x, Q14a y) { return sub(_(x), _(y)); }
- Q14 mul(Q14, Q14); Q14 mul(Q14a x, Q14a y) { return mul(_(x), _(y)); }
-
- Q14 min(Q14, Q14); Q14 min(Q14a x, Q14a y) { return min(_(x), _(y)); }
- Q14 max(Q14, Q14); Q14 max(Q14a x, Q14a y) { return max(_(x), _(y)); }
-
- Q14 shl(Q14, int bits);
- Q14 shr(Q14, int bits);
- Q14 sra(Q14, int bits);
-
- Q14 eq (Q14, Q14); Q14 eq(Q14a x, Q14a y) { return eq(_(x), _(y)); }
- Q14 neq(Q14, Q14); Q14 neq(Q14a x, Q14a y) { return neq(_(x), _(y)); }
- Q14 lt (Q14, Q14); Q14 lt (Q14a x, Q14a y) { return lt (_(x), _(y)); }
- Q14 lte(Q14, Q14); Q14 lte(Q14a x, Q14a y) { return lte(_(x), _(y)); }
- Q14 gt (Q14, Q14); Q14 gt (Q14a x, Q14a y) { return gt (_(x), _(y)); }
- Q14 gte(Q14, Q14); Q14 gte(Q14a x, Q14a y) { return gte(_(x), _(y)); }
-
- Q14 bit_and (Q14, Q14); Q14 bit_and (Q14a x, Q14a y) { return bit_and (_(x), _(y)); }
- Q14 bit_or (Q14, Q14); Q14 bit_or (Q14a x, Q14a y) { return bit_or (_(x), _(y)); }
- Q14 bit_xor (Q14, Q14); Q14 bit_xor (Q14a x, Q14a y) { return bit_xor (_(x), _(y)); }
- Q14 bit_clear(Q14, Q14); Q14 bit_clear(Q14a x, Q14a y) { return bit_clear(_(x), _(y)); }
-
- Q14 unsigned_avg(Q14 x, Q14 y); // (x+y+1)>>1
- Q14 unsigned_avg(Q14a x, Q14a y) { return unsigned_avg(_(x), _(y)); }
-
- Q14 to_Q14(F32); F32 to_F32(Q14); // Converts values, e.g. 0x4000 <-> 1.0f
- Q14 to_Q14(I32); I32 to_I32(Q14); // Preserves bits, e.g. 0x4000 <-> 0x00004000
-
// Common idioms used in several places, worth centralizing for consistency.
F32 from_unorm(int bits, I32); // E.g. from_unorm(8, x) -> x * (1/255.0f)
I32 to_unorm(int bits, F32); // E.g. to_unorm(8, x) -> round(x * 255)
@@ -891,14 +828,6 @@
return splat(x.imm);
}
- Q14 _(Q14a x) {
- if (x.id != NA) {
- SkASSERT(x.builder == this);
- return {this, x.id};
- }
- return splat_q14(x.imm);
- }
-
bool allImm() const;
template <typename T, typename... Rest>
@@ -985,44 +914,6 @@
// TODO: control flow
// TODO: 64-bit values?
- static inline Q14 operator+(Q14 x, Q14a y) { return x->add(x,y); }
- static inline Q14 operator+(float x, Q14 y) { return y->add(x,y); }
-
- static inline Q14 operator-(Q14 x, Q14a y) { return x->sub(x,y); }
- static inline Q14 operator-(float x, Q14 y) { return y->sub(x,y); }
-
- static inline Q14 operator*(Q14 x, Q14a y) { return x->mul(x,y); }
- static inline Q14 operator*(float x, Q14 y) { return y->mul(x,y); }
-
- static inline Q14 min(Q14 x, Q14a y) { return x->min(x,y); }
- static inline Q14 min(float x, Q14 y) { return y->min(x,y); }
-
- static inline Q14 max(Q14 x, Q14a y) { return x->max(x,y); }
- static inline Q14 max(float x, Q14 y) { return y->max(x,y); }
-
- static inline Q14 unsigned_avg(Q14 x, Q14a y) { return x->unsigned_avg(x,y); }
- static inline Q14 unsigned_avg(float x, Q14 y) { return y->unsigned_avg(x,y); }
-
- static inline Q14 operator==(Q14 x, Q14 y) { return x->eq(x,y); }
- static inline Q14 operator==(Q14 x, float y) { return x->eq(x,y); }
- static inline Q14 operator==(float x, Q14 y) { return y->eq(x,y); }
-
- static inline Q14 operator!=(Q14 x, Q14 y) { return x->neq(x,y); }
- static inline Q14 operator!=(Q14 x, float y) { return x->neq(x,y); }
- static inline Q14 operator!=(float x, Q14 y) { return y->neq(x,y); }
-
- static inline Q14 operator< (Q14 x, Q14a y) { return x->lt(x,y); }
- static inline Q14 operator< (float x, Q14 y) { return y->lt(x,y); }
-
- static inline Q14 operator<=(Q14 x, Q14a y) { return x->lte(x,y); }
- static inline Q14 operator<=(float x, Q14 y) { return y->lte(x,y); }
-
- static inline Q14 operator> (Q14 x, Q14a y) { return x->gt(x,y); }
- static inline Q14 operator> (float x, Q14 y) { return y->gt(x,y); }
-
- static inline Q14 operator>=(Q14 x, Q14a y) { return x->gte(x,y); }
- static inline Q14 operator>=(float x, Q14 y) { return y->gte(x,y); }
-
static inline I32 operator+(I32 x, I32a y) { return x->add(x,y); }
static inline I32 operator+(int x, I32 y) { return y->add(x,y); }
@@ -1098,10 +989,6 @@
static inline I32 operator>=(F32 x, F32a y) { return x->gte(x,y); }
static inline I32 operator>=(float x, F32 y) { return y->gte(x,y); }
- static inline Q14& operator+=(Q14& x, Q14a y) { return (x = x + y); }
- static inline Q14& operator-=(Q14& x, Q14a y) { return (x = x - y); }
- static inline Q14& operator*=(Q14& x, Q14a y) { return (x = x * y); }
-
static inline I32& operator+=(I32& x, I32a y) { return (x = x + y); }
static inline I32& operator-=(I32& x, I32a y) { return (x = x - y); }
static inline I32& operator*=(I32& x, I32a y) { return (x = x * y); }
@@ -1165,11 +1052,6 @@
static inline I32 to_half(F32 x) { return x-> to_half(x); }
static inline F32 from_half(I32 x) { return x->from_half(x); }
- static inline F32 to_F32(Q14 x) { return x->to_F32(x); }
- static inline I32 to_I32(Q14 x) { return x->to_I32(x); }
- static inline Q14 to_Q14(F32 x) { return x->to_Q14(x); }
- static inline Q14 to_Q14(I32 x) { return x->to_Q14(x); }
-
static inline F32 lerp(F32 lo, F32a hi, F32a t) { return lo->lerp(lo,hi,t); }
static inline F32 lerp(float lo, F32 hi, F32a t) { return hi->lerp(lo,hi,t); }
static inline F32 lerp(float lo, float hi, F32 t) { return t->lerp(lo,hi,t); }
@@ -1186,12 +1068,6 @@
static inline I32 shr(I32 x, int bits) { return x->shr(x, bits); }
static inline I32 sra(I32 x, int bits) { return x->sra(x, bits); }
- static inline Q14 operator<<(Q14 x, int bits) { return x->shl(x, bits); }
- static inline Q14 shl(Q14 x, int bits) { return x->shl(x, bits); }
- static inline Q14 shr(Q14 x, int bits) { return x->shr(x, bits); }
- static inline Q14 sra(Q14 x, int bits) { return x->sra(x, bits); }
- static inline Q14 operator>>(Q14 x, int bits) { return x->sra(x, bits); }
-
static inline I32 operator&(I32 x, I32a y) { return x->bit_and(x,y); }
static inline I32 operator&(int x, I32 y) { return y->bit_and(x,y); }
@@ -1205,25 +1081,11 @@
static inline I32& operator|=(I32& x, I32a y) { return (x = x | y); }
static inline I32& operator^=(I32& x, I32a y) { return (x = x ^ y); }
- static inline Q14 operator&(Q14 x, Q14a y) { return x->bit_and(x,y); }
- static inline Q14 operator&(int x, Q14 y) { return y->bit_and(x,y); }
-
- static inline Q14 operator|(Q14 x, Q14a y) { return x->bit_or(x,y); }
- static inline Q14 operator|(int x, Q14 y) { return y->bit_or(x,y); }
-
- static inline Q14 operator^(Q14 x, Q14a y) { return x->bit_xor(x,y); }
- static inline Q14 operator^(int x, Q14 y) { return y->bit_xor(x,y); }
-
- static inline Q14& operator&=(Q14& x, Q14a y) { return (x = x & y); }
- static inline Q14& operator|=(Q14& x, Q14a y) { return (x = x | y); }
- static inline Q14& operator^=(Q14& x, Q14a y) { return (x = x ^ y); }
-
static inline I32 bit_clear(I32 x, I32a y) { return x->bit_clear(x,y); }
static inline I32 bit_clear(int x, I32 y) { return y->bit_clear(x,y); }
static inline I32 select(I32 cond, I32a t, I32a f) { return cond->select(cond,t,f); }
static inline F32 select(I32 cond, F32a t, F32a f) { return cond->select(cond,t,f); }
- static inline Q14 select(Q14 cond, Q14a t, Q14a f) { return cond->select(cond,t,f); }
static inline I32 extract(I32 x, int bits, I32a z) { return x->extract(x,bits,z); }
static inline I32 extract(int x, int bits, I32 z) { return z->extract(x,bits,z); }
@@ -1231,9 +1093,7 @@
static inline I32 pack (int x, I32 y, int bits) { return y->pack (x,y,bits); }
static inline I32 operator~(I32 x) { return ~0 ^ x; }
- static inline Q14 operator~(Q14 x) { return ~0 ^ x; }
static inline I32 operator-(I32 x) { return 0 - x; }
- static inline Q14 operator-(Q14 x) { return 0 - x; }
static inline F32 operator-(F32 x) { return 0.0f - x; }
static inline F32 from_unorm(int bits, I32 x) { return x->from_unorm(bits,x); }
diff --git a/src/core/SkVM_fwd.h b/src/core/SkVM_fwd.h
index e05d5c9..ed1b5c6 100644
--- a/src/core/SkVM_fwd.h
+++ b/src/core/SkVM_fwd.h
@@ -16,7 +16,6 @@
struct I32;
struct F32;
struct Color;
- struct Color_Q14;
struct Coord;
struct Uniforms;
} // namespace skvm
diff --git a/src/opts/SkVM_opts.h b/src/opts/SkVM_opts.h
index a169f8f..da39ae0 100644
--- a/src/opts/SkVM_opts.h
+++ b/src/opts/SkVM_opts.h
@@ -7,36 +7,6 @@
#include "include/private/SkVx.h"
#include "src/core/SkVM.h"
-// Ideally this is (x*y + 0x2000)>>14,
-// but to let use vpmulhrsw we'll approximate that as ((x*y + 0x4000)>>15)<<1.
-template <int N>
-static inline skvx::Vec<N,int16_t> mul_q14(const skvx::Vec<N,int16_t>& x,
- const skvx::Vec<N,int16_t>& y) {
-#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2
- if constexpr (N == 16) {
- return skvx::bit_pun<skvx::Vec<N,int16_t>>(_mm256_mulhrs_epi16(skvx::bit_pun<__m256i>(x),
- skvx::bit_pun<__m256i>(y)))
- << 1;
- }
-#endif
-#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSSE3
- if constexpr (N == 8) {
- return skvx::bit_pun<skvx::Vec<N,int16_t>>(_mm_mulhrs_epi16(skvx::bit_pun<__m128i>(x),
- skvx::bit_pun<__m128i>(y)))
- << 1;
- }
-#endif
- // TODO: NEON specialization with vqrdmulh.s16?
-
- // Try to recurse onto the specializations above.
- if constexpr (N > 8) {
- return join(mul_q14(x.lo, y.lo),
- mul_q14(x.hi, y.hi));
- }
- return skvx::cast<int16_t>((skvx::cast<int>(x) *
- skvx::cast<int>(y) + 0x4000)>>15 ) <<1;
-}
-
template <int N>
static inline skvx::Vec<N,int> gather32(const int* ptr, const skvx::Vec<N,int>& ix) {
#if SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_AVX2
@@ -302,41 +272,6 @@
r[d].f32 = skvx::from_half(skvx::cast<uint16_t>(r[x].i32));
break;
- CASE(Op::splat_q14): r[d].i16 = immy; break;
-
- CASE(Op::add_q14): r[d].i16 = r[x].i16 + r[y].i16; break;
- CASE(Op::sub_q14): r[d].i16 = r[x].i16 - r[y].i16; break;
- CASE(Op::mul_q14): r[d].i16 = mul_q14(r[x].i16, r[y].i16); break;
-
- CASE(Op::shl_q14): r[d].i16 = r[x].i16 << immy; break;
- CASE(Op::sra_q14): r[d].i16 = r[x].i16 >> immy; break;
- CASE(Op::shr_q14): r[d].u16 = r[x].u16 >> immy; break;
-
- CASE(Op::eq_q14): r[d].i16 = r[x].i16 == r[y].i16; break;
- CASE(Op::gt_q14): r[d].i16 = r[x].i16 > r[y].i16; break;
-
- CASE(Op::min_q14): r[d].i16 = min(r[x].i16, r[y].i16); break;
- CASE(Op::max_q14): r[d].i16 = max(r[x].i16, r[y].i16); break;
-
- CASE(Op::bit_and_q14): r[d].i16 = r[x].i16 & r[y].i16; break;
- CASE(Op::bit_or_q14 ): r[d].i16 = r[x].i16 | r[y].i16; break;
- CASE(Op::bit_xor_q14): r[d].i16 = r[x].i16 ^ r[y].i16; break;
- CASE(Op::bit_clear_q14): r[d].i16 = r[x].i16 & ~r[y].i16; break;
-
- CASE(Op::select_q14):
- r[d].i16 = skvx::if_then_else(r[x].i16, r[y].i16, r[z].i16);
- break;
-
- // Happily, Clang can see through this one and generates perfect code
- // using vpavgw without any help from us!
- CASE(Op::uavg_q14):
- r[d].u16 = skvx::cast<uint16_t>( (skvx::cast<int>(r[x].u16) +
- skvx::cast<int>(r[y].u16) + 1)>>1 );
- break;
-
- CASE(Op::to_q14): r[d].i16 = skvx::cast<int16_t>(r[x].i32); break;
- CASE(Op::from_q14): r[d].i32 = skvx::cast<int32_t>(r[x].i16); break;
-
#undef CASE
}
}
diff --git a/tests/SkVMTest.cpp b/tests/SkVMTest.cpp
index fcd10f6..a11a499 100644
--- a/tests/SkVMTest.cpp
+++ b/tests/SkVMTest.cpp
@@ -2390,143 +2390,6 @@
});
}
-DEF_TEST(SkVM_Q14, r) {
- // Some nice round Q14 test values from -1.0 (0xc000) to +1.0 (0x4000) by 16ths (0x0400).
- const uint16_t src[] = {
- 0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000,
- };
-
- // These test cases are essentially mechanically generated to get coverage...
- // I've spot checked here and there and things seem correct, but I wouldn't
- // be surprised to find that there were bugs. Using nice round numbers to
- // avoid having to think about low-bit precision for now.
- struct {
- skvm::Q14 (*fn)(skvm::Q14);
- uint16_t expected[33];
- } cases[] = {
- {[](skvm::Q14 x) { return x; }, // Just double checking the test harness works.
- {0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000}},
-
- {[](skvm::Q14 x) { return x*x; }, // square ±1/16 (0x0400) -> 1/256 (0x0040), etc.
- {0x4000, 0x3840, 0x3100, 0x2a40, 0x2400, 0x1e40, 0x1900, 0x1440,
- 0x1000, 0x0c40, 0x0900, 0x0640, 0x0400, 0x0240, 0x0100, 0x0040,
- 0x0000,
- 0x0040, 0x0100, 0x0240, 0x0400, 0x0640, 0x0900, 0x0c40, 0x1000,
- 0x1440, 0x1900, 0x1e40, 0x2400, 0x2a40, 0x3100, 0x3840, 0x4000}},
-
- {[](skvm::Q14 x) { return -(x*-x); }, // square, version B
- {0x4000, 0x3840, 0x3100, 0x2a40, 0x2400, 0x1e40, 0x1900, 0x1440,
- 0x1000, 0x0c40, 0x0900, 0x0640, 0x0400, 0x0240, 0x0100, 0x0040,
- 0x0000,
- 0x0040, 0x0100, 0x0240, 0x0400, 0x0640, 0x0900, 0x0c40, 0x1000,
- 0x1440, 0x1900, 0x1e40, 0x2400, 0x2a40, 0x3100, 0x3840, 0x4000}},
-
- {[](skvm::Q14 x) { return x>>1; }, // divide by 2
- {0xe000, 0xe200, 0xe400, 0xe600, 0xe800, 0xea00, 0xec00, 0xee00,
- 0xf000, 0xf200, 0xf400, 0xf600, 0xf800, 0xfa00, 0xfc00, 0xfe00,
- 0x0000,
- 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00, 0x1000,
- 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00, 0x2000}},
-
- {[](skvm::Q14 x) { return shr(x,1); }, // logical shift by 1
- {0x6000, 0x6200, 0x6400, 0x6600, 0x6800, 0x6a00, 0x6c00, 0x6e00,
- 0x7000, 0x7200, 0x7400, 0x7600, 0x7800, 0x7a00, 0x7c00, 0x7e00,
- 0x0000,
- 0x0200, 0x0400, 0x0600, 0x0800, 0x0a00, 0x0c00, 0x0e00, 0x1000,
- 0x1200, 0x1400, 0x1600, 0x1800, 0x1a00, 0x1c00, 0x1e00, 0x2000}},
-
- {[](skvm::Q14 x) { return x - (x>>2); }, // 3/4 x, version A
- {0xd000, 0xd300, 0xd600, 0xd900, 0xdc00, 0xdf00, 0xe200, 0xe500,
- 0xe800, 0xeb00, 0xee00, 0xf100, 0xf400, 0xf700, 0xfa00, 0xfd00,
- 0x0000,
- 0x0300, 0x0600, 0x0900, 0x0c00, 0x0f00, 0x1200, 0x1500, 0x1800,
- 0x1b00, 0x1e00, 0x2100, 0x2400, 0x2700, 0x2a00, 0x2d00, 0x3000}},
-
- {[](skvm::Q14 x) { return (x>>1) + (x>>2); }, // 3/4 x, version B
- {0xd000, 0xd300, 0xd600, 0xd900, 0xdc00, 0xdf00, 0xe200, 0xe500,
- 0xe800, 0xeb00, 0xee00, 0xf100, 0xf400, 0xf700, 0xfa00, 0xfd00,
- 0x0000,
- 0x0300, 0x0600, 0x0900, 0x0c00, 0x0f00, 0x1200, 0x1500, 0x1800,
- 0x1b00, 0x1e00, 0x2100, 0x2400, 0x2700, 0x2a00, 0x2d00, 0x3000}},
-
- {[](skvm::Q14 x) { return ((x>>2) + (x>>3))<<1; }, // 3/4 x, version C
- {0xd000, 0xd300, 0xd600, 0xd900, 0xdc00, 0xdf00, 0xe200, 0xe500,
- 0xe800, 0xeb00, 0xee00, 0xf100, 0xf400, 0xf700, 0xfa00, 0xfd00,
- 0x0000,
- 0x0300, 0x0600, 0x0900, 0x0c00, 0x0f00, 0x1200, 0x1500, 0x1800,
- 0x1b00, 0x1e00, 0x2100, 0x2400, 0x2700, 0x2a00, 0x2d00, 0x3000}},
-
- // TODO: I'm not sure if this one is working correctly or not. Should only work for >=0?
- {[](skvm::Q14 x) { return unsigned_avg(x, x>>1); }, // 3/4 x, version D
- {0xd000, 0xd300, 0xd600, 0xd900, 0xdc00, 0xdf00, 0xe200, 0xe500,
- 0xe800, 0xeb00, 0xee00, 0xf100, 0xf400, 0xf700, 0xfa00, 0xfd00,
- 0x0000,
- 0x0300, 0x0600, 0x0900, 0x0c00, 0x0f00, 0x1200, 0x1500, 0x1800,
- 0x1b00, 0x1e00, 0x2100, 0x2400, 0x2700, 0x2a00, 0x2d00, 0x3000}},
-
- {[](skvm::Q14 x) { return min(x, +0.5f); }, // clamp down to 0x2000, version A
- {0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000}},
-
- {[](skvm::Q14 x) { return select(x < +0.5f, x, +0.5f); }, // clamp down to 0x2000, vB
- {0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000, 0x2000}},
-
- {[](skvm::Q14 x) { return select(x == 1.0f, 0.5f, x); },
- {0xc000, 0xc400, 0xc800, 0xcc00, 0xd000, 0xd400, 0xd800, 0xdc00,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x2000}},
-
- {[](skvm::Q14 x) { return max(x, -0.5f); }, // clamp up to 0xe000
- {0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0xe000, 0xe000,
- 0xe000, 0xe400, 0xe800, 0xec00, 0xf000, 0xf400, 0xf800, 0xfc00,
- 0x0000,
- 0x0400, 0x0800, 0x0c00, 0x1000, 0x1400, 0x1800, 0x1c00, 0x2000,
- 0x2400, 0x2800, 0x2c00, 0x3000, 0x3400, 0x3800, 0x3c00, 0x4000}},
- };
-
- for (const auto& test : cases) {
- skvm::Builder b;
- {
- skvm::Arg dst = b.varying<uint16_t>(),
- src = b.varying<uint16_t>();
-
- skvm::Q14 x = to_Q14(b.load16(src));
- store16(dst, to_I32(test.fn(x)));
- }
-
- test_jit_and_interpreter(b.done(), [&](const skvm::Program& program){
- uint16_t dst[33];
- program.eval(33, dst,src);
- for (int i = 0; i < 33; i++) {
- if (test.expected[32]) {
- REPORTER_ASSERT(r, test.expected[i] == dst[i]);
- } else {
- if (i == 0 || i == 8 || i == 16 || i == 17 || i == 25) SkDebugf("\n");
- SkDebugf("0x%04x, ", dst[i]);
- }
- }
- });
- }
-
-}
-
DEF_TEST(SkVM_badpack, r) {
// Test case distilled from actual failing draw,
// originally with a bad arm64 implementation of pack().