basic hoisting

We've got this can_hoist analysis... why not use it?
I need to do some pen and paper work before I can do
this for the scalar loop, so that's TODO.

The tight part of a memset-from-uniforms loop becomes

    0x1065c70e0: vmovdqu64 %zmm0, (%rdx)
    0x1065c70e6: addl   $-0x10, %edi
    0x1065c70e9: addq   $0x40, %rdx
    0x1065c70ed: cmpl   $0xf, %edi
    0x1065c70f0: jg     0x1065c70e0

Change-Id: Iad8ee018ae65ee9f370980939a70f042ee3f9138
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/274586
Reviewed-by: Herb Derby <herb@google.com>
Commit-Queue: Mike Klein <mtklein@google.com>
This commit is contained in:
Mike Klein 2020-03-02 14:57:39 -06:00 committed by Skia Commit-Bot
parent b43cfa4d3f
commit 5a879c47e2

View File

@ -1929,6 +1929,7 @@ namespace skvm {
}
llvm::BasicBlock *enter = llvm::BasicBlock::Create(ctx, "enter", fn),
*hoist = llvm::BasicBlock::Create(ctx, "hoist", fn),
*testK = llvm::BasicBlock::Create(ctx, "testK", fn),
*loopK = llvm::BasicBlock::Create(ctx, "loopK", fn),
*test1 = llvm::BasicBlock::Create(ctx, "test1", fn),
@ -2157,9 +2158,33 @@ namespace skvm {
return true;
};
// We can't jump to the first basic block or this would be testK directly.
{
IRBuilder b(enter);
b.CreateBr(hoist);
}
// hoist: emit each hoistable vector instruction; goto testK;
// LLVM can do this sort of thing itself, but we've got the information cheap,
// and pointer aliasing makes it easier to manually hoist than teach LLVM it's safe.
{
IRBuilder b(hoist);
// Hoisted instructions will need args (think, uniforms), so set that up now.
// These phi nodes are degenerate... they'll always be the passed-in args from enter.
// Later on when we start looping the phi nodes will start looking useful.
llvm::Argument* arg = fn->arg_begin();
(void)arg++; // Leave n as nullptr... it'd be a bug to use n in a hoisted instruction.
for (size_t i = 0; i < fStrides.size(); i++) {
args.push_back(b.CreatePHI(arg->getType(), 1));
args.back()->addIncoming(arg++, enter);
}
for (size_t i = 0; i < instructions.size(); i++) {
if (instructions[i].can_hoist && !emit(i, false, &b)) {
return;
}
}
b.CreateBr(testK);
}
@ -2167,15 +2192,16 @@ namespace skvm {
{
IRBuilder b(testK);
// Set up phi nodes for `n` and each pointer argument from enter; later we'll add loopK.
// New phi nodes for `n` and each pointer argument from hoist; later we'll add loopK.
// These also start as the initial function arguments; hoist can't have changed them.
llvm::Argument* arg = fn->arg_begin();
n = b.CreatePHI(arg->getType(), 2);
n->addIncoming(arg++, enter);
n->addIncoming(arg++, hoist);
for (size_t i = 0; i < fStrides.size(); i++) {
args.push_back(b.CreatePHI(arg->getType(), 2));
args.back()->addIncoming(arg++, enter);
args[i] = b.CreatePHI(arg->getType(), 2);
args[i]->addIncoming(arg++, hoist);
}
b.CreateCondBr(b.CreateICmpSGE(n, b.getInt32(K)), loopK, test1);
@ -2185,7 +2211,7 @@ namespace skvm {
{
IRBuilder b(loopK);
for (size_t i = 0; i < instructions.size(); i++) {
if (!emit(i, false, &b)) {
if (!instructions[i].can_hoist && !emit(i, false, &b)) {
return;
}
}
@ -2203,6 +2229,8 @@ namespace skvm {
b.CreateBr(testK);
}
// TODO: hoist1
// test1: if (N >= 1) goto loop1; else goto leave;
{
IRBuilder b(test1);