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:
parent
b43cfa4d3f
commit
5a879c47e2
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user