- fixed: Tacking on a return statement should only be done if the function has branches that actually reach the end. Otherwise it may interfere with return type deduction.
- used the return check to optimize out unneeded jumps at the end of an if statement's first block.
This commit is contained in:
parent
98fa3d2d93
commit
1b77a8f491
4 changed files with 65 additions and 5 deletions
|
|
@ -6879,6 +6879,18 @@ FxExpression *FxSequence::Resolve(FCompileContext &ctx)
|
|||
return this;
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxSequence :: CheckReturn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FxSequence::CheckReturn()
|
||||
{
|
||||
// a sequence always returns when its last element returns.
|
||||
return Expressions.Size() > 0 && Expressions.Last()->CheckReturn();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxSequence :: Emit
|
||||
|
|
@ -7194,6 +7206,24 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
|
|||
return ExpEmit();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxSequence :: CheckReturn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FxSwitchStatement::CheckReturn()
|
||||
{
|
||||
//A switch statement returns when it contains no breaks and ends with a return
|
||||
for (auto line : *Content)
|
||||
{
|
||||
if (line->ExprType == EFX_JumpStatement)
|
||||
{
|
||||
return false; // Break means that the end of the statement will be reached, Continue cannot happen in the last statement of the last block.
|
||||
}
|
||||
}
|
||||
return Content->Size() > 0 && Content->Last()->CheckReturn();
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
@ -7355,17 +7385,35 @@ ExpEmit FxIfStatement::Emit(VMFunctionBuilder *build)
|
|||
v.Free(build);
|
||||
if (path2 != nullptr)
|
||||
{
|
||||
size_t path1jump = build->Emit(OP_JMP, 0);
|
||||
size_t path1jump;
|
||||
|
||||
// if the branch ends with a return we do not need a terminating jmp.
|
||||
if (!path1->CheckReturn()) path1jump = build->Emit(OP_JMP, 0);
|
||||
else path1jump = 0xffffffff;
|
||||
// Evaluate second path
|
||||
build->BackpatchToHere(jumpspot);
|
||||
v = path2->Emit(build);
|
||||
v.Free(build);
|
||||
jumpspot = path1jump;
|
||||
}
|
||||
build->BackpatchToHere(jumpspot);
|
||||
if (jumpspot != 0xffffffff) build->BackpatchToHere(jumpspot);
|
||||
return ExpEmit();
|
||||
}
|
||||
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxIfStatement :: CheckReturn
|
||||
//
|
||||
//==========================================================================
|
||||
|
||||
bool FxIfStatement::CheckReturn()
|
||||
{
|
||||
//An if statement returns if both branches return, if present.
|
||||
return (WhenTrue == nullptr || WhenTrue->CheckReturn()) &&
|
||||
(WhenFalse == nullptr || WhenFalse->CheckReturn());
|
||||
}
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
// FxLoopStatement :: Resolve
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue