more unit tests
Backfill tests for some uncovered operations. Mostly functional tests, with some targeted at particular corners of code generation, and a few assembler unit tests. This doesn't get up to 100% line coverage, but I think it covers all the non-failure cases. Change-Id: Ib701df0c505aa41e3b2fe3cd429447acb294b752 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/230837 Reviewed-by: Mike Klein <mtklein@google.com> Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
parent
4d2d6f4137
commit
81d526703c
@ -447,6 +447,245 @@ DEF_TEST(SkVM_LoopCounts, r) {
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_gathers, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg img = b.uniform(),
|
||||
buf32 = b.varying<int>(),
|
||||
buf16 = b.varying<uint16_t>(),
|
||||
buf8 = b.varying<uint8_t>();
|
||||
|
||||
skvm::I32 x = b.load32(buf32);
|
||||
|
||||
b.store32(buf32, b.gather32(img, b.bit_and(x, b.splat( 7))));
|
||||
b.store16(buf16, b.gather16(img, b.bit_and(x, b.splat(15))));
|
||||
b.store8 (buf8 , b.gather8 (img, b.bit_and(x, b.splat(31))));
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
const int img[] = {12,34,56,78, 90,98,76,54};
|
||||
|
||||
constexpr int N = 20;
|
||||
int buf32[N];
|
||||
uint16_t buf16[N];
|
||||
uint8_t buf8 [N];
|
||||
|
||||
for (int i = 0; i < 20; i++) {
|
||||
buf32[i] = i;
|
||||
}
|
||||
|
||||
program.eval(N, img, buf32, buf16, buf8);
|
||||
int i = 0;
|
||||
REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 12 && buf8[i] == 12); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 34 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 90 && buf16[i] == 56 && buf8[i] == 34); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 98 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 76 && buf16[i] == 78 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 54 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
|
||||
REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 90 && buf8[i] == 56); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 98 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 90 && buf16[i] == 76 && buf8[i] == 78); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 98 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 76 && buf16[i] == 54 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 54 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
|
||||
REPORTER_ASSERT(r, buf32[i] == 12 && buf16[i] == 12 && buf8[i] == 90); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 34 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 56 && buf16[i] == 34 && buf8[i] == 0); i++;
|
||||
REPORTER_ASSERT(r, buf32[i] == 78 && buf16[i] == 0 && buf8[i] == 0); i++;
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_bitops, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg ptr = b.varying<int>();
|
||||
|
||||
skvm::I32 x = b.load32(ptr);
|
||||
|
||||
x = b.bit_and (x, b.splat(0xf1)); // 0x40
|
||||
x = b.bit_or (x, b.splat(0x80)); // 0xc0
|
||||
x = b.bit_xor (x, b.splat(0xfe)); // 0x3e
|
||||
x = b.bit_clear(x, b.splat(0x30)); // 0x0e
|
||||
|
||||
x = b.shl(x, 28); // 0xe000'0000
|
||||
x = b.sra(x, 28); // 0xffff'fffe
|
||||
x = b.shr(x, 1); // 0x7fff'ffff
|
||||
|
||||
b.store32(ptr, x);
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
int x = 0x42;
|
||||
program.eval(1, &x);
|
||||
REPORTER_ASSERT(r, x == 0x7fff'ffff);
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_f32, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg arg = b.varying<float>();
|
||||
|
||||
skvm::F32 x = b.bit_cast(b.load32(arg)),
|
||||
y = b.add(x,x), // y = 2x
|
||||
z = b.sub(y,x), // z = 2x-x = x
|
||||
w = b.div(z,x); // w = x/x = 1
|
||||
b.store32(arg, b.bit_cast(w));
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
float buf[] = { 1,2,3,4,5,6,7,8,9 };
|
||||
program.eval(SK_ARRAY_COUNT(buf), buf);
|
||||
for (float v : buf) {
|
||||
REPORTER_ASSERT(r, v == 1.0f);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_cmp_i32, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::I32 x = b.load32(b.varying<int>());
|
||||
|
||||
auto to_bit = [&](int shift, skvm::I32 mask) {
|
||||
return b.shl(b.bit_and(mask, b.splat(0x1)), shift);
|
||||
};
|
||||
|
||||
skvm::I32 m = b.splat(0);
|
||||
m = b.bit_or(m, to_bit(0, b. eq(x, b.splat(0))));
|
||||
m = b.bit_or(m, to_bit(1, b.neq(x, b.splat(1))));
|
||||
m = b.bit_or(m, to_bit(2, b. lt(x, b.splat(2))));
|
||||
m = b.bit_or(m, to_bit(3, b.lte(x, b.splat(3))));
|
||||
m = b.bit_or(m, to_bit(4, b. gt(x, b.splat(4))));
|
||||
m = b.bit_or(m, to_bit(5, b.gte(x, b.splat(5))));
|
||||
|
||||
b.store32(b.varying<int>(), m);
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
int in[] = { 0,1,2,3,4,5,6,7,8,9 };
|
||||
int out[SK_ARRAY_COUNT(in)];
|
||||
|
||||
program.eval(SK_ARRAY_COUNT(in), in, out);
|
||||
|
||||
REPORTER_ASSERT(r, out[0] == 0b001111);
|
||||
REPORTER_ASSERT(r, out[1] == 0b001100);
|
||||
REPORTER_ASSERT(r, out[2] == 0b001010);
|
||||
REPORTER_ASSERT(r, out[3] == 0b001010);
|
||||
REPORTER_ASSERT(r, out[4] == 0b000010);
|
||||
for (int i = 5; i < (int)SK_ARRAY_COUNT(out); i++) {
|
||||
REPORTER_ASSERT(r, out[i] == 0b110010);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_cmp_f32, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::F32 x = b.bit_cast(b.load32(b.varying<float>()));
|
||||
|
||||
auto to_bit = [&](int shift, skvm::I32 mask) {
|
||||
return b.shl(b.bit_and(mask, b.splat(0x1)), shift);
|
||||
};
|
||||
|
||||
skvm::I32 m = b.splat(0);
|
||||
m = b.bit_or(m, to_bit(0, b. eq(x, b.splat(0.0f))));
|
||||
m = b.bit_or(m, to_bit(1, b.neq(x, b.splat(1.0f))));
|
||||
m = b.bit_or(m, to_bit(2, b. lt(x, b.splat(2.0f))));
|
||||
m = b.bit_or(m, to_bit(3, b.lte(x, b.splat(3.0f))));
|
||||
m = b.bit_or(m, to_bit(4, b. gt(x, b.splat(4.0f))));
|
||||
m = b.bit_or(m, to_bit(5, b.gte(x, b.splat(5.0f))));
|
||||
|
||||
b.store32(b.varying<int>(), m);
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
float in[] = { 0,1,2,3,4,5,6,7,8,9 };
|
||||
int out[SK_ARRAY_COUNT(in)];
|
||||
|
||||
program.eval(SK_ARRAY_COUNT(in), in, out);
|
||||
|
||||
REPORTER_ASSERT(r, out[0] == 0b001111);
|
||||
REPORTER_ASSERT(r, out[1] == 0b001100);
|
||||
REPORTER_ASSERT(r, out[2] == 0b001010);
|
||||
REPORTER_ASSERT(r, out[3] == 0b001010);
|
||||
REPORTER_ASSERT(r, out[4] == 0b000010);
|
||||
for (int i = 5; i < (int)SK_ARRAY_COUNT(out); i++) {
|
||||
REPORTER_ASSERT(r, out[i] == 0b110010);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_i16x2, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg buf = b.varying<int>();
|
||||
|
||||
skvm::I32 x = b.load32(buf),
|
||||
y = b.add_16x2(x,x), // y = 2x
|
||||
z = b.mul_16x2(x,y), // z = 2x^2
|
||||
w = b.sub_16x2(z,x), // w = x(2x-1)
|
||||
v = b.shl_16x2(w,7), // These shifts will be a no-op
|
||||
u = b.sra_16x2(v,7); // for all but x=12 and x=13.
|
||||
b.store32(buf, u);
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
uint16_t buf[] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13 };
|
||||
|
||||
program.eval(SK_ARRAY_COUNT(buf)/2, buf);
|
||||
for (int i = 0; i < 12; i++) {
|
||||
REPORTER_ASSERT(r, buf[i] == i*(2*i-1));
|
||||
}
|
||||
REPORTER_ASSERT(r, buf[12] == 0xff14); // 12*23 = 0x114
|
||||
REPORTER_ASSERT(r, buf[13] == 0xff45); // 13*25 = 0x145
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_cmp_i16, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg buf = b.varying<int>();
|
||||
skvm::I32 x = b.load32(buf);
|
||||
|
||||
auto to_bit = [&](int shift, skvm::I32 mask) {
|
||||
return b.shl_16x2(b.bit_and(mask, b.splat(0x0001'0001)), shift);
|
||||
};
|
||||
|
||||
skvm::I32 m = b.splat(0);
|
||||
m = b.bit_or(m, to_bit(0, b. eq_16x2(x, b.splat(0x0000'0000))));
|
||||
m = b.bit_or(m, to_bit(1, b.neq_16x2(x, b.splat(0x0001'0001))));
|
||||
m = b.bit_or(m, to_bit(2, b. lt_16x2(x, b.splat(0x0002'0002))));
|
||||
m = b.bit_or(m, to_bit(3, b.lte_16x2(x, b.splat(0x0003'0003))));
|
||||
m = b.bit_or(m, to_bit(4, b. gt_16x2(x, b.splat(0x0004'0004))));
|
||||
m = b.bit_or(m, to_bit(5, b.gte_16x2(x, b.splat(0x0005'0005))));
|
||||
|
||||
b.store32(buf, m);
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
int16_t buf[] = { 0,1, 2,3, 4,5, 6,7, 8,9 };
|
||||
|
||||
program.eval(SK_ARRAY_COUNT(buf)/2, buf);
|
||||
|
||||
REPORTER_ASSERT(r, buf[0] == 0b001111);
|
||||
REPORTER_ASSERT(r, buf[1] == 0b001100);
|
||||
REPORTER_ASSERT(r, buf[2] == 0b001010);
|
||||
REPORTER_ASSERT(r, buf[3] == 0b001010);
|
||||
REPORTER_ASSERT(r, buf[4] == 0b000010);
|
||||
for (int i = 5; i < (int)SK_ARRAY_COUNT(buf); i++) {
|
||||
REPORTER_ASSERT(r, buf[i] == 0b110010);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
DEF_TEST(SkVM_mad, r) {
|
||||
// This program is designed to exercise the tricky corners of instruction
|
||||
// and register selection for Op::mad_f32.
|
||||
@ -475,6 +714,28 @@ DEF_TEST(SkVM_mad, r) {
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_madder, r) {
|
||||
skvm::Builder b;
|
||||
{
|
||||
skvm::Arg arg = b.varying<float>();
|
||||
|
||||
skvm::F32 x = b.bit_cast(b.load32(arg)),
|
||||
y = b.mad(x,x,x), // x is needed in the future, so r[x] != r[y].
|
||||
z = b.mad(y,x,y), // r[x] can be reused after this instruction, but not r[y].
|
||||
w = b.mad(y,y,z);
|
||||
b.store32(arg, b.bit_cast(w));
|
||||
}
|
||||
|
||||
test_jit_and_interpreter(b.done(), [&](const skvm::Program& program) {
|
||||
float x = 2.0f;
|
||||
// y = 2*2 + 2 = 6
|
||||
// z = 6*2 + 6 = 18
|
||||
// w = 6*6 + 18 = 54
|
||||
program.eval(1, &x);
|
||||
REPORTER_ASSERT(r, x == 54.0f);
|
||||
});
|
||||
}
|
||||
|
||||
DEF_TEST(SkVM_hoist, r) {
|
||||
// This program uses enough constants that it will fail to JIT if we hoist them.
|
||||
// The JIT will try again without hoisting, and that'll just need 2 registers.
|
||||
@ -986,6 +1247,22 @@ DEF_TEST(SkVM_Assembler, r) {
|
||||
0x43,0x80,0x00,0x91, // add x3, x2, #32
|
||||
});
|
||||
|
||||
// Loading from a label on ARM.
|
||||
test_asm(r, [&](A& a) {
|
||||
A::Label fore,aft;
|
||||
a.label(&fore);
|
||||
a.word(0x01234567);
|
||||
a.ldrq(A::v1, &fore);
|
||||
a.ldrq(A::v2, &aft);
|
||||
a.label(&aft);
|
||||
a.word(0x76543210);
|
||||
},{
|
||||
0x67,0x45,0x23,0x01,
|
||||
0xe1,0xff,0xff,0x9c, // ldr q1, #-4
|
||||
0x22,0x00,0x00,0x9c, // ldr q2, #4
|
||||
0x10,0x32,0x54,0x76,
|
||||
});
|
||||
|
||||
test_asm(r, [&](A& a) {
|
||||
a.ldrq(A::v0, A::x8);
|
||||
a.strq(A::v0, A::x8);
|
||||
@ -1019,4 +1296,10 @@ DEF_TEST(SkVM_Assembler, r) {
|
||||
0x00,0x01,0x40,0x3d,
|
||||
0x00,0x01,0x00,0x3d,
|
||||
});
|
||||
|
||||
test_asm(r, [&](A& a) {
|
||||
a.tbl(A::v0, A::v1, A::v2);
|
||||
},{
|
||||
0x20,0x00,0x02,0x4e,
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user