bool visitStatement(const Statement& stmt) override { if (stmt.is<VarDeclaration>()) { // Hoist the variable's symbol outside of the initializer block's symbol table, and // into the outer symbol table. If the initializer's symbol table originally had // ownership, transfer it. (If the variable was owned elsewhere, it can keep its // current owner.)
Variable* var = stmt.as<VarDeclaration>().var();
fInnerSymbols->moveSymbolTo(fHoistedSymbols, var, fContext); returnfalse;
} return ProgramVisitor::visitStatement(stmt);
}
if (!isSimpleInitializer && !isVardeclBlockInitializer) {
context.fErrors->error(initializer->fPosition, "invalid for loop initializer"); return nullptr;
}
if (test) {
test = context.fTypes.fBool->coerceExpression(std::move(test), context); if (!test) { return nullptr;
}
}
// The type of the next-expression doesn't matter, but it needs to be a complete expression. // Report an error on intermediate expressions like FunctionReference or TypeReference. if (next && next->isIncomplete(context)) { return nullptr;
}
std::unique_ptr<LoopUnrollInfo> unrollInfo; if (context.fConfig->strictES2Mode()) { // In strict-ES2, loops must be unrollable or it's an error.
unrollInfo = Analysis::GetLoopUnrollInfo(context, pos, positions, initializer.get(), &test,
next.get(), statement.get(), context.fErrors); if (!unrollInfo) { return nullptr;
}
} else { // In ES3, loops don't have to be unrollable, but we can use the unroll information for // optimization purposes.
unrollInfo = Analysis::GetLoopUnrollInfo(context, pos, positions, initializer.get(), &test,
next.get(), statement.get(), /*errors=*/nullptr);
}
if (Analysis::DetectVarDeclarationWithoutScope(*statement, context.fErrors)) { return nullptr;
}
if (isVardeclBlockInitializer) { // If the initializer statement of a for loop contains multiple variables, this causes // difficulties for several of our backends; e.g. Metal doesn't have a way to express arrays // of different size in the same decl-stmt, because the array-size is part of the type. It's // conceptually equivalent to synthesize a scope, declare the variables, and then emit a for // statement with an empty init-stmt. (Note that we can't just do this transformation // unilaterally for all for-statements, because the resulting for loop isn't ES2-compliant.)
std::unique_ptr<SymbolTable> hoistedSymbols = symbolTable->insertNewParent();
hoist_vardecl_symbols_into_outer_scope(context, initializer->as<Block>(),
symbolTable.get(), hoistedSymbols.get());
StatementArray scope;
scope.push_back(std::move(initializer));
scope.push_back(ForStatement::Make(context,
pos,
positions, /*initializer=*/nullptr,
std::move(test),
std::move(next),
std::move(statement),
std::move(unrollInfo),
std::move(symbolTable))); return Block::Make(pos,
std::move(scope),
Block::Kind::kBracedScope,
std::move(hoistedSymbols));
}
// Unrollable loops are easy to optimize because we know initializer, test and next don't have // interesting side effects. if (unrollInfo) { // A zero-iteration unrollable loop can be replaced with Nop. // An unrollable loop with an empty body can be replaced with Nop. if (unrollInfo->fCount <= 0 || statement->isEmpty()) { return Nop::Make();
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.