mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-08-25 21:22:04 +00:00
Migrate some of the validation logic over to use the results of behavior analysis. The most significant changes are: * Unreachable-statements now consider merge-points of control flow. For example, if all branches of a if-statement or switch-statement either return or discard, the next statement will be considered unreachable. * Unreachable statements are no longer an error, but a warning. See https://github.com/gpuweb/gpuweb/issues/2378. * Statements that follow a loops that does not break, or have a conditional will now be considered unreachable. * Unreachable statements produced by the SPIR-V reader are now removed using the new RemoveUnreachableStatements transform. Some other new changes include additional validation for the continuing block for for-loops, to match the rules of a loop continuing block. The new cases this validation is testing for are not expressible in WGSL, but some transforms may produce complex continuing statements that might violate these rules. All the writers are able to decay these complex for-loop continuing statements to regular loops. Bug: tint:1302 Change-Id: I0d8a48c73d5d5c30a1cddf92cc3383a692a58e61 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/71500 Kokoro: Kokoro <noreply+kokoro@google.com> Reviewed-by: David Neto <dneto@google.com>
189 lines
5.8 KiB
C++
189 lines
5.8 KiB
C++
// Copyright 2021 The Tint Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef SRC_SEM_STATEMENT_H_
|
|
#define SRC_SEM_STATEMENT_H_
|
|
|
|
#include "src/sem/behavior.h"
|
|
#include "src/sem/node.h"
|
|
|
|
// Forward declarations
|
|
namespace tint {
|
|
namespace ast {
|
|
class Function;
|
|
class Statement;
|
|
} // namespace ast
|
|
namespace sem {
|
|
class BlockStatement;
|
|
} // namespace sem
|
|
} // namespace tint
|
|
|
|
namespace tint {
|
|
namespace sem {
|
|
|
|
/// Forward declaration
|
|
class CompoundStatement;
|
|
class Function;
|
|
|
|
namespace detail {
|
|
/// FindFirstParentReturn is a traits helper for determining the return type for
|
|
/// the template member function Statement::FindFirstParent().
|
|
/// For zero or multiple template arguments, FindFirstParentReturn::type
|
|
/// resolves to CompoundStatement.
|
|
template <typename... TYPES>
|
|
struct FindFirstParentReturn {
|
|
/// The pointer type returned by Statement::FindFirstParent()
|
|
using type = CompoundStatement;
|
|
};
|
|
|
|
/// A specialization of FindFirstParentReturn for a single template argument.
|
|
/// FindFirstParentReturn::type resolves to the single template argument.
|
|
template <typename T>
|
|
struct FindFirstParentReturn<T> {
|
|
/// The pointer type returned by Statement::FindFirstParent()
|
|
using type = T;
|
|
};
|
|
|
|
template <typename... TYPES>
|
|
using FindFirstParentReturnType =
|
|
typename FindFirstParentReturn<TYPES...>::type;
|
|
} // namespace detail
|
|
|
|
/// Statement holds the semantic information for a statement.
|
|
class Statement : public Castable<Statement, Node> {
|
|
public:
|
|
/// Constructor
|
|
/// @param declaration the AST node for this statement
|
|
/// @param parent the owning statement
|
|
/// @param function the owning function
|
|
Statement(const ast::Statement* declaration,
|
|
const CompoundStatement* parent,
|
|
const sem::Function* function);
|
|
|
|
/// Destructor
|
|
~Statement() override;
|
|
|
|
/// @return the AST node for this statement
|
|
const ast::Statement* Declaration() const { return declaration_; }
|
|
|
|
/// @return the statement that encloses this statement
|
|
const CompoundStatement* Parent() const { return parent_; }
|
|
|
|
/// @returns the closest enclosing parent that satisfies the given predicate,
|
|
/// which may be the statement itself, or nullptr if no match is found.
|
|
/// @param pred a predicate that the resulting block must satisfy
|
|
template <typename Pred>
|
|
const CompoundStatement* FindFirstParent(Pred&& pred) const;
|
|
|
|
/// @returns the closest enclosing parent that is of one of the types in
|
|
/// `TYPES`, which may be the statement itself, or nullptr if no match is
|
|
/// found. If `TYPES` is a single template argument, the return type is a
|
|
/// pointer to that template argument type, otherwise a CompoundStatement
|
|
/// pointer is returned.
|
|
template <typename... TYPES>
|
|
const detail::FindFirstParentReturnType<TYPES...>* FindFirstParent() const;
|
|
|
|
/// @return the closest enclosing block for this statement
|
|
const BlockStatement* Block() const;
|
|
|
|
/// @returns the function that owns this statement
|
|
const sem::Function* Function() const { return function_; }
|
|
|
|
/// @return the behaviors of this statement
|
|
const sem::Behaviors& Behaviors() const { return behaviors_; }
|
|
|
|
/// @return the behaviors of this statement
|
|
sem::Behaviors& Behaviors() { return behaviors_; }
|
|
|
|
/// @returns true if this statement is reachable by control flow according to
|
|
/// the behavior analysis
|
|
bool IsReachable() const { return is_reachable_; }
|
|
|
|
/// @param is_reachable whether this statement is reachable by control flow
|
|
/// according to the behavior analysis
|
|
void SetIsReachable(bool is_reachable) { is_reachable_ = is_reachable; }
|
|
|
|
private:
|
|
const ast::Statement* const declaration_;
|
|
const CompoundStatement* const parent_;
|
|
const sem::Function* const function_;
|
|
sem::Behaviors behaviors_{sem::Behavior::kNext};
|
|
bool is_reachable_ = true;
|
|
};
|
|
|
|
/// CompoundStatement is the base class of statements that can hold other
|
|
/// statements.
|
|
class CompoundStatement : public Castable<Statement, Statement> {
|
|
public:
|
|
/// Constructor
|
|
/// @param declaration the AST node for this statement
|
|
/// @param statement the owning statement
|
|
/// @param function the owning function
|
|
CompoundStatement(const ast::Statement* declaration,
|
|
const CompoundStatement* statement,
|
|
const sem::Function* function);
|
|
|
|
/// Destructor
|
|
~CompoundStatement() override;
|
|
};
|
|
|
|
template <typename Pred>
|
|
const CompoundStatement* Statement::FindFirstParent(Pred&& pred) const {
|
|
if (auto* self = As<CompoundStatement>()) {
|
|
if (pred(self)) {
|
|
return self;
|
|
}
|
|
}
|
|
const auto* curr = parent_;
|
|
while (curr && !pred(curr)) {
|
|
curr = curr->Parent();
|
|
}
|
|
return curr;
|
|
}
|
|
|
|
template <typename... TYPES>
|
|
const detail::FindFirstParentReturnType<TYPES...>* Statement::FindFirstParent()
|
|
const {
|
|
using ReturnType = detail::FindFirstParentReturnType<TYPES...>;
|
|
if (sizeof...(TYPES) == 1) {
|
|
if (auto* p = As<ReturnType>()) {
|
|
return p;
|
|
}
|
|
const auto* curr = parent_;
|
|
while (curr) {
|
|
if (auto* p = curr->As<ReturnType>()) {
|
|
return p;
|
|
}
|
|
curr = curr->Parent();
|
|
}
|
|
} else {
|
|
if (IsAnyOf<TYPES...>()) {
|
|
return As<ReturnType>();
|
|
}
|
|
const auto* curr = parent_;
|
|
while (curr) {
|
|
if (curr->IsAnyOf<TYPES...>()) {
|
|
return curr->As<ReturnType>();
|
|
}
|
|
curr = curr->Parent();
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace sem
|
|
} // namespace tint
|
|
|
|
#endif // SRC_SEM_STATEMENT_H_
|