mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-11 07:11:54 +00:00
- 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;
|
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
|
// FxSequence :: Emit
|
||||||
|
@ -7194,6 +7206,24 @@ ExpEmit FxSwitchStatement::Emit(VMFunctionBuilder *build)
|
||||||
return ExpEmit();
|
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);
|
v.Free(build);
|
||||||
if (path2 != nullptr)
|
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
|
// Evaluate second path
|
||||||
build->BackpatchToHere(jumpspot);
|
build->BackpatchToHere(jumpspot);
|
||||||
v = path2->Emit(build);
|
v = path2->Emit(build);
|
||||||
v.Free(build);
|
v.Free(build);
|
||||||
jumpspot = path1jump;
|
jumpspot = path1jump;
|
||||||
}
|
}
|
||||||
build->BackpatchToHere(jumpspot);
|
if (jumpspot != 0xffffffff) build->BackpatchToHere(jumpspot);
|
||||||
return ExpEmit();
|
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
|
// FxLoopStatement :: Resolve
|
||||||
|
|
|
@ -297,6 +297,7 @@ public:
|
||||||
virtual bool RequestAddress(bool *writable);
|
virtual bool RequestAddress(bool *writable);
|
||||||
virtual PPrototype *ReturnProto();
|
virtual PPrototype *ReturnProto();
|
||||||
virtual VMFunction *GetDirectFunction();
|
virtual VMFunction *GetDirectFunction();
|
||||||
|
virtual bool CheckReturn() { return false; }
|
||||||
bool IsNumeric() const { return ValueType != TypeName && ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
|
bool IsNumeric() const { return ValueType != TypeName && ValueType->GetRegCount() == 1 && (ValueType->GetRegType() == REGT_INT || ValueType->GetRegType() == REGT_FLOAT); }
|
||||||
bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; }
|
bool IsFloat() const { return ValueType->GetRegType() == REGT_FLOAT && ValueType->GetRegCount() == 1; }
|
||||||
bool IsInteger() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT); }
|
bool IsInteger() const { return ValueType != TypeName && (ValueType->GetRegType() == REGT_INT); }
|
||||||
|
@ -1390,6 +1391,7 @@ public:
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
|
void Add(FxExpression *expr) { if (expr != NULL) Expressions.Push(expr); expr->NeedResult = false; }
|
||||||
VMFunction *GetDirectFunction();
|
VMFunction *GetDirectFunction();
|
||||||
|
bool CheckReturn();
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1438,6 +1440,7 @@ public:
|
||||||
~FxSwitchStatement();
|
~FxSwitchStatement();
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
bool CheckReturn();
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1476,6 +1479,7 @@ public:
|
||||||
~FxIfStatement();
|
~FxIfStatement();
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
|
bool CheckReturn();
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
@ -1589,6 +1593,7 @@ public:
|
||||||
FxExpression *Resolve(FCompileContext&);
|
FxExpression *Resolve(FCompileContext&);
|
||||||
ExpEmit Emit(VMFunctionBuilder *build);
|
ExpEmit Emit(VMFunctionBuilder *build);
|
||||||
VMFunction *GetDirectFunction();
|
VMFunction *GetDirectFunction();
|
||||||
|
bool CheckReturn() { return true; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
|
|
|
@ -715,6 +715,13 @@ void FFunctionBuildList::Build()
|
||||||
|
|
||||||
FScriptPosition::StrictErrors = !item.FromDecorate;
|
FScriptPosition::StrictErrors = !item.FromDecorate;
|
||||||
item.Code = item.Code->Resolve(ctx);
|
item.Code = item.Code->Resolve(ctx);
|
||||||
|
if (!item.Code->CheckReturn())
|
||||||
|
{
|
||||||
|
auto newcmpd = new FxCompoundStatement(item.Code->ScriptPosition);
|
||||||
|
newcmpd->Add(item.Code);
|
||||||
|
newcmpd->Add(new FxReturnStatement(nullptr, item.Code->ScriptPosition));
|
||||||
|
item.Code = newcmpd->Resolve(ctx);
|
||||||
|
}
|
||||||
item.Proto = ctx.ReturnProto;
|
item.Proto = ctx.ReturnProto;
|
||||||
|
|
||||||
// Make sure resolving it didn't obliterate it.
|
// Make sure resolving it didn't obliterate it.
|
||||||
|
|
|
@ -2464,15 +2464,15 @@ FxExpression *ZCCCompiler::ConvertAST(PClass *cls, ZCC_TreeNode *ast)
|
||||||
// This must be done here so that we can check for a trailing return statement.
|
// This must be done here so that we can check for a trailing return statement.
|
||||||
auto x = new FxCompoundStatement(*ast);
|
auto x = new FxCompoundStatement(*ast);
|
||||||
auto compound = static_cast<ZCC_CompoundStmt *>(ast);
|
auto compound = static_cast<ZCC_CompoundStmt *>(ast);
|
||||||
bool isreturn = false;
|
//bool isreturn = false;
|
||||||
auto node = compound->Content;
|
auto node = compound->Content;
|
||||||
if (node != nullptr) do
|
if (node != nullptr) do
|
||||||
{
|
{
|
||||||
x->Add(ConvertNode(node));
|
x->Add(ConvertNode(node));
|
||||||
isreturn = node->NodeType == AST_ReturnStmt;
|
//isreturn = node->NodeType == AST_ReturnStmt;
|
||||||
node = static_cast<decltype(node)>(node->SiblingNext);
|
node = static_cast<decltype(node)>(node->SiblingNext);
|
||||||
} while (node != compound->Content);
|
} while (node != compound->Content);
|
||||||
if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast));
|
//if (!isreturn) x->Add(new FxReturnStatement(nullptr, *ast));
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue