Early out Is checks.

This CL adds a check to the `Is` castable methods to determine if the
target type is `final`. If the type being compared too is `final` we
bail out early in the walk up the hierarchy as it won't be a parent
class.

Change-Id: Ieba4dd686e47207a3db0cf3a8ea46fbc1a8d1c91
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96600
Reviewed-by: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Commit-Queue: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
dan sinclair 2022-07-20 15:53:14 +00:00 committed by Dawn LUCI CQ
parent 633cdf41cc
commit 46c32d882d
28 changed files with 72 additions and 62 deletions

View File

@ -117,6 +117,7 @@ def _NonInclusiveFileFilter(file):
"src/dawn/node/tools/src/cmd/run-cts/main.go", # Terminal type name "src/dawn/node/tools/src/cmd/run-cts/main.go", # Terminal type name
"src/dawn/samples/ComputeBoids.cpp", # External URL "src/dawn/samples/ComputeBoids.cpp", # External URL
"src/dawn/tests/end2end/DepthBiasTests.cpp", # External URL "src/dawn/tests/end2end/DepthBiasTests.cpp", # External URL
"src/tint/transform/canonicalize_entry_point_io.cc", # External URL
"test/tint/samples/compute_boids.wgsl", # External URL "test/tint/samples/compute_boids.wgsl", # External URL
"third_party/khronos/KHR/khrplatform.h", # Third party file "third_party/khronos/KHR/khrplatform.h", # Third party file
"tools/roll-all", # Branch name "tools/roll-all", # Branch name

View File

@ -22,7 +22,7 @@
namespace tint::ast { namespace tint::ast {
/// A float 16 type /// A float 16 type
class F16 : public Castable<F16, Type> { class F16 final : public Castable<F16, Type> {
public: public:
/// Constructor /// Constructor
/// @param pid the identifier of the program that owns this node /// @param pid the identifier of the program that owns this node

View File

@ -20,7 +20,7 @@
namespace tint::ast { namespace tint::ast {
/// An integer literal. The literal may have an 'i', 'u' or no suffix. /// An integer literal. The literal may have an 'i', 'u' or no suffix.
class IntLiteralExpression : public Castable<IntLiteralExpression, LiteralExpression> { class IntLiteralExpression final : public Castable<IntLiteralExpression, LiteralExpression> {
public: public:
/// Literal suffix /// Literal suffix
enum class Suffix { enum class Suffix {

View File

@ -101,6 +101,36 @@ struct TypeInfo {
/// The type hash code bitwise-or'd with all ancestor's hashcodes. /// The type hash code bitwise-or'd with all ancestor's hashcodes.
const HashCode full_hashcode; const HashCode full_hashcode;
/// @returns true if `type` derives from the class `TO`
/// @param object the object type to test from, which must be, or derive from
/// type `FROM`.
/// @see CastFlags
template <typename TO, typename FROM, int FLAGS = 0>
static inline bool Is(const tint::TypeInfo* object) {
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
constexpr const bool nocast = std::is_same<FROM, TO>::value;
constexpr const bool assert_is_castable = (FLAGS & kDontErrorOnImpossibleCast) == 0;
static_assert(upcast || downcast || nocast || !assert_is_castable, "impossible cast");
return upcast || nocast || object->Is<TO>();
}
/// @returns true if this type derives from the class `T`
template <typename T>
inline bool Is() const {
auto* type = &Of<std::remove_cv_t<T>>();
if constexpr (std::is_final_v<T>) {
// T is final, so nothing can derive from T.
// We do not need to check ancestors, only whether this type is equal to the type T.
return type == this;
} else {
return Is(type);
}
}
/// @param type the test type info /// @param type the test type info
/// @returns true if the class with this TypeInfo is of, or derives from the /// @returns true if the class with this TypeInfo is of, or derives from the
/// class with the given TypeInfo. /// class with the given TypeInfo.
@ -112,8 +142,8 @@ struct TypeInfo {
return false; return false;
} }
// Walk the base types, starting with this TypeInfo, to see if any of the // Walk the base types, starting with this TypeInfo, to see if any of the pointers match
// pointers match `type`. // `type`.
for (auto* ti = this; ti != nullptr; ti = ti->base) { for (auto* ti = this; ti != nullptr; ti = ti->base) {
if (ti == type) { if (ti == type) {
return true; return true;
@ -122,26 +152,6 @@ struct TypeInfo {
return false; return false;
} }
/// @returns true if `type` derives from the class `TO`
/// @param type the object type to test from, which must be, or derive from
/// type `FROM`.
/// @see CastFlags
template <typename TO, typename FROM, int FLAGS = 0>
static inline bool Is(const tint::TypeInfo* type) {
constexpr const bool downcast = std::is_base_of<FROM, TO>::value;
constexpr const bool upcast = std::is_base_of<TO, FROM>::value;
constexpr const bool nocast = std::is_same<FROM, TO>::value;
constexpr const bool assert_is_castable = (FLAGS & kDontErrorOnImpossibleCast) == 0;
static_assert(upcast || downcast || nocast || !assert_is_castable, "impossible cast");
if (upcast || nocast) {
return true;
}
return type->Is(&Of<std::remove_cv_t<TO>>());
}
/// @returns the static TypeInfo for the type T /// @returns the static TypeInfo for the type T
template <typename T> template <typename T>
static const TypeInfo& Of() { static const TypeInfo& Of() {
@ -211,14 +221,12 @@ struct TypeInfo {
if constexpr (kCount == 0) { if constexpr (kCount == 0) {
return false; return false;
} else if constexpr (kCount == 1) { } else if constexpr (kCount == 1) {
return Is(&Of<std::tuple_element_t<0, TUPLE>>()); return Is<std::tuple_element_t<0, TUPLE>>();
} else if constexpr (kCount == 2) { } else if constexpr (kCount == 2) {
return Is(&Of<std::tuple_element_t<0, TUPLE>>()) || return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>();
Is(&Of<std::tuple_element_t<1, TUPLE>>());
} else if constexpr (kCount == 3) { } else if constexpr (kCount == 3) {
return Is(&Of<std::tuple_element_t<0, TUPLE>>()) || return Is<std::tuple_element_t<0, TUPLE>>() || Is<std::tuple_element_t<1, TUPLE>>() ||
Is(&Of<std::tuple_element_t<1, TUPLE>>()) || Is<std::tuple_element_t<2, TUPLE>>();
Is(&Of<std::tuple_element_t<2, TUPLE>>());
} else { } else {
// Optimization: Compare the object's hashcode to the bitwise-or of all // Optimization: Compare the object's hashcode to the bitwise-or of all
// the tested type's hashcodes. If there's no intersection of bits in // the tested type's hashcodes. If there's no intersection of bits in
@ -587,7 +595,7 @@ inline bool NonDefaultCases(T* object,
// Attempt to dynamically cast the object to the handler type. If that // Attempt to dynamically cast the object to the handler type. If that
// succeeds, call the case handler with the cast object. // succeeds, call the case handler with the cast object.
using CaseType = SwitchCaseType<CaseFunc>; using CaseType = SwitchCaseType<CaseFunc>;
if (type->Is(&TypeInfo::Of<CaseType>())) { if (type->Is<CaseType>()) {
auto* ptr = static_cast<CaseType*>(object); auto* ptr = static_cast<CaseType*>(object);
if constexpr (kHasReturnType) { if constexpr (kHasReturnType) {
new (result) RETURN_TYPE(static_cast<RETURN_TYPE>(std::get<0>(cases)(ptr))); new (result) RETURN_TYPE(static_cast<RETURN_TYPE>(std::get<0>(cases)(ptr)));

View File

@ -22,7 +22,7 @@
namespace tint::sem { namespace tint::sem {
/// A float 16 type /// A float 16 type
class F16 : public Castable<F16, Type> { class F16 final : public Castable<F16, Type> {
public: public:
/// Constructor /// Constructor
F16(); F16();

View File

@ -170,7 +170,7 @@ class Struct final : public Castable<Struct, Type> {
}; };
/// StructMember holds the semantic information for structure members. /// StructMember holds the semantic information for structure members.
class StructMember : public Castable<StructMember, Node> { class StructMember final : public Castable<StructMember, Node> {
public: public:
/// Constructor /// Constructor
/// @param declaration the AST declaration node /// @param declaration the AST declaration node

View File

@ -73,7 +73,7 @@ struct OffsetExpr : Offset {
/// OffsetLiteral is an implementation of Offset that constructs a u32 literal /// OffsetLiteral is an implementation of Offset that constructs a u32 literal
/// value. /// value.
struct OffsetLiteral : Castable<OffsetLiteral, Offset> { struct OffsetLiteral final : Castable<OffsetLiteral, Offset> {
uint32_t const literal = 0; uint32_t const literal = 0;
explicit OffsetLiteral(uint32_t lit) : literal(lit) {} explicit OffsetLiteral(uint32_t lit) : literal(lit) {}

View File

@ -38,7 +38,7 @@ namespace tint::transform {
/// ///
/// This transform also handles increment and decrement statements in the same /// This transform also handles increment and decrement statements in the same
/// manner, by replacing `i++` with `i = i + 1`. /// manner, by replacing `i++` with `i = i + 1`.
class ExpandCompoundAssignment : public Castable<ExpandCompoundAssignment, Transform> { class ExpandCompoundAssignment final : public Castable<ExpandCompoundAssignment, Transform> {
public: public:
/// Constructor /// Constructor
ExpandCompoundAssignment(); ExpandCompoundAssignment();

View File

@ -27,7 +27,8 @@ namespace tint::transform {
/// ///
/// @note Depends on the following transforms to have been run first: /// @note Depends on the following transforms to have been run first:
/// * SimplifyPointers /// * SimplifyPointers
class LocalizeStructArrayAssignment : public Castable<LocalizeStructArrayAssignment, Transform> { class LocalizeStructArrayAssignment final
: public Castable<LocalizeStructArrayAssignment, Transform> {
public: public:
/// Constructor /// Constructor
LocalizeStructArrayAssignment(); LocalizeStructArrayAssignment();

View File

@ -21,7 +21,7 @@ namespace tint::transform {
/// LoopToForLoop is a Transform that attempts to convert WGSL `loop {}` /// LoopToForLoop is a Transform that attempts to convert WGSL `loop {}`
/// statements into a for-loop statement. /// statements into a for-loop statement.
class LoopToForLoop : public Castable<LoopToForLoop, Transform> { class LoopToForLoop final : public Castable<LoopToForLoop, Transform> {
public: public:
/// Constructor /// Constructor
LoopToForLoop(); LoopToForLoop();

View File

@ -27,7 +27,7 @@ namespace tint::transform {
/// The inner transforms will execute in the appended order. /// The inner transforms will execute in the appended order.
/// If any inner transform fails the manager will return immediately and /// If any inner transform fails the manager will return immediately and
/// the error can be retrieved with the Output's diagnostics. /// the error can be retrieved with the Output's diagnostics.
class Manager : public Castable<Manager, Transform> { class Manager final : public Castable<Manager, Transform> {
public: public:
/// Constructor /// Constructor
Manager(); Manager();

View File

@ -61,7 +61,7 @@ namespace tint::transform {
/// foo(&p, sptr); /// foo(&p, sptr);
/// } /// }
/// ``` /// ```
class ModuleScopeVarToEntryPointParam class ModuleScopeVarToEntryPointParam final
: public Castable<ModuleScopeVarToEntryPointParam, Transform> { : public Castable<ModuleScopeVarToEntryPointParam, Transform> {
public: public:
/// Constructor /// Constructor

View File

@ -50,7 +50,7 @@ struct BindingPoints {
/// decoding, gamut conversion, and gamma encoding steps. Specifically /// decoding, gamut conversion, and gamma encoding steps. Specifically
// for BT.709 to SRGB conversion, it takes the fast path only doing the yuv->rgb // for BT.709 to SRGB conversion, it takes the fast path only doing the yuv->rgb
// step and skipping all other steps. // step and skipping all other steps.
class MultiplanarExternalTexture : public Castable<MultiplanarExternalTexture, Transform> { class MultiplanarExternalTexture final : public Castable<MultiplanarExternalTexture, Transform> {
public: public:
/// BindingsMap is a map where the key is the binding location of a /// BindingsMap is a map where the key is the binding location of a
/// texture_external and the value is a struct containing the desired /// texture_external and the value is a struct containing the desired
@ -60,7 +60,7 @@ class MultiplanarExternalTexture : public Castable<MultiplanarExternalTexture, T
/// NewBindingPoints is consumed by the MultiplanarExternalTexture transform. /// NewBindingPoints is consumed by the MultiplanarExternalTexture transform.
/// Data holds information about location of each texture_external binding and /// Data holds information about location of each texture_external binding and
/// which binding slots it should expand into. /// which binding slots it should expand into.
struct NewBindingPoints : public Castable<Data, transform::Data> { struct NewBindingPoints final : public Castable<Data, transform::Data> {
/// Constructor /// Constructor
/// @param bm a map to the new binding slots to use. /// @param bm a map to the new binding slots to use.
explicit NewBindingPoints(BindingsMap bm); explicit NewBindingPoints(BindingsMap bm);

View File

@ -44,7 +44,7 @@ namespace tint::transform {
/// ///
/// @note Depends on the following transforms to have been run first: /// @note Depends on the following transforms to have been run first:
/// * CanonicalizeEntryPointIO /// * CanonicalizeEntryPointIO
class NumWorkgroupsFromUniform : public Castable<NumWorkgroupsFromUniform, Transform> { class NumWorkgroupsFromUniform final : public Castable<NumWorkgroupsFromUniform, Transform> {
public: public:
/// Constructor /// Constructor
NumWorkgroupsFromUniform(); NumWorkgroupsFromUniform();
@ -52,7 +52,7 @@ class NumWorkgroupsFromUniform : public Castable<NumWorkgroupsFromUniform, Trans
~NumWorkgroupsFromUniform() override; ~NumWorkgroupsFromUniform() override;
/// Configuration options for the NumWorkgroupsFromUniform transform. /// Configuration options for the NumWorkgroupsFromUniform transform.
struct Config : public Castable<Data, transform::Data> { struct Config final : public Castable<Data, transform::Data> {
/// Constructor /// Constructor
/// @param ubo_bp the binding point to use for the generated uniform buffer. If ubo_bp /// @param ubo_bp the binding point to use for the generated uniform buffer. If ubo_bp
/// contains no value, a free binding point will be used to ensure the generated program is /// contains no value, a free binding point will be used to ensure the generated program is

View File

@ -25,7 +25,7 @@ namespace tint::transform {
/// array or structure. For example, the following is not immediately expressable for HLSL: /// array or structure. For example, the following is not immediately expressable for HLSL:
/// `array<i32, 2>(1, 2)[0]` /// `array<i32, 2>(1, 2)[0]`
/// @see crbug.com/tint/406 /// @see crbug.com/tint/406
class PromoteInitializersToLet : public Castable<PromoteInitializersToLet, Transform> { class PromoteInitializersToLet final : public Castable<PromoteInitializersToLet, Transform> {
public: public:
/// Constructor /// Constructor
PromoteInitializersToLet(); PromoteInitializersToLet();

View File

@ -23,7 +23,7 @@ namespace tint::transform {
/// declarations before the statement of usage with the goal of ensuring /// declarations before the statement of usage with the goal of ensuring
/// left-to-right order of evaluation, while respecting short-circuit /// left-to-right order of evaluation, while respecting short-circuit
/// evaluation. /// evaluation.
class PromoteSideEffectsToDecl : public Castable<PromoteSideEffectsToDecl, Transform> { class PromoteSideEffectsToDecl final : public Castable<PromoteSideEffectsToDecl, Transform> {
public: public:
/// Constructor /// Constructor
PromoteSideEffectsToDecl(); PromoteSideEffectsToDecl();

View File

@ -23,7 +23,7 @@ namespace tint::transform {
/// bool variable, and checking if the variable is set after the switch to /// bool variable, and checking if the variable is set after the switch to
/// continue. It is necessary to work around FXC "error X3708: continue cannot /// continue. It is necessary to work around FXC "error X3708: continue cannot
/// be used in a switch". See crbug.com/tint/1080. /// be used in a switch". See crbug.com/tint/1080.
class RemoveContinueInSwitch : public Castable<RemoveContinueInSwitch, Transform> { class RemoveContinueInSwitch final : public Castable<RemoveContinueInSwitch, Transform> {
public: public:
/// Constructor /// Constructor
RemoveContinueInSwitch(); RemoveContinueInSwitch();

View File

@ -25,7 +25,7 @@ namespace tint::transform {
/// RemovePhonies is a Transform that removes all phony-assignment statements, /// RemovePhonies is a Transform that removes all phony-assignment statements,
/// while preserving function call expressions in the RHS of the assignment that /// while preserving function call expressions in the RHS of the assignment that
/// may have side-effects. /// may have side-effects.
class RemovePhonies : public Castable<RemovePhonies, Transform> { class RemovePhonies final : public Castable<RemovePhonies, Transform> {
public: public:
/// Constructor /// Constructor
RemovePhonies(); RemovePhonies();

View File

@ -24,7 +24,7 @@ namespace tint::transform {
/// RemoveUnreachableStatements is a Transform that removes all statements /// RemoveUnreachableStatements is a Transform that removes all statements
/// marked as unreachable. /// marked as unreachable.
class RemoveUnreachableStatements : public Castable<RemoveUnreachableStatements, Transform> { class RemoveUnreachableStatements final : public Castable<RemoveUnreachableStatements, Transform> {
public: public:
/// Constructor /// Constructor
RemoveUnreachableStatements(); RemoveUnreachableStatements();

View File

@ -23,11 +23,11 @@
namespace tint::transform { namespace tint::transform {
/// Renamer is a Transform that renames all the symbols in a program. /// Renamer is a Transform that renames all the symbols in a program.
class Renamer : public Castable<Renamer, Transform> { class Renamer final : public Castable<Renamer, Transform> {
public: public:
/// Data is outputted by the Renamer transform. /// Data is outputted by the Renamer transform.
/// Data holds information about shader usage and constant buffer offsets. /// Data holds information about shader usage and constant buffer offsets.
struct Data : public Castable<Data, transform::Data> { struct Data final : public Castable<Data, transform::Data> {
/// Remappings is a map of old symbol name to new symbol name /// Remappings is a map of old symbol name to new symbol name
using Remappings = std::unordered_map<std::string, std::string>; using Remappings = std::unordered_map<std::string, std::string>;
@ -59,7 +59,7 @@ class Renamer : public Castable<Renamer, Transform> {
/// Optional configuration options for the transform. /// Optional configuration options for the transform.
/// If omitted, then the renamer will use Target::kAll. /// If omitted, then the renamer will use Target::kAll.
struct Config : public Castable<Config, transform::Data> { struct Config final : public Castable<Config, transform::Data> {
/// Constructor /// Constructor
/// @param tgt the targets to rename /// @param tgt the targets to rename
/// @param keep_unicode if false, symbols with non-ascii code-points are /// @param keep_unicode if false, symbols with non-ascii code-points are

View File

@ -31,7 +31,7 @@ namespace tint::transform {
/// the bounds of the array. Any access before the start of the array will clamp /// the bounds of the array. Any access before the start of the array will clamp
/// to zero and any access past the end of the array will clamp to /// to zero and any access past the end of the array will clamp to
/// (array length - 1). /// (array length - 1).
class Robustness : public Castable<Robustness, Transform> { class Robustness final : public Castable<Robustness, Transform> {
public: public:
/// Storage class to be skipped in the transform /// Storage class to be skipped in the transform
enum class StorageClass { enum class StorageClass {
@ -40,7 +40,7 @@ class Robustness : public Castable<Robustness, Transform> {
}; };
/// Configuration options for the transform /// Configuration options for the transform
struct Config : public Castable<Config, Data> { struct Config final : public Castable<Config, Data> {
/// Constructor /// Constructor
Config(); Config();

View File

@ -31,7 +31,7 @@ namespace tint::transform {
/// ///
/// @note Depends on the following transforms to have been run first: /// @note Depends on the following transforms to have been run first:
/// * Unshadow /// * Unshadow
class SimplifyPointers : public Castable<SimplifyPointers, Transform> { class SimplifyPointers final : public Castable<SimplifyPointers, Transform> {
public: public:
/// Constructor /// Constructor
SimplifyPointers(); SimplifyPointers();

View File

@ -25,10 +25,10 @@ namespace tint::transform {
/// ///
/// All module-scope variables, types, and functions that are not used by the /// All module-scope variables, types, and functions that are not used by the
/// target entry point will also be removed. /// target entry point will also be removed.
class SingleEntryPoint : public Castable<SingleEntryPoint, Transform> { class SingleEntryPoint final : public Castable<SingleEntryPoint, Transform> {
public: public:
/// Configuration options for the transform /// Configuration options for the transform
struct Config : public Castable<Config, Data> { struct Config final : public Castable<Config, Data> {
/// Constructor /// Constructor
/// @param entry_point the name of the entry point to keep /// @param entry_point the name of the entry point to keep
explicit Config(std::string entry_point = ""); explicit Config(std::string entry_point = "");

View File

@ -21,7 +21,7 @@ namespace tint::transform {
/// Unshadow is a Transform that renames any variables that shadow another /// Unshadow is a Transform that renames any variables that shadow another
/// variable. /// variable.
class Unshadow : public Castable<Unshadow, Transform> { class Unshadow final : public Castable<Unshadow, Transform> {
public: public:
/// Constructor /// Constructor
Unshadow(); Unshadow();

View File

@ -36,7 +36,7 @@ namespace tint::transform {
/// ///
/// @note Depends on the following transforms to have been run first: /// @note Depends on the following transforms to have been run first:
/// * PromoteSideEffectsToDecl /// * PromoteSideEffectsToDecl
class UnwindDiscardFunctions : public Castable<UnwindDiscardFunctions, Transform> { class UnwindDiscardFunctions final : public Castable<UnwindDiscardFunctions, Transform> {
public: public:
/// Constructor /// Constructor
UnwindDiscardFunctions(); UnwindDiscardFunctions();

View File

@ -20,7 +20,7 @@
namespace tint::transform { namespace tint::transform {
/// A transform that converts scalar matrix constructors to the vector form. /// A transform that converts scalar matrix constructors to the vector form.
class VectorizeScalarMatrixConstructors class VectorizeScalarMatrixConstructors final
: public Castable<VectorizeScalarMatrixConstructors, Transform> { : public Castable<VectorizeScalarMatrixConstructors, Transform> {
public: public:
/// Constructor /// Constructor

View File

@ -128,10 +128,10 @@ using VertexStateDescriptor = std::vector<VertexBufferLayoutDescriptor>;
/// code, but these are types that the data may arrive as. We need to convert /// code, but these are types that the data may arrive as. We need to convert
/// these smaller types into the base types such as `f32` and `u32` for the /// these smaller types into the base types such as `f32` and `u32` for the
/// shader to use. /// shader to use.
class VertexPulling : public Castable<VertexPulling, Transform> { class VertexPulling final : public Castable<VertexPulling, Transform> {
public: public:
/// Configuration options for the transform /// Configuration options for the transform
struct Config : public Castable<Config, Data> { struct Config final : public Castable<Config, Data> {
/// Constructor /// Constructor
Config(); Config();

View File

@ -22,7 +22,7 @@ namespace tint::transform {
/// ZeroInitWorkgroupMemory is a transform that injects code at the top of entry /// ZeroInitWorkgroupMemory is a transform that injects code at the top of entry
/// points to zero-initialize workgroup memory used by that entry point (and all /// points to zero-initialize workgroup memory used by that entry point (and all
/// transitive functions called by that entry point) /// transitive functions called by that entry point)
class ZeroInitWorkgroupMemory : public Castable<ZeroInitWorkgroupMemory, Transform> { class ZeroInitWorkgroupMemory final : public Castable<ZeroInitWorkgroupMemory, Transform> {
public: public:
/// Constructor /// Constructor
ZeroInitWorkgroupMemory(); ZeroInitWorkgroupMemory();