- flatten FxBinaryLogical chains into a single node for more efficient processing.

This commit is contained in:
Christoph Oelckers 2016-11-02 15:46:15 +01:00
parent eca4fba0f6
commit ff66dc3189
2 changed files with 55 additions and 47 deletions

View file

@ -3583,9 +3583,47 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
return x; return x;
} }
} }
Flatten();
return this; return this;
} }
//==========================================================================
//
// flatten a list of the same operator into a single node.
//
//==========================================================================
void FxBinaryLogical::Flatten()
{
if (left->ExprType == EFX_BinaryLogical && static_cast<FxBinaryLogical *>(left)->Operator == Operator)
{
list = std::move(static_cast<FxBinaryLogical *>(left)->list);
delete left;
}
else
{
list.Push(left);
}
if (right->ExprType == EFX_BinaryLogical && static_cast<FxBinaryLogical *>(right)->Operator == Operator)
{
auto &rlist = static_cast<FxBinaryLogical *>(right)->list;
auto cnt = rlist.Size();
auto v = list.Reserve(cnt);
for (unsigned i = 0; i < cnt; i++)
{
list[v + i] = rlist[i];
rlist[i] = nullptr;
}
delete right;
}
else
{
list.Push(right);
}
left = right = nullptr;
}
//========================================================================== //==========================================================================
// //
// //
@ -3594,56 +3632,24 @@ FxExpression *FxBinaryLogical::Resolve(FCompileContext& ctx)
ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build) ExpEmit FxBinaryLogical::Emit(VMFunctionBuilder *build)
{ {
// This is not the "right" way to do these, but it works for now. TArray<size_t> patchspots;
// (Problem: No information sharing is done between nodes to reduce the
// code size if you have something like a1 && a2 && a3 && ... && an.)
assert(left->ValueType->GetRegType() == REGT_INT && right->ValueType->GetRegType() == REGT_INT);
ExpEmit op1 = left->Emit(build);
assert(!op1.Konst);
int zero = build->GetConstantInt(0); int zero = build->GetConstantInt(0);
op1.Free(build); for (unsigned i = 0; i < list.Size(); i++)
if (Operator == TK_AndAnd)
{ {
build->Emit(OP_EQ_K, 1, op1.RegNum, zero); assert(list[i]->ValueType->GetRegType() == REGT_INT);
// If op1 is 0, skip evaluation of op2. ExpEmit op1 = list[i]->Emit(build);
size_t patchspot = build->Emit(OP_JMP, 0, 0, 0); assert(!op1.Konst);
op1.Free(build);
// Evaluate op2. build->Emit(OP_EQ_K, (Operator == TK_AndAnd) ? 1 : 0, op1.RegNum, zero);
ExpEmit op2 = right->Emit(build); patchspots.Push(build->Emit(OP_JMP, 0, 0, 0));
assert(!op2.Konst);
op2.Free(build);
ExpEmit to(build, REGT_INT);
build->Emit(OP_EQ_K, 1, op2.RegNum, zero);
build->Emit(OP_JMP, 2);
build->Emit(OP_LI, to.RegNum, 1);
build->Emit(OP_JMP, 1);
size_t target = build->Emit(OP_LI, to.RegNum, 0);
build->Backpatch(patchspot, target);
return to;
}
else
{
assert(Operator == TK_OrOr);
build->Emit(OP_EQ_K, 0, op1.RegNum, zero);
// If op1 is not 0, skip evaluation of op2.
size_t patchspot = build->Emit(OP_JMP, 0, 0, 0);
// Evaluate op2.
ExpEmit op2 = right->Emit(build);
assert(!op2.Konst);
op2.Free(build);
ExpEmit to(build, REGT_INT);
build->Emit(OP_EQ_K, 0, op2.RegNum, zero);
build->Emit(OP_JMP, 2);
build->Emit(OP_LI, to.RegNum, 0);
build->Emit(OP_JMP, 1);
size_t target = build->Emit(OP_LI, to.RegNum, 1);
build->Backpatch(patchspot, target);
return to;
} }
ExpEmit to(build, REGT_INT);
build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 1 : 0);
build->Emit(OP_JMP, 1);
auto ctarget = build->Emit(OP_LI, to.RegNum, (Operator == TK_AndAnd) ? 0 : 1);
for (auto addr : patchspots) build->Backpatch(addr, ctarget);
return to;
} }
//========================================================================== //==========================================================================

View file

@ -910,9 +910,11 @@ public:
int Operator; int Operator;
FxExpression *left; FxExpression *left;
FxExpression *right; FxExpression *right;
TDeletingArray<FxExpression *> list;
FxBinaryLogical(int, FxExpression*, FxExpression*); FxBinaryLogical(int, FxExpression*, FxExpression*);
~FxBinaryLogical(); ~FxBinaryLogical();
void Flatten();
FxExpression *Resolve(FCompileContext&); FxExpression *Resolve(FCompileContext&);
ExpEmit Emit(VMFunctionBuilder *build); ExpEmit Emit(VMFunctionBuilder *build);