staticbool is_safe_to_eliminate(const Type& type, const Expression& arg) { if (type.isScalar()) { // A scalar "compound type" with a single scalar argument is a no-op and can be eliminated. // (Pedantically, this isn't a compound at all, but it's harmless to allow and simplifies // call sites which need to narrow a vector and may sometimes end up with a scalar.)
SkASSERTF(arg.type().matches(type), "Creating type '%s' from '%s'",
type.description().c_str(), arg.type().description().c_str()); returntrue;
} if (type.isVector() && arg.type().matches(type)) { // A vector compound constructor containing a single argument of matching type can trivially // be eliminated. returntrue;
} // This is a meaningful single-argument compound constructor (e.g. vector-from-matrix, // matrix-from-vector). returnfalse;
}
staticconst Expression* make_splat_from_arguments(const Type& type, const ExpressionArray& args) { // Splats cannot represent a matrix. if (type.isMatrix()) { return nullptr;
} const Expression* splatExpression = nullptr; for (int index = 0; index < args.size(); ++index) { // Arguments must only be scalars or a splat constructors (which can only contain scalars). const Expression* expr; if (args[index]->type().isScalar()) {
expr = args[index].get();
} elseif (args[index]->is<ConstructorSplat>()) {
expr = args[index]->as<ConstructorSplat>().argument().get();
} else { return nullptr;
} // On the first iteration, just remember the expression we encountered. if (index == 0) {
splatExpression = expr; continue;
} // On subsequent iterations, ensure that the expression we found matches the first one. // (Note that IsSameExpressionTree will always reject an Expression with side effects.) if (!Analysis::IsSameExpressionTree(*expr, *splatExpression)) { return nullptr;
}
}
// All the arguments must have matching component type.
SkASSERT(std::all_of(args.begin(), args.end(), [&](const std::unique_ptr<Expression>& arg) { const Type& argType = arg->type(); return (argType.isScalar() || argType.isVector() || argType.isMatrix()) &&
(argType.componentType().matches(type.componentType()));
}));
// The slot count of the combined argument list must match the composite type's slot count.
SkASSERT(type.slotCount() ==
std::accumulate(args.begin(), args.end(), /*initial value*/ (size_t)0,
[](size_t n, const std::unique_ptr<Expression>& arg) { return n + arg->type().slotCount();
})); // No-op compound constructors (containing a single argument of the same type) are eliminated. // (Even though this is a "compound constructor," we let scalars pass through here; it's // harmless to allow and simplifies call sites which need to narrow a vector and may sometimes // end up with a scalar.) if (args.size() == 1 && is_safe_to_eliminate(type, *args.front())) {
args.front()->fPosition = pos; return std::move(args.front());
} // Beyond this point, the type must be a vector or matrix.
SkASSERT(type.isVector() || type.isMatrix());
// See how many fields we would have if composite constructors were flattened out. int fields = 0; for (const std::unique_ptr<Expression>& arg : args) {
fields += arg->is<ConstructorCompound>()
? arg->as<ConstructorCompound>().arguments().size()
: 1;
}
// If we added up more fields than we're starting with, we found at least one input that can // be flattened out. if (fields > args.size()) {
ExpressionArray flattened;
flattened.reserve_exact(fields); for (std::unique_ptr<Expression>& arg : args) { // For non-ConstructorCompound fields, move them over as-is. if (!arg->is<ConstructorCompound>()) {
flattened.push_back(std::move(arg)); continue;
} // For ConstructorCompound fields, move over their inner arguments individually.
ConstructorCompound& compositeCtor = arg->as<ConstructorCompound>(); for (std::unique_ptr<Expression>& innerArg : compositeCtor.arguments()) {
flattened.push_back(std::move(innerArg));
}
}
args = std::move(flattened);
}
}
// Replace constant variables with their corresponding values, so `float2(one, two)` can // compile down to `float2(1.0, 2.0)` (the latter is a compile-time constant). for (std::unique_ptr<Expression>& arg : args) {
arg = ConstantFolder::MakeConstantValueForVariable(pos, std::move(arg));
}
if (context.fConfig->fSettings.fOptimize) { // Reduce compound constructors to splats where possible. if (const Expression* splat = make_splat_from_arguments(type, args)) { return ConstructorSplat::Make(context, pos, type, splat->clone());
}
}
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.