more JIT refactoring

This re-enables AVX2 JIT with simultaneous register assignment and
instruction selection.  You can see it working in a very basic way in
how we choose instructions and registers for Op::mad_f32.

Constants are still broadcast, here inside the loop instead of hoisted.
I think it'll probably end up best to use constants directly from memory
(as in vpshufb's masks), falling back to these in-loop broadcasts when
that can't work.

Change-Id: If17d51b9960f08da3612e51ac04424e996bf83d4
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/228366
Commit-Queue: Mike Klein <mtklein@google.com>
Reviewed-by: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2019-07-18 10:17:28 -05:00 committed by Skia Commit-Bot
parent 869a3e81ea
commit 558b639225
3 changed files with 420 additions and 661 deletions

File diff suppressed because it is too large Load Diff

View File

@ -260,7 +260,7 @@ namespace skvm {
int death; // Index of last live instruction taking this input; live if != 0.
};
Program done();
Program done(const char* debug_name = nullptr);
// Declare a varying argument with given stride.
Arg arg(int stride);
@ -302,7 +302,7 @@ namespace skvm {
I32 shr(I32 x, int bits);
I32 sra(I32 x, int bits);
I32 extract(I32 x, int bits, I32 z); // (x >> bits) & z
I32 extract(I32 x, int bits, I32 y); // (x >> bits) & y
I32 pack (I32 x, I32 y, int bits); // x | (y << bits)
// Shuffle the bytes in x according to each nibble of control, as if
@ -366,11 +366,10 @@ namespace skvm {
union { Reg z; int imm; };
};
Program(std::vector<Instruction>, int regs, int loop, std::vector<int> strides);
Program() : Program({}, 0, 0, {}) {}
Program(const std::vector<Builder::Instruction>& instructions,
const std::vector<int> & strides);
const std::vector<int> & strides,
const char* debug_name);
Program() : Program({}, {}, nullptr) {}
~Program();
Program(Program&&);
@ -394,14 +393,20 @@ namespace skvm {
private:
void eval(int n, void* args[]) const;
void setupInterpreter(const std::vector<Builder::Instruction>&);
void setupJIT (const std::vector<Builder::Instruction>&, const char* debug_name);
bool jit (const std::vector<Builder::Instruction>&, Assembler*) const;
// Dump jit-*.dump files for perf inject.
void dumpJIT(const char* debug_name) const;
std::vector<Instruction> fInstructions;
int fRegs;
int fLoop;
std::vector<int> fStrides;
void* fJITBuf = nullptr; // Raw mmap'd buffer.
size_t fJITSize = 0; // Size of buf in bytes.
void (*fJITEntry)() = nullptr; // Entry point, offset into buf.
void* fJITBuf = nullptr;
size_t fJITSize = 0;
};

View File

@ -284,6 +284,9 @@ DEF_TEST(SkVM, r) {
for (int i = 0; i < 4; i++) {
uint8_t d = got & 0xff,
w = want & 0xff;
if (abs(d-w) >= 2) {
SkDebugf("d %02x, w %02x\n", d,w);
}
REPORTER_ASSERT(r, abs(d-w) < 2);
got >>= 8;
want >>= 8;
@ -292,10 +295,10 @@ DEF_TEST(SkVM, r) {
});
};
test_8888(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::RGBA_8888}.done());
test_8888(SrcoverBuilder_I32_Naive{}.done());
test_8888(SrcoverBuilder_I32{}.done());
test_8888(SrcoverBuilder_I32_SWAR{}.done());
test_8888(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::RGBA_8888}.done("srcover_f32"));
test_8888(SrcoverBuilder_I32_Naive{}.done("srcover_i32_naive"));
test_8888(SrcoverBuilder_I32{}.done("srcover_i32"));
test_8888(SrcoverBuilder_I32_SWAR{}.done("srcover_i32_SWAR"));
test_jit_and_interpreter(SrcoverBuilder_F32{Fmt::RGBA_8888, Fmt::G8}.done(),
[&](const skvm::Program& program) {