tint/utils: Add TINT_LIKELY / TINT_UNLIKELY macros

Emits branch prediction hints.
Give unlikely hints about where we call TINT_ICE.

Change-Id: Ied5bc3d7c8b3a838e96e5a0a64156048f90411c6
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/116875
Commit-Queue: Ben Clayton <bclayton@google.com>
Auto-Submit: Ben Clayton <bclayton@google.com>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Dan Sinclair <dsinclair@chromium.org>
This commit is contained in:
Ben Clayton 2023-01-12 22:52:57 +00:00 committed by Dawn LUCI CQ
parent 2915fadce4
commit 884f95258d
36 changed files with 321 additions and 282 deletions

View File

@ -134,7 +134,7 @@ void Module::Copy(CloneContext* ctx, const Module* src) {
enables_.Clear(); enables_.Clear();
for (auto* decl : global_declarations_) { for (auto* decl : global_declarations_) {
if (!decl) { if (TINT_UNLIKELY(!decl)) {
TINT_ICE(AST, ctx->dst->Diagnostics()) << "src global declaration was nullptr"; TINT_ICE(AST, ctx->dst->Diagnostics()) << "src global declaration was nullptr";
continue; continue;
} }

View File

@ -25,6 +25,7 @@
#include "src/tint/ast/member_accessor_expression.h" #include "src/tint/ast/member_accessor_expression.h"
#include "src/tint/ast/phony_expression.h" #include "src/tint/ast/phony_expression.h"
#include "src/tint/ast/unary_op_expression.h" #include "src/tint/ast/unary_op_expression.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/reverse.h" #include "src/tint/utils/reverse.h"
#include "src/tint/utils/vector.h" #include "src/tint/utils/vector.h"
@ -147,7 +148,8 @@ bool TraverseExpressions(const ast::Expression* root, diag::List& diags, CALLBAC
return true; return true;
}, },
[&](Default) { [&](Default) {
if (expr->IsAnyOf<LiteralExpression, IdentifierExpression, PhonyExpression>()) { if (TINT_LIKELY((expr->IsAnyOf<LiteralExpression, IdentifierExpression,
PhonyExpression>()))) {
return true; // Leaf expression return true; // Leaf expression
} }
TINT_ICE(AST, diags) << "unhandled expression type: " << expr->TypeInfo().name; TINT_ICE(AST, diags) << "unhandled expression type: " << expr->TypeInfo().name;

View File

@ -26,6 +26,7 @@
#include "src/tint/program_id.h" #include "src/tint/program_id.h"
#include "src/tint/symbol.h" #include "src/tint/symbol.h"
#include "src/tint/traits.h" #include "src/tint/traits.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/hashmap.h" #include "src/tint/utils/hashmap.h"
#include "src/tint/utils/hashset.h" #include "src/tint/utils/hashset.h"
#include "src/tint/utils/vector.h" #include "src/tint/utils/vector.h"
@ -300,8 +301,9 @@ class CloneContext {
using TPtr = traits::ParameterType<F, 0>; using TPtr = traits::ParameterType<F, 0>;
using T = typename std::remove_pointer<TPtr>::type; using T = typename std::remove_pointer<TPtr>::type;
for (auto& transform : transforms_) { for (auto& transform : transforms_) {
if (transform.typeinfo->Is(&TypeInfo::Of<T>()) || bool already_registered = transform.typeinfo->Is(&TypeInfo::Of<T>()) ||
TypeInfo::Of<T>().Is(transform.typeinfo)) { TypeInfo::Of<T>().Is(transform.typeinfo);
if (TINT_UNLIKELY(already_registered)) {
TINT_ICE(Clone, Diagnostics()) TINT_ICE(Clone, Diagnostics())
<< "ReplaceAll() called with a handler for type " << TypeInfo::Of<T>().name << "ReplaceAll() called with a handler for type " << TypeInfo::Of<T>().name
<< " that is already handled by a handler for type " << " that is already handled by a handler for type "
@ -326,7 +328,7 @@ class CloneContext {
/// register a SymbolTransform more than once will result in an ICE. /// register a SymbolTransform more than once will result in an ICE.
/// @returns this CloneContext so calls can be chained /// @returns this CloneContext so calls can be chained
CloneContext& ReplaceAll(const SymbolTransform& replacer) { CloneContext& ReplaceAll(const SymbolTransform& replacer) {
if (symbol_transform_) { if (TINT_UNLIKELY(symbol_transform_)) {
TINT_ICE(Clone, Diagnostics()) << "ReplaceAll(const SymbolTransform&) called " TINT_ICE(Clone, Diagnostics()) << "ReplaceAll(const SymbolTransform&) called "
"multiple times on the same CloneContext"; "multiple times on the same CloneContext";
return *this; return *this;
@ -383,7 +385,7 @@ class CloneContext {
template <typename T, size_t N, typename OBJECT> template <typename T, size_t N, typename OBJECT>
CloneContext& Remove(const utils::Vector<T, N>& vector, OBJECT* object) { CloneContext& Remove(const utils::Vector<T, N>& vector, OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, object);
if (std::find(vector.begin(), vector.end(), object) == vector.end()) { if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), object) == vector.end()))) {
TINT_ICE(Clone, Diagnostics()) TINT_ICE(Clone, Diagnostics())
<< "CloneContext::Remove() vector does not contain object"; << "CloneContext::Remove() vector does not contain object";
return *this; return *this;
@ -450,7 +452,7 @@ class CloneContext {
const OBJECT* object) { const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, before);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
if (std::find(vector.begin(), vector.end(), before) == vector.end()) { if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), before) == vector.end()))) {
TINT_ICE(Clone, Diagnostics()) TINT_ICE(Clone, Diagnostics())
<< "CloneContext::InsertBefore() vector does not contain before"; << "CloneContext::InsertBefore() vector does not contain before";
return *this; return *this;
@ -492,7 +494,7 @@ class CloneContext {
const OBJECT* object) { const OBJECT* object) {
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, src, after);
TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object); TINT_ASSERT_PROGRAM_IDS_EQUAL_IF_VALID(Clone, dst, object);
if (std::find(vector.begin(), vector.end(), after) == vector.end()) { if (TINT_UNLIKELY((std::find(vector.begin(), vector.end(), after) == vector.end()))) {
TINT_ICE(Clone, Diagnostics()) TINT_ICE(Clone, Diagnostics())
<< "CloneContext::InsertAfter() vector does not contain after"; << "CloneContext::InsertAfter() vector does not contain after";
return *this; return *this;
@ -583,7 +585,8 @@ class CloneContext {
if (obj == nullptr) { if (obj == nullptr) {
return nullptr; return nullptr;
} }
if (const TO* cast = obj->template As<TO>()) { const TO* cast = obj->template As<TO>();
if (TINT_LIKELY(cast)) {
return cast; return cast;
} }
CheckedCastFailure(obj, TypeInfo::Of<TO>()); CheckedCastFailure(obj, TypeInfo::Of<TO>());

View File

@ -887,7 +887,7 @@ void Inspector::GenerateSamplerTargets() {
template <size_t N, typename F> template <size_t N, typename F>
void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) { void Inspector::GetOriginatingResources(std::array<const ast::Expression*, N> exprs, F&& callback) {
if (!program_->IsValid()) { if (TINT_UNLIKELY(!program_->IsValid())) {
TINT_ICE(Inspector, diagnostics_) TINT_ICE(Inspector, diagnostics_)
<< "attempting to get originating resources in invalid program"; << "attempting to get originating resources in invalid program";
return; return;

View File

@ -21,6 +21,7 @@
#include "src/tint/demangler.h" #include "src/tint/demangler.h"
#include "src/tint/sem/expression.h" #include "src/tint/sem/expression.h"
#include "src/tint/sem/variable.h" #include "src/tint/sem/variable.h"
#include "src/tint/utils/compiler_macros.h"
using namespace tint::number_suffixes; // NOLINT using namespace tint::number_suffixes; // NOLINT
@ -89,7 +90,7 @@ void ProgramBuilder::MarkAsMoved() {
} }
void ProgramBuilder::AssertNotMoved() const { void ProgramBuilder::AssertNotMoved() const {
if (moved_) { if (TINT_UNLIKELY(moved_)) {
TINT_ICE(ProgramBuilder, const_cast<ProgramBuilder*>(this)->diagnostics_) TINT_ICE(ProgramBuilder, const_cast<ProgramBuilder*>(this)->diagnostics_)
<< "Attempting to use ProgramBuilder after it has been moved"; << "Attempting to use ProgramBuilder after it has been moved";
} }

View File

@ -296,15 +296,15 @@ bool ParserImpl::peek_is(Token::Type tok, size_t idx) {
} }
void ParserImpl::split_token(Token::Type lhs, Token::Type rhs) { void ParserImpl::split_token(Token::Type lhs, Token::Type rhs) {
if (next_token_idx_ == 0) { if (TINT_UNLIKELY(next_token_idx_ == 0)) {
TINT_ICE(Reader, builder_.Diagnostics()) TINT_ICE(Reader, builder_.Diagnostics())
<< "attempt to update placeholder at beginning of tokens"; << "attempt to update placeholder at beginning of tokens";
} }
if (next_token_idx_ >= tokens_.size()) { if (TINT_UNLIKELY(next_token_idx_ >= tokens_.size())) {
TINT_ICE(Reader, builder_.Diagnostics()) TINT_ICE(Reader, builder_.Diagnostics())
<< "attempt to update placeholder past end of tokens"; << "attempt to update placeholder past end of tokens";
} }
if (!tokens_[next_token_idx_].IsPlaceholder()) { if (TINT_UNLIKELY(!tokens_[next_token_idx_].IsPlaceholder())) {
TINT_ICE(Reader, builder_.Diagnostics()) << "attempt to update non-placeholder token"; TINT_ICE(Reader, builder_.Diagnostics()) << "attempt to update non-placeholder token";
} }
tokens_[next_token_idx_ - 1].SetType(lhs); tokens_[next_token_idx_ - 1].SetType(lhs);
@ -3852,7 +3852,7 @@ T ParserImpl::sync(Token::Type tok, F&& body) {
auto result = body(); auto result = body();
--parse_depth_; --parse_depth_;
if (sync_tokens_.back() != tok) { if (TINT_UNLIKELY(sync_tokens_.back() != tok)) {
TINT_ICE(Reader, builder_.Diagnostics()) << "sync_tokens is out of sync"; TINT_ICE(Reader, builder_.Diagnostics()) << "sync_tokens is out of sync";
} }
sync_tokens_.pop_back(); sync_tokens_.pop_back();

View File

@ -332,7 +332,7 @@ ConstEval::Result CompositeConvert(const constant::Composite* composite,
std::function<const type::Type*(size_t idx)> target_el_ty; std::function<const type::Type*(size_t idx)> target_el_ty;
if (auto* str = target_ty->As<type::Struct>()) { if (auto* str = target_ty->As<type::Struct>()) {
if (str->Members().Length() != composite->elements.Length()) { if (TINT_UNLIKELY(str->Members().Length() != composite->elements.Length())) {
TINT_ICE(Resolver, builder.Diagnostics()) TINT_ICE(Resolver, builder.Diagnostics())
<< "const-eval conversion of structure has mismatched element counts"; << "const-eval conversion of structure has mismatched element counts";
return utils::Failure; return utils::Failure;
@ -1837,7 +1837,7 @@ ConstEval::Result ConstEval::OpShiftLeft(const type::Type* ty,
return Dispatch_ia_iu32(create, c0, c1); return Dispatch_ia_iu32(create, c0, c1);
}; };
if (!type::Type::DeepestElementOf(args[1]->Type())->Is<type::U32>()) { if (TINT_UNLIKELY(!type::Type::DeepestElementOf(args[1]->Type())->Is<type::U32>())) {
TINT_ICE(Resolver, builder.Diagnostics()) TINT_ICE(Resolver, builder.Diagnostics())
<< "Element type of rhs of ShiftLeft must be a u32"; << "Element type of rhs of ShiftLeft must be a u32";
return utils::Failure; return utils::Failure;
@ -1901,7 +1901,7 @@ ConstEval::Result ConstEval::OpShiftRight(const type::Type* ty,
return Dispatch_ia_iu32(create, c0, c1); return Dispatch_ia_iu32(create, c0, c1);
}; };
if (!type::Type::DeepestElementOf(args[1]->Type())->Is<type::U32>()) { if (TINT_UNLIKELY(!type::Type::DeepestElementOf(args[1]->Type())->Is<type::U32>())) {
TINT_ICE(Resolver, builder.Diagnostics()) TINT_ICE(Resolver, builder.Diagnostics())
<< "Element type of rhs of ShiftLeft must be a u32"; << "Element type of rhs of ShiftLeft must be a u32";
return utils::Failure; return utils::Failure;

View File

@ -71,6 +71,7 @@
#include "src/tint/symbol_table.h" #include "src/tint/symbol_table.h"
#include "src/tint/type/short_name.h" #include "src/tint/type/short_name.h"
#include "src/tint/utils/block_allocator.h" #include "src/tint/utils/block_allocator.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
@ -319,8 +320,8 @@ class DependencyScanner {
}, },
[&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); }, [&](const ast::StaticAssert* assertion) { TraverseExpression(assertion->condition); },
[&](Default) { [&](Default) {
if (!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement, if (TINT_UNLIKELY((!stmt->IsAnyOf<ast::BreakStatement, ast::ContinueStatement,
ast::DiscardStatement>()) { ast::DiscardStatement>()))) {
UnhandledNode(diagnostics_, stmt); UnhandledNode(diagnostics_, stmt);
} }
}); });
@ -697,7 +698,7 @@ struct DependencyAnalysis {
sorted_.Add(global->node); sorted_.Add(global->node);
if (!stack.IsEmpty()) { if (TINT_UNLIKELY(!stack.IsEmpty())) {
// Each stack.push() must have a corresponding stack.pop_back(). // Each stack.push() must have a corresponding stack.pop_back().
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
<< "stack not empty after returning from TraverseDependencies()"; << "stack not empty after returning from TraverseDependencies()";
@ -709,7 +710,8 @@ struct DependencyAnalysis {
/// of global `from` depending on `to`. /// of global `from` depending on `to`.
/// @note will raise an ICE if the edge is not found. /// @note will raise an ICE if the edge is not found.
DependencyInfo DepInfoFor(const Global* from, const Global* to) const { DependencyInfo DepInfoFor(const Global* from, const Global* to) const {
if (auto info = dependency_edges_.Find(DependencyEdge{from, to})) { auto info = dependency_edges_.Find(DependencyEdge{from, to});
if (TINT_LIKELY(info)) {
return *info; return *info;
} }
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)

View File

@ -1546,7 +1546,7 @@ IntrinsicPrototype Impl::MatchIntrinsic(const IntrinsicInfo& intrinsic,
Any any; Any any;
return_type = return_type =
Match(match.templates, match.overload, indices, earliest_eval_stage).Type(&any); Match(match.templates, match.overload, indices, earliest_eval_stage).Type(&any);
if (!return_type) { if (TINT_UNLIKELY(!return_type)) {
TINT_ICE(Resolver, builder.Diagnostics()) << "MatchState.Match() returned null"; TINT_ICE(Resolver, builder.Diagnostics()) << "MatchState.Match() returned null";
return {}; return {};
} }

View File

@ -83,6 +83,7 @@
#include "src/tint/type/sampler.h" #include "src/tint/type/sampler.h"
#include "src/tint/type/short_name.h" #include "src/tint/type/short_name.h"
#include "src/tint/type/storage_texture.h" #include "src/tint/type/storage_texture.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/math.h" #include "src/tint/utils/math.h"
#include "src/tint/utils/reverse.h" #include "src/tint/utils/reverse.h"
@ -130,7 +131,7 @@ bool Resolver::Resolve() {
bool result = ResolveInternal(); bool result = ResolveInternal();
if (!result && !diagnostics_.contains_errors()) { if (TINT_UNLIKELY(!result && !diagnostics_.contains_errors())) {
TINT_ICE(Resolver, diagnostics_) << "resolving failed, but no error was raised"; TINT_ICE(Resolver, diagnostics_) << "resolving failed, but no error was raised";
return false; return false;
} }
@ -188,7 +189,7 @@ bool Resolver::ResolveInternal() {
bool result = true; bool result = true;
for (auto* node : builder_->ASTNodes().Objects()) { for (auto* node : builder_->ASTNodes().Objects()) {
if (!marked_[node->node_id.value]) { if (TINT_UNLIKELY(!marked_[node->node_id.value])) {
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
<< "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n" << "AST node '" << node->TypeInfo().name << "' was not reached by the resolver\n"
<< "At: " << node->source << "\n" << "At: " << node->source << "\n"
@ -884,7 +885,7 @@ bool Resolver::AllocateOverridableConstantIds() {
void Resolver::SetShadows() { void Resolver::SetShadows() {
for (auto it : dependencies_.shadows) { for (auto it : dependencies_.shadows) {
CastableBase* b = sem_.Get(it.value); CastableBase* b = sem_.Get(it.value);
if (!b) { if (TINT_UNLIKELY(!b)) {
TINT_ICE(Resolver, builder_->Diagnostics()) TINT_ICE(Resolver, builder_->Diagnostics())
<< "AST node '" << it.value->TypeInfo().name << "' had no semantic info\n" << "AST node '" << it.value->TypeInfo().name << "' had no semantic info\n"
<< "At: " << it.value->source << "\n" << "At: " << it.value->source << "\n"
@ -1073,7 +1074,7 @@ sem::Function* Resolver::Function(const ast::Function* decl) {
if (decl->body) { if (decl->body) {
Mark(decl->body); Mark(decl->body);
if (current_compound_statement_) { if (TINT_UNLIKELY(current_compound_statement_)) {
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
<< "Resolver::Function() called with a current compound statement"; << "Resolver::Function() called with a current compound statement";
return nullptr; return nullptr;
@ -1804,7 +1805,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
const constant::Value* materialized_val = nullptr; const constant::Value* materialized_val = nullptr;
if (!skip_const_eval_.Contains(decl)) { if (!skip_const_eval_.Contains(decl)) {
auto expr_val = expr->ConstantValue(); auto expr_val = expr->ConstantValue();
if (!expr_val) { if (TINT_UNLIKELY(!expr_val)) {
TINT_ICE(Resolver, builder_->Diagnostics()) TINT_ICE(Resolver, builder_->Diagnostics())
<< decl->source << "Materialize(" << decl->TypeInfo().name << decl->source << "Materialize(" << decl->TypeInfo().name
<< ") called on expression with no constant value"; << ") called on expression with no constant value";
@ -1817,7 +1818,7 @@ const sem::Expression* Resolver::Materialize(const sem::Expression* expr,
return nullptr; return nullptr;
} }
materialized_val = val.Get(); materialized_val = val.Get();
if (!materialized_val) { if (TINT_UNLIKELY(!materialized_val)) {
TINT_ICE(Resolver, builder_->Diagnostics()) TINT_ICE(Resolver, builder_->Diagnostics())
<< decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val->Type()) << decl->source << "ConvertValue(" << builder_->FriendlyName(expr_val->Type())
<< " -> " << builder_->FriendlyName(concrete_ty) << ") returned invalid value"; << " -> " << builder_->FriendlyName(concrete_ty) << ") returned invalid value";
@ -2488,7 +2489,7 @@ void Resolver::CollectTextureSamplerPairs(const sem::Builtin* builtin,
// Collect a texture/sampler pair for this builtin. // Collect a texture/sampler pair for this builtin.
const auto& signature = builtin->Signature(); const auto& signature = builtin->Signature();
int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture); int texture_index = signature.IndexOf(sem::ParameterUsage::kTexture);
if (texture_index == -1) { if (TINT_UNLIKELY(texture_index == -1)) {
TINT_ICE(Resolver, diagnostics_) << "texture builtin without texture parameter"; TINT_ICE(Resolver, diagnostics_) << "texture builtin without texture parameter";
} }
if (auto* user = if (auto* user =
@ -3445,7 +3446,7 @@ sem::Struct* Resolver::Structure(const ast::Struct* str) {
AddError(msg.str(), str->source); AddError(msg.str(), str->source);
return nullptr; return nullptr;
} }
if (struct_align > std::numeric_limits<uint32_t>::max()) { if (TINT_UNLIKELY(struct_align > std::numeric_limits<uint32_t>::max())) {
TINT_ICE(Resolver, diagnostics_) << "calculated struct stride exceeds uint32"; TINT_ICE(Resolver, diagnostics_) << "calculated struct stride exceeds uint32";
return nullptr; return nullptr;
} }
@ -3842,12 +3843,12 @@ SEM* Resolver::StatementScope(const ast::Statement* ast, SEM* sem, F&& callback)
} }
bool Resolver::Mark(const ast::Node* node) { bool Resolver::Mark(const ast::Node* node) {
if (node == nullptr) { if (TINT_UNLIKELY(node == nullptr)) {
TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr"; TINT_ICE(Resolver, diagnostics_) << "Resolver::Mark() called with nullptr";
return false; return false;
} }
auto marked_bit_ref = marked_[node->node_id.value]; auto marked_bit_ref = marked_[node->node_id.value];
if (!marked_bit_ref) { if (TINT_LIKELY(!marked_bit_ref)) {
marked_bit_ref = true; marked_bit_ref = true;
return true; return true;
} }

View File

@ -40,7 +40,7 @@ class SemHelper {
auto* Get(const AST_OR_TYPE* ast) const { auto* Get(const AST_OR_TYPE* ast) const {
using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>; using T = sem::Info::GetResultType<SEM, AST_OR_TYPE>;
auto* sem = builder_->Sem().Get(ast); auto* sem = builder_->Sem().Get(ast);
if (!sem) { if (TINT_UNLIKELY(!sem)) {
TINT_ICE(Resolver, builder_->Diagnostics()) TINT_ICE(Resolver, builder_->Diagnostics())
<< "AST node '" << ast->TypeInfo().name << "' had no semantic info\n" << "AST node '" << ast->TypeInfo().name << "' had no semantic info\n"
<< "At: " << ast->source << "\n" << "At: " << ast->source << "\n"

View File

@ -1007,8 +1007,8 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co
AddError("missing return at end of function", decl->source); AddError("missing return at end of function", decl->source);
return false; return false;
} }
} else if (IsValidationEnabled(decl->attributes, } else if (TINT_UNLIKELY(IsValidationEnabled(
ast::DisabledValidation::kFunctionHasNoBody)) { decl->attributes, ast::DisabledValidation::kFunctionHasNoBody))) {
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
<< "Function " << symbols_.NameFor(decl->symbol) << " has no body"; << "Function " << symbols_.NameFor(decl->symbol) << " has no body";
} }
@ -1040,7 +1040,8 @@ bool Validator::Function(const sem::Function* func, ast::PipelineStage stage) co
// https://www.w3.org/TR/WGSL/#behaviors-rules // https://www.w3.org/TR/WGSL/#behaviors-rules
// a function behavior is always one of {}, or {Next}. // a function behavior is always one of {}, or {Next}.
if (func->Behaviors() != sem::Behaviors{} && func->Behaviors() != sem::Behavior::kNext) { if (TINT_UNLIKELY(func->Behaviors() != sem::Behaviors{} &&
func->Behaviors() != sem::Behavior::kNext)) {
auto name = symbols_.NameFor(decl->symbol); auto name = symbols_.NameFor(decl->symbol);
TINT_ICE(Resolver, diagnostics_) TINT_ICE(Resolver, diagnostics_)
<< "function '" << name << "' behaviors are: " << func->Behaviors(); << "function '" << name << "' behaviors are: " << func->Behaviors();
@ -1111,7 +1112,7 @@ bool Validator::EntryPoint(const sem::Function* func, ast::PipelineStage stage)
bool is_input = param_or_ret == ParamOrRetType::kParameter; bool is_input = param_or_ret == ParamOrRetType::kParameter;
if (!location.has_value()) { if (TINT_UNLIKELY(!location.has_value())) {
TINT_ICE(Resolver, diagnostics_) << "Location has no value"; TINT_ICE(Resolver, diagnostics_) << "Location has no value";
return false; return false;
} }
@ -1810,7 +1811,7 @@ bool Validator::ArrayInitializer(const ast::CallExpression* ctor,
return false; return false;
} }
if (!c->Is<type::ConstantArrayCount>()) { if (TINT_UNLIKELY(!c->Is<type::ConstantArrayCount>())) {
TINT_ICE(Resolver, diagnostics_) << "Invalid ArrayCount found"; TINT_ICE(Resolver, diagnostics_) << "Invalid ArrayCount found";
return false; return false;
} }

View File

@ -218,7 +218,7 @@ struct ArrayLengthFromUniform::State {
// arrayLength(&struct_var.array_member) // arrayLength(&struct_var.array_member)
// arrayLength(&array_var) // arrayLength(&array_var)
auto* param = call_expr->args[0]->As<ast::UnaryOpExpression>(); auto* param = call_expr->args[0]->As<ast::UnaryOpExpression>();
if (!param || param->op != ast::UnaryOp::kAddressOf) { if (TINT_UNLIKELY(!param || param->op != ast::UnaryOp::kAddressOf)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected form of arrayLength argument to be &array_var or " << "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member"; "&struct_var.array_member";
@ -229,7 +229,7 @@ struct ArrayLengthFromUniform::State {
storage_buffer_expr = accessor->structure; storage_buffer_expr = accessor->structure;
} }
auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr); auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
if (!storage_buffer_sem) { if (TINT_UNLIKELY(!storage_buffer_sem)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected form of arrayLength argument to be &array_var or " << "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member"; "&struct_var.array_member";
@ -238,7 +238,7 @@ struct ArrayLengthFromUniform::State {
// Get the index to use for the buffer size array. // Get the index to use for the buffer size array.
auto* var = tint::As<sem::GlobalVariable>(storage_buffer_sem->Variable()); auto* var = tint::As<sem::GlobalVariable>(storage_buffer_sem->Variable());
if (!var) { if (TINT_UNLIKELY(!var)) {
TINT_ICE(Transform, b.Diagnostics()) << "storage buffer is not a global variable"; TINT_ICE(Transform, b.Diagnostics()) << "storage buffer is not a global variable";
break; break;
} }

View File

@ -480,7 +480,7 @@ struct BuiltinPolyfill::State {
uint32_t width = WidthOf(ty); uint32_t width = WidthOf(ty);
// Currently in WGSL parameters of insertBits must be i32, u32, vecN<i32> or vecN<u32> // Currently in WGSL parameters of insertBits must be i32, u32, vecN<i32> or vecN<u32>
if (!type::Type::DeepestElementOf(ty)->IsAnyOf<type::I32, type::U32>()) { if (TINT_UNLIKELY(((!type::Type::DeepestElementOf(ty)->IsAnyOf<type::I32, type::U32>())))) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "insertBits polyfill only support i32, u32, and vector of i32 or u32, got " << "insertBits polyfill only support i32, u32, and vector of i32 or u32, got "
<< b.FriendlyName(ty); << b.FriendlyName(ty);

View File

@ -152,7 +152,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
// arrayLength(&array_var) // arrayLength(&array_var)
auto* arg = call_expr->args[0]; auto* arg = call_expr->args[0];
auto* address_of = arg->As<ast::UnaryOpExpression>(); auto* address_of = arg->As<ast::UnaryOpExpression>();
if (!address_of || address_of->op != ast::UnaryOp::kAddressOf) { if (TINT_UNLIKELY(!address_of || address_of->op != ast::UnaryOp::kAddressOf)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "arrayLength() expected address-of, got " << arg->TypeInfo().name; << "arrayLength() expected address-of, got " << arg->TypeInfo().name;
} }
@ -161,7 +161,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
storage_buffer_expr = accessor->structure; storage_buffer_expr = accessor->structure;
} }
auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr); auto* storage_buffer_sem = sem.Get<sem::VariableUser>(storage_buffer_expr);
if (!storage_buffer_sem) { if (TINT_UNLIKELY(!storage_buffer_sem)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected form of arrayLength argument to be &array_var or " << "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member"; "&struct_var.array_member";
@ -213,7 +213,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
}, },
[&](const type::Array* arr) { return arr; }); [&](const type::Array* arr) { return arr; });
if (!array_type) { if (TINT_UNLIKELY(!array_type)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected form of arrayLength argument to be " << "expected form of arrayLength argument to be "
"&array_var or &struct_var.array_member"; "&array_var or &struct_var.array_member";

View File

@ -354,7 +354,7 @@ struct CanonicalizeEntryPointIO::State {
// list to pass them through to the inner function. // list to pass them through to the inner function.
utils::Vector<const ast::Expression*, 8> inner_struct_values; utils::Vector<const ast::Expression*, 8> inner_struct_values;
for (auto* member : str->Members()) { for (auto* member : str->Members()) {
if (member->Type()->Is<sem::Struct>()) { if (TINT_UNLIKELY(member->Type()->Is<sem::Struct>())) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct"; TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
continue; continue;
} }
@ -383,7 +383,7 @@ struct CanonicalizeEntryPointIO::State {
bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment; bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
if (auto* str = inner_ret_type->As<sem::Struct>()) { if (auto* str = inner_ret_type->As<sem::Struct>()) {
for (auto* member : str->Members()) { for (auto* member : str->Members()) {
if (member->Type()->Is<sem::Struct>()) { if (TINT_UNLIKELY(member->Type()->Is<sem::Struct>())) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct"; TINT_ICE(Transform, ctx.dst->Diagnostics()) << "nested IO struct";
continue; continue;
} }

View File

@ -89,7 +89,7 @@ Transform::ApplyResult ClampFragDepth::Apply(const Program* src, const DataMap&,
// Abort on any use of push constants in the module. // Abort on any use of push constants in the module.
for (auto* global : src->AST().GlobalVariables()) { for (auto* global : src->AST().GlobalVariables()) {
if (auto* var = global->As<ast::Var>()) { if (auto* var = global->As<ast::Var>()) {
if (var->declared_address_space == ast::AddressSpace::kPushConstant) { if (TINT_UNLIKELY(var->declared_address_space == ast::AddressSpace::kPushConstant)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "ClampFragDepth doesn't know how to handle module that already use push " << "ClampFragDepth doesn't know how to handle module that already use push "
"constants."; "constants.";

View File

@ -503,7 +503,7 @@ struct DecomposeMemoryAccess::State {
auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u)); auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
auto* for_init = b.Decl(i); auto* for_init = b.Decl(i);
auto arr_cnt = arr_ty->ConstantCount(); auto arr_cnt = arr_ty->ConstantCount();
if (!arr_cnt) { if (TINT_UNLIKELY(!arr_cnt)) {
// Non-constant counts should not be possible: // Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and // * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles storage and uniform. // this method only handles storage and uniform.
@ -607,7 +607,7 @@ struct DecomposeMemoryAccess::State {
auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u)); auto* i = b.Var(b.Symbols().New("i"), b.Expr(0_u));
auto* for_init = b.Decl(i); auto* for_init = b.Decl(i);
auto arr_cnt = arr_ty->ConstantCount(); auto arr_cnt = arr_ty->ConstantCount();
if (!arr_cnt) { if (TINT_UNLIKELY(!arr_cnt)) {
// Non-constant counts should not be possible: // Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup // * Override-expression counts can only be applied to workgroup
// arrays, and this method only handles storage and uniform. // arrays, and this method only handles storage and uniform.
@ -700,7 +700,7 @@ struct DecomposeMemoryAccess::State {
} }
auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty); auto* atomic = IntrinsicAtomicFor(ctx.dst, op, el_ty);
if (atomic == nullptr) { if (TINT_UNLIKELY(!atomic)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "IntrinsicAtomicFor() returned nullptr for op " << op << " and type " << "IntrinsicAtomicFor() returned nullptr for op " << op << " and type "
<< el_ty->TypeInfo().name; << el_ty->TypeInfo().name;

View File

@ -1097,7 +1097,8 @@ struct DirectVariableAccess::State {
continue; continue;
} }
if (auto* member = std::get_if<Symbol>(&op)) { auto* member = std::get_if<Symbol>(&op);
if (TINT_LIKELY(member)) {
ss << sym.NameFor(*member); ss << sym.NameFor(*member);
continue; continue;
} }
@ -1145,7 +1146,8 @@ struct DirectVariableAccess::State {
return b.IndexAccessor(expr, idx); return b.IndexAccessor(expr, idx);
} }
if (auto* member = std::get_if<Symbol>(&access)) { auto* member = std::get_if<Symbol>(&access);
if (TINT_LIKELY(member)) {
/// The access is a member access. /// The access is a member access.
return b.MemberAccessor(expr, ctx.Clone(*member)); return b.MemberAccessor(expr, ctx.Clone(*member));
} }

View File

@ -187,24 +187,27 @@ struct LocalizeStructArrayAssignment::State {
std::pair<const type::Type*, ast::AddressSpace> GetOriginatingTypeAndAddressSpace( std::pair<const type::Type*, ast::AddressSpace> GetOriginatingTypeAndAddressSpace(
const ast::AssignmentStatement* assign_stmt) { const ast::AssignmentStatement* assign_stmt) {
auto* root_ident = src->Sem().Get(assign_stmt->lhs)->RootIdentifier(); auto* root_ident = src->Sem().Get(assign_stmt->lhs)->RootIdentifier();
if (!root_ident) { if (TINT_UNLIKELY(!root_ident)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "Unable to determine originating variable for lhs of assignment " << "Unable to determine originating variable for lhs of assignment "
"statement"; "statement";
return {}; return {};
} }
auto* type = root_ident->Type(); return Switch(
if (auto* ref = type->As<type::Reference>()) { root_ident->Type(), //
return {ref->StoreType(), ref->AddressSpace()}; [&](const type::Reference* ref) {
} else if (auto* ptr = type->As<type::Pointer>()) { return std::make_pair(ref->StoreType(), ref->AddressSpace());
return {ptr->StoreType(), ptr->AddressSpace()}; },
} [&](const type::Pointer* ptr) {
return std::make_pair(ptr->StoreType(), ptr->AddressSpace());
TINT_ICE(Transform, b.Diagnostics()) },
<< "Expecting to find variable of type pointer or reference on lhs " [&](Default) {
"of assignment statement"; TINT_ICE(Transform, b.Diagnostics())
return {}; << "Expecting to find variable of type pointer or reference on lhs "
"of assignment statement";
return std::pair<const type::Type*, ast::AddressSpace>{};
});
} }
}; };

View File

@ -402,7 +402,7 @@ struct MultiplanarExternalTexture::State {
NewBindingSymbols syms) { NewBindingSymbols syms) {
const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]); const ast::Expression* plane_0_binding_param = ctx.Clone(expr->args[0]);
if (expr->args.Length() != 3) { if (TINT_UNLIKELY(expr->args.Length() != 3)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected textureSampleBaseClampToEdge call with a " << "expected textureSampleBaseClampToEdge call with a "
"texture_external to have 3 parameters, found " "texture_external to have 3 parameters, found "
@ -447,7 +447,7 @@ struct MultiplanarExternalTexture::State {
/// @param syms the expanded symbols to be used in the new call /// @param syms the expanded symbols to be used in the new call
/// @returns a call expression to textureLoadExternal /// @returns a call expression to textureLoadExternal
const ast::CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) { const ast::CallExpression* createTextureLoad(const sem::Call* call, NewBindingSymbols syms) {
if (call->Arguments().Length() != 2) { if (TINT_UNLIKELY(call->Arguments().Length() != 2)) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "expected textureLoad call with a texture_external to have 2 arguments, found " << "expected textureLoad call with a texture_external to have 2 arguments, found "
<< call->Arguments().Length() << " arguments"; << call->Arguments().Length() << " arguments";

View File

@ -25,6 +25,7 @@
#include "src/tint/sem/module.h" #include "src/tint/sem/module.h"
#include "src/tint/sem/struct.h" #include "src/tint/sem/struct.h"
#include "src/tint/sem/variable.h" #include "src/tint/sem/variable.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/hashmap.h" #include "src/tint/utils/hashmap.h"
#include "src/tint/utils/transform.h" #include "src/tint/utils/transform.h"
@ -433,7 +434,7 @@ struct Std140::State {
attrs.Push(b.create<ast::StrideAttribute>(arr->Stride())); attrs.Push(b.create<ast::StrideAttribute>(arr->Stride()));
} }
auto count = arr->ConstantCount(); auto count = arr->ConstantCount();
if (!count) { if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible: // Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and // * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles types transitively used as uniform buffers. // this method only handles types transitively used as uniform buffers.
@ -518,7 +519,7 @@ struct Std140::State {
access.indices.Push(UniformVariable{}); access.indices.Push(UniformVariable{});
return Action::kStop; return Action::kStop;
} }
if (user->Variable()->Type()->Is<type::Pointer>()) { if (TINT_LIKELY(user->Variable()->Type()->Is<type::Pointer>())) {
// Found a pointer. As the root identifier is a uniform buffer variable, // Found a pointer. As the root identifier is a uniform buffer variable,
// this must be a pointer-let. Continue traversing from the let // this must be a pointer-let. Continue traversing from the let
// initializer. // initializer.
@ -633,7 +634,7 @@ struct Std140::State {
[&](const sem::Struct* str) { return sym.NameFor(str->Name()); }, [&](const sem::Struct* str) { return sym.NameFor(str->Name()); },
[&](const type::Array* arr) { [&](const type::Array* arr) {
auto count = arr->ConstantCount(); auto count = arr->ConstantCount();
if (!count) { if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible: // Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and // * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles types transitively used as uniform buffers. // this method only handles types transitively used as uniform buffers.
@ -717,7 +718,8 @@ struct Std140::State {
}, // }, //
[&](const type::Matrix* mat) { [&](const type::Matrix* mat) {
// Reassemble a std140 matrix from the structure of column vector members. // Reassemble a std140 matrix from the structure of column vector members.
if (auto std140_mat = std140_mats.Get(mat)) { auto std140_mat = std140_mats.Get(mat);
if (TINT_LIKELY(std140_mat)) {
utils::Vector<const ast::Expression*, 8> args; utils::Vector<const ast::Expression*, 8> args;
// std140 decomposed matrix. Reassemble. // std140 decomposed matrix. Reassemble.
auto* mat_ty = CreateASTTypeFor(ctx, mat); auto* mat_ty = CreateASTTypeFor(ctx, mat);
@ -739,7 +741,7 @@ struct Std140::State {
auto* dst_el = b.IndexAccessor(var, i); auto* dst_el = b.IndexAccessor(var, i);
auto* src_el = Convert(arr->ElemType(), b.IndexAccessor(param, i)); auto* src_el = Convert(arr->ElemType(), b.IndexAccessor(param, i));
auto count = arr->ConstantCount(); auto count = arr->ConstantCount();
if (!count) { if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible: // Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and // * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles types transitively used as uniform buffers. // this method only handles types transitively used as uniform buffers.

View File

@ -65,7 +65,7 @@ void Transform::RemoveStatement(CloneContext& ctx, const ast::Statement* stmt) {
ctx.Remove(block->Declaration()->statements, stmt); ctx.Remove(block->Declaration()->statements, stmt);
return; return;
} }
if (tint::Is<sem::ForLoopStatement>(sem->Parent())) { if (TINT_LIKELY(tint::Is<sem::ForLoopStatement>(sem->Parent()))) {
ctx.Replace(stmt, static_cast<ast::Expression*>(nullptr)); ctx.Replace(stmt, static_cast<ast::Expression*>(nullptr));
return; return;
} }
@ -130,11 +130,12 @@ const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type
auto* count = ctx.Clone(override->expr->Declaration()); auto* count = ctx.Clone(override->expr->Declaration());
return ctx.dst->ty.array(el, count, std::move(attrs)); return ctx.dst->ty.array(el, count, std::move(attrs));
} }
if (auto count = a->ConstantCount()) { auto count = a->ConstantCount();
return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs)); if (TINT_UNLIKELY(!count)) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) << type::Array::kErrExpectedConstantCount;
return ctx.dst->ty.array(el, u32(1), std::move(attrs));
} }
TINT_ICE(Transform, ctx.dst->Diagnostics()) << type::Array::kErrExpectedConstantCount; return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
return ctx.dst->ty.array(el, u32(1), std::move(attrs));
} }
if (auto* s = ty->As<sem::Struct>()) { if (auto* s = ty->As<sem::Struct>()) {
return ctx.dst->create<ast::TypeName>(ctx.Clone(s->Declaration()->name)); return ctx.dst->create<ast::TypeName>(ctx.Clone(s->Declaration()->name));

View File

@ -83,7 +83,7 @@ Transform::ApplyResult TruncateInterstageVariables::Apply(const Program* src,
auto* func_sem = sem.Get(func_ast); auto* func_sem = sem.Get(func_ast);
auto* str = func_sem->ReturnType()->As<sem::Struct>(); auto* str = func_sem->ReturnType()->As<sem::Struct>();
if (!str) { if (TINT_UNLIKELY(!str)) {
TINT_ICE(Transform, ctx.dst->Diagnostics()) TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "Entrypoint function return type is non-struct.\n" << "Entrypoint function return type is non-struct.\n"
<< "TruncateInterstageVariables transform needs to run after " << "TruncateInterstageVariables transform needs to run after "

View File

@ -336,7 +336,8 @@ struct HoistToDeclBefore::State {
return true; return true;
} }
if (auto* fl = parent->As<sem::ForLoopStatement>()) { auto* fl = parent->As<sem::ForLoopStatement>();
if (TINT_LIKELY(fl)) {
// Insertion point is a for-loop initializer or continuing statement. // Insertion point is a for-loop initializer or continuing statement.
// These require special care. // These require special care.
if (fl->Declaration()->initializer == ip) { if (fl->Declaration()->initializer == ip) {
@ -349,7 +350,7 @@ struct HoistToDeclBefore::State {
return true; return true;
} }
if (fl->Declaration()->continuing == ip) { if (TINT_LIKELY(fl->Declaration()->continuing == ip)) {
// Insertion point is a for-loop continuing statement. // Insertion point is a for-loop continuing statement.
// For-loop needs to be decomposed to a loop. // For-loop needs to be decomposed to a loop.

View File

@ -93,7 +93,8 @@ Transform::ApplyResult VectorizeMatrixConversions::Apply(const Program* src,
} }
// The source and destination type of a matrix conversion must have a same shape. // The source and destination type of a matrix conversion must have a same shape.
if (!(src_type->rows() == dst_type->rows() && src_type->columns() == dst_type->columns())) { if (TINT_UNLIKELY(!(src_type->rows() == dst_type->rows() &&
src_type->columns() == dst_type->columns()))) {
TINT_ICE(Transform, b.Diagnostics()) TINT_ICE(Transform, b.Diagnostics())
<< "source and destination matrix has different shape in matrix conversion"; << "source and destination matrix has different shape in matrix conversion";
return nullptr; return nullptr;

View File

@ -128,7 +128,7 @@ Transform::ApplyResult VectorizeScalarMatrixInitializers::Apply(const Program* s
return b.Call(fn, ctx.Clone(args[0]->Declaration())); return b.Call(fn, ctx.Clone(args[0]->Declaration()));
} }
if (args.Length() == mat_type->columns() * mat_type->rows()) { if (TINT_LIKELY(args.Length() == mat_type->columns() * mat_type->rows())) {
return build_mat([&](uint32_t c, uint32_t r) { return build_mat([&](uint32_t c, uint32_t r) {
return ctx.Clone(args[c * mat_type->rows() + r]->Declaration()); return ctx.Clone(args[c * mat_type->rows() + r]->Declaration());
}); });

View File

@ -22,6 +22,7 @@
#include "src/tint/ast/variable_decl_statement.h" #include "src/tint/ast/variable_decl_statement.h"
#include "src/tint/program_builder.h" #include "src/tint/program_builder.h"
#include "src/tint/sem/variable.h" #include "src/tint/sem/variable.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/math.h" #include "src/tint/utils/math.h"
@ -766,12 +767,17 @@ struct VertexPulling::State {
auto* sem = src->Sem().Get<sem::Parameter>(param); auto* sem = src->Sem().Get<sem::Parameter>(param);
info.type = sem->Type(); info.type = sem->Type();
if (!sem->Location().has_value()) { if (TINT_UNLIKELY(!sem->Location().has_value())) {
TINT_ICE(Transform, b.Diagnostics()) << "Location missing value"; TINT_ICE(Transform, b.Diagnostics()) << "Location missing value";
return; return;
} }
location_info[sem->Location().value()] = info; location_info[sem->Location().value()] = info;
} else if (auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes)) { } else {
auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(param->attributes);
if (TINT_UNLIKELY(!builtin)) {
TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
return;
}
// Check for existing vertex_index and instance_index builtins. // Check for existing vertex_index and instance_index builtins.
if (builtin->builtin == ast::BuiltinValue::kVertexIndex) { if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
vertex_index_expr = [this, param]() { return b.Expr(ctx.Clone(param->symbol)); }; vertex_index_expr = [this, param]() { return b.Expr(ctx.Clone(param->symbol)); };
@ -779,8 +785,6 @@ struct VertexPulling::State {
instance_index_expr = [this, param]() { return b.Expr(ctx.Clone(param->symbol)); }; instance_index_expr = [this, param]() { return b.Expr(ctx.Clone(param->symbol)); };
} }
new_function_parameters.Push(ctx.Clone(param)); new_function_parameters.Push(ctx.Clone(param));
} else {
TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
} }
} }
@ -817,8 +821,12 @@ struct VertexPulling::State {
TINT_ASSERT(Transform, sem->Location().has_value()); TINT_ASSERT(Transform, sem->Location().has_value());
location_info[sem->Location().value()] = info; location_info[sem->Location().value()] = info;
has_locations = true; has_locations = true;
} else if (auto* builtin = } else {
ast::GetAttribute<ast::BuiltinAttribute>(member->attributes)) { auto* builtin = ast::GetAttribute<ast::BuiltinAttribute>(member->attributes);
if (TINT_UNLIKELY(!builtin)) {
TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
return;
}
// Check for existing vertex_index and instance_index builtins. // Check for existing vertex_index and instance_index builtins.
if (builtin->builtin == ast::BuiltinValue::kVertexIndex) { if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
vertex_index_expr = member_expr; vertex_index_expr = member_expr;
@ -826,8 +834,6 @@ struct VertexPulling::State {
instance_index_expr = member_expr; instance_index_expr = member_expr;
} }
members_to_clone.Push(member); members_to_clone.Push(member);
} else {
TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
} }
} }

View File

@ -41,6 +41,9 @@
__pragma(warning(pop)) \ __pragma(warning(pop)) \
TINT_REQUIRE_SEMICOLON TINT_REQUIRE_SEMICOLON
// clang-format on // clang-format on
#define TINT_UNLIKELY(x) x /* currently no-op */
#define TINT_LIKELY(x) x /* currently no-op */
#elif defined(__clang__) #elif defined(__clang__)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Clang // Clang
@ -64,6 +67,9 @@
_Pragma("clang diagnostic pop") \ _Pragma("clang diagnostic pop") \
TINT_REQUIRE_SEMICOLON TINT_REQUIRE_SEMICOLON
// clang-format on // clang-format on
#define TINT_UNLIKELY(x) __builtin_expect(!!(x), false)
#define TINT_LIKELY(x) __builtin_expect(!!(x), true)
#elif defined(__GNUC__) #elif defined(__GNUC__)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// GCC // GCC
@ -87,12 +93,18 @@
_Pragma("GCC diagnostic pop") \ _Pragma("GCC diagnostic pop") \
TINT_REQUIRE_SEMICOLON TINT_REQUIRE_SEMICOLON
// clang-format on // clang-format on
#define TINT_UNLIKELY(x) __builtin_expect(!!(x), false)
#define TINT_LIKELY(x) __builtin_expect(!!(x), true)
#else #else
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Other // Other
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
#define TINT_BEGIN_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON #define TINT_BEGIN_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON
#define TINT_END_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON #define TINT_END_DISABLE_WARNING(name) TINT_REQUIRE_SEMICOLON
#define TINT_UNLIKELY(x) x
#define TINT_LIKELY(x) x
#endif #endif
#endif // SRC_TINT_UTILS_COMPILER_MACROS_H_ #endif // SRC_TINT_UTILS_COMPILER_MACROS_H_

View File

@ -292,41 +292,41 @@ bool GeneratorImpl::Generate() {
continue; // These are not emitted. continue; // These are not emitted.
} }
if (auto* global = decl->As<ast::Variable>()) { bool ok = Switch(
if (!EmitGlobalVariable(global)) { decl, //
[&](const ast::Variable* global) { return EmitGlobalVariable(global); },
[&](const ast::Struct* str) {
auto* sem = builder_.Sem().Get(str);
bool has_rt_arr = false;
if (auto* arr = sem->Members().Back()->Type()->As<type::Array>()) {
has_rt_arr = arr->Count()->Is<type::RuntimeArrayCount>();
}
bool is_block = ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(
str->attributes);
if (!has_rt_arr && !is_block) {
if (!EmitStructType(current_buffer_, sem)) {
return false;
}
}
return true;
},
[&](const ast::Function* func) {
if (func->IsEntryPoint()) {
return EmitEntryPointFunction(func);
}
return EmitFunction(func);
},
[&](const ast::Enable* enable) {
// Record the required extension for generating extension directive later
return RecordExtension(enable);
},
[&](Default) {
TINT_ICE(Writer, diagnostics_)
<< "unhandled module-scope declaration: " << decl->TypeInfo().name;
return false; return false;
} });
} else if (auto* str = decl->As<ast::Struct>()) {
auto* sem = builder_.Sem().Get(str); if (TINT_UNLIKELY(!ok)) {
bool has_rt_arr = false;
if (auto* arr = sem->Members().Back()->Type()->As<type::Array>()) {
has_rt_arr = arr->Count()->Is<type::RuntimeArrayCount>();
}
bool is_block =
ast::HasAttribute<transform::AddBlockAttribute::BlockAttribute>(str->attributes);
if (!has_rt_arr && !is_block) {
if (!EmitStructType(current_buffer_, sem)) {
return false;
}
}
} else if (auto* func = decl->As<ast::Function>()) {
if (func->IsEntryPoint()) {
if (!EmitEntryPointFunction(func)) {
return false;
}
} else {
if (!EmitFunction(func)) {
return false;
}
}
} else if (auto* ext = decl->As<ast::Enable>()) {
// Record the required extension for generating extension directive later
if (!RecordExtension(ext)) {
return false;
}
} else {
TINT_ICE(Writer, diagnostics_)
<< "unhandled module-scope declaration: " << decl->TypeInfo().name;
return false; return false;
} }
} }
@ -493,7 +493,7 @@ bool GeneratorImpl::EmitBitwiseBoolOp(std::ostream& out, const ast::BinaryExpres
// Emit operator. // Emit operator.
if (expr->op == ast::BinaryOp::kAnd) { if (expr->op == ast::BinaryOp::kAnd) {
out << " & "; out << " & ";
} else if (expr->op == ast::BinaryOp::kOr) { } else if (TINT_LIKELY(expr->op == ast::BinaryOp::kOr)) {
out << " | "; out << " | ";
} else { } else {
TINT_ICE(Writer, diagnostics_) << "unexpected binary op: " << FriendlyName(expr->op); TINT_ICE(Writer, diagnostics_) << "unexpected binary op: " << FriendlyName(expr->op);
@ -742,22 +742,17 @@ bool GeneratorImpl::EmitBreakIf(const ast::BreakIfStatement* b) {
bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) { bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr) {
auto* call = builder_.Sem().Get<sem::Call>(expr); auto* call = builder_.Sem().Get<sem::Call>(expr);
auto* target = call->Target(); return Switch(
call->Target(), //
if (target->Is<sem::Function>()) { [&](const sem::Function*) { return EmitFunctionCall(out, call); },
return EmitFunctionCall(out, call); [&](const sem::Builtin* builtin) { return EmitBuiltinCall(out, call, builtin); },
} [&](const sem::TypeConversion* conv) { return EmitTypeConversion(out, call, conv); },
if (auto* builtin = target->As<sem::Builtin>()) { [&](const sem::TypeInitializer* init) { return EmitTypeInitializer(out, call, init); },
return EmitBuiltinCall(out, call, builtin); [&](Default) {
} TINT_ICE(Writer, diagnostics_)
if (auto* cast = target->As<sem::TypeConversion>()) { << "unhandled call target: " << call->Target()->TypeInfo().name;
return EmitTypeConversion(out, call, cast); return false;
} });
if (auto* ctor = target->As<sem::TypeInitializer>()) {
return EmitTypeInitializer(out, call, ctor);
}
TINT_ICE(Writer, diagnostics_) << "unhandled call target: " << target->TypeInfo().name;
return false;
} }
bool GeneratorImpl::EmitFunctionCall(std::ostream& out, const sem::Call* call) { bool GeneratorImpl::EmitFunctionCall(std::ostream& out, const sem::Call* call) {
@ -1379,7 +1374,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
}; };
auto* texture = arg(Usage::kTexture); auto* texture = arg(Usage::kTexture);
if (!texture) { if (TINT_UNLIKELY(!texture)) {
TINT_ICE(Writer, diagnostics_) << "missing texture argument"; TINT_ICE(Writer, diagnostics_) << "missing texture argument";
return false; return false;
} }
@ -1579,7 +1574,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
out << ", "; out << ", ";
auto* param_coords = arg(Usage::kCoords); auto* param_coords = arg(Usage::kCoords);
if (!param_coords) { if (TINT_UNLIKELY(!param_coords)) {
TINT_ICE(Writer, diagnostics_) << "missing coords argument"; TINT_ICE(Writer, diagnostics_) << "missing coords argument";
return false; return false;
} }
@ -1678,7 +1673,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
out << "xyz"[i]; out << "xyz"[i];
} }
} }
if (wgsl_ret_width > glsl_ret_width) { if (TINT_UNLIKELY(wgsl_ret_width > glsl_ret_width)) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "WGSL return width (" << wgsl_ret_width << ") is wider than GLSL return width (" << "WGSL return width (" << wgsl_ret_width << ") is wider than GLSL return width ("
<< glsl_ret_width << ") for " << builtin->Type(); << glsl_ret_width << ") for " << builtin->Type();
@ -2028,7 +2023,7 @@ bool GeneratorImpl::EmitGlobalVariable(const ast::Variable* global) {
bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) { bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable* sem) {
auto* type = sem->Type()->UnwrapRef(); auto* type = sem->Type()->UnwrapRef();
auto* str = type->As<sem::Struct>(); auto* str = type->As<sem::Struct>();
if (!str) { if (TINT_UNLIKELY(!str)) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type"; TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return false; return false;
} }
@ -2049,7 +2044,7 @@ bool GeneratorImpl::EmitUniformVariable(const ast::Var* var, const sem::Variable
bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) { bool GeneratorImpl::EmitStorageVariable(const ast::Var* var, const sem::Variable* sem) {
auto* type = sem->Type()->UnwrapRef(); auto* type = sem->Type()->UnwrapRef();
auto* str = type->As<sem::Struct>(); auto* str = type->As<sem::Struct>();
if (!str) { if (TINT_UNLIKELY(!str)) {
TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type"; TINT_ICE(Writer, builder_.Diagnostics()) << "storage variable must be of struct type";
return false; return false;
} }
@ -2254,7 +2249,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
for (auto* var : func->params) { for (auto* var : func->params) {
auto* sem = builder_.Sem().Get(var); auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type(); auto* type = sem->Type();
if (!type->Is<sem::Struct>()) { if (TINT_UNLIKELY(!type->Is<sem::Struct>())) {
// ICE likely indicates that the CanonicalizeEntryPointIO transform was // ICE likely indicates that the CanonicalizeEntryPointIO transform was
// not run, or a builtin parameter was added after it was run. // not run, or a builtin parameter was added after it was run.
TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter"; TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
@ -2893,7 +2888,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
if (mat->rows() != mat->columns()) { if (mat->rows() != mat->columns()) {
out << "x" << mat->rows(); out << "x" << mat->rows();
} }
} else if (type->Is<type::Pointer>()) { } else if (TINT_UNLIKELY(type->Is<type::Pointer>())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "Attempting to emit pointer type. These should have been removed " << "Attempting to emit pointer type. These should have been removed "
"with the InlinePointerLets transform"; "with the InlinePointerLets transform";
@ -2903,7 +2898,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
} else if (auto* str = type->As<sem::Struct>()) { } else if (auto* str = type->As<sem::Struct>()) {
out << StructName(str); out << StructName(str);
} else if (auto* tex = type->As<type::Texture>()) { } else if (auto* tex = type->As<type::Texture>()) {
if (tex->Is<type::ExternalTexture>()) { if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
TINT_ICE(Writer, diagnostics_) << "Multiplanar external texture transform was not run."; TINT_ICE(Writer, diagnostics_) << "Multiplanar external texture transform was not run.";
return false; return false;
} }
@ -2925,7 +2920,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
if (!subtype || subtype->Is<type::F32>()) { if (!subtype || subtype->Is<type::F32>()) {
} else if (subtype->Is<type::I32>()) { } else if (subtype->Is<type::I32>()) {
out << "i"; out << "i";
} else if (subtype->Is<type::U32>()) { } else if (TINT_LIKELY(subtype->Is<type::U32>())) {
out << "u"; out << "u";
} else { } else {
TINT_ICE(Writer, diagnostics_) << "Unsupported texture type"; TINT_ICE(Writer, diagnostics_) << "Unsupported texture type";

View File

@ -69,6 +69,7 @@
#include "src/tint/type/multisampled_texture.h" #include "src/tint/type/multisampled_texture.h"
#include "src/tint/type/sampled_texture.h" #include "src/tint/type/sampled_texture.h"
#include "src/tint/type/storage_texture.h" #include "src/tint/type/storage_texture.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/utils/scoped_assignment.h" #include "src/tint/utils/scoped_assignment.h"
@ -2289,7 +2290,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
}; };
auto* texture = arg(Usage::kTexture); auto* texture = arg(Usage::kTexture);
if (!texture) { if (TINT_UNLIKELY(!texture)) {
TINT_ICE(Writer, diagnostics_) << "missing texture argument"; TINT_ICE(Writer, diagnostics_) << "missing texture argument";
return false; return false;
} }
@ -2412,7 +2413,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
} }
} }
if (num_dimensions > 4) { if (TINT_UNLIKELY(num_dimensions > 4)) {
TINT_ICE(Writer, diagnostics_) << "Texture query builtin temporary vector has " TINT_ICE(Writer, diagnostics_) << "Texture query builtin temporary vector has "
<< num_dimensions << " dimensions"; << num_dimensions << " dimensions";
return false; return false;
@ -2446,7 +2447,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
pre << dims; pre << dims;
} else { } else {
static constexpr char xyzw[] = {'x', 'y', 'z', 'w'}; static constexpr char xyzw[] = {'x', 'y', 'z', 'w'};
if (num_dimensions < 0 || num_dimensions > 4) { if (TINT_UNLIKELY(num_dimensions < 0 || num_dimensions > 4)) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "vector dimensions are " << num_dimensions; << "vector dimensions are " << num_dimensions;
return false; return false;
@ -2553,7 +2554,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
} }
auto* param_coords = arg(Usage::kCoords); auto* param_coords = arg(Usage::kCoords);
if (!param_coords) { if (TINT_UNLIKELY(!param_coords)) {
TINT_ICE(Writer, diagnostics_) << "missing coords argument"; TINT_ICE(Writer, diagnostics_) << "missing coords argument";
return false; return false;
} }
@ -2636,7 +2637,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
out << "xyz"[i]; out << "xyz"[i];
} }
} }
if (wgsl_ret_width > hlsl_ret_width) { if (TINT_UNLIKELY(wgsl_ret_width > hlsl_ret_width)) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "WGSL return width (" << wgsl_ret_width << ") is wider than HLSL return width (" << "WGSL return width (" << wgsl_ret_width << ") is wider than HLSL return width ("
<< hlsl_ret_width << ") for " << builtin->Type(); << hlsl_ret_width << ") for " << builtin->Type();
@ -3241,7 +3242,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
for (auto* var : func->params) { for (auto* var : func->params) {
auto* sem = builder_.Sem().Get(var); auto* sem = builder_.Sem().Get(var);
auto* type = sem->Type(); auto* type = sem->Type();
if (!type->Is<sem::Struct>()) { if (TINT_UNLIKELY(!type->Is<sem::Struct>())) {
// ICE likely indicates that the CanonicalizeEntryPointIO transform was // ICE likely indicates that the CanonicalizeEntryPointIO transform was
// not run, or a builtin parameter was added after it was run. // not run, or a builtin parameter was added after it was run.
TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter"; TINT_ICE(Writer, diagnostics_) << "Unsupported non-struct entry point parameter";
@ -3944,7 +3945,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
const type::Type* base_type = ary; const type::Type* base_type = ary;
std::vector<uint32_t> sizes; std::vector<uint32_t> sizes;
while (auto* arr = base_type->As<type::Array>()) { while (auto* arr = base_type->As<type::Array>()) {
if (arr->Count()->Is<type::RuntimeArrayCount>()) { if (TINT_UNLIKELY(arr->Count()->Is<type::RuntimeArrayCount>())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "runtime arrays may only exist in storage buffers, which should have " << "runtime arrays may only exist in storage buffers, which should have "
"been transformed into a ByteAddressBuffer"; "been transformed into a ByteAddressBuffer";
@ -4032,7 +4033,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return true; return true;
}, },
[&](const type::Texture* tex) { [&](const type::Texture* tex) {
if (tex->Is<type::ExternalTexture>()) { if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "Multiplanar external texture transform was not run."; << "Multiplanar external texture transform was not run.";
return false; return false;
@ -4075,7 +4076,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
if (storage) { if (storage) {
auto* component = image_format_to_rwtexture_type(storage->texel_format()); auto* component = image_format_to_rwtexture_type(storage->texel_format());
if (component == nullptr) { if (TINT_UNLIKELY(!component)) {
TINT_ICE(Writer, diagnostics_) << "Unsupported StorageTexture TexelFormat: " TINT_ICE(Writer, diagnostics_) << "Unsupported StorageTexture TexelFormat: "
<< static_cast<int>(storage->texel_format()); << static_cast<int>(storage->texel_format());
return false; return false;
@ -4090,7 +4091,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
out << "float4"; out << "float4";
} else if (subtype->Is<type::I32>()) { } else if (subtype->Is<type::I32>()) {
out << "int4"; out << "int4";
} else if (subtype->Is<type::U32>()) { } else if (TINT_LIKELY(subtype->Is<type::U32>())) {
out << "uint4"; out << "uint4";
} else { } else {
TINT_ICE(Writer, diagnostics_) << "Unsupported multisampled texture type"; TINT_ICE(Writer, diagnostics_) << "Unsupported multisampled texture type";
@ -4170,7 +4171,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
for (auto* attr : decl->attributes) { for (auto* attr : decl->attributes) {
if (attr->Is<ast::LocationAttribute>()) { if (attr->Is<ast::LocationAttribute>()) {
auto& pipeline_stage_uses = str->PipelineStageUses(); auto& pipeline_stage_uses = str->PipelineStageUses();
if (pipeline_stage_uses.size() != 1) { if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses"; TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
} }
@ -4183,8 +4184,8 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
} else if (pipeline_stage_uses.count( } else if (pipeline_stage_uses.count(
type::PipelineStageUsage::kFragmentInput)) { type::PipelineStageUsage::kFragmentInput)) {
post += " : TEXCOORD" + std::to_string(loc); post += " : TEXCOORD" + std::to_string(loc);
} else if (pipeline_stage_uses.count( } else if (TINT_LIKELY(pipeline_stage_uses.count(
type::PipelineStageUsage::kFragmentOutput)) { type::PipelineStageUsage::kFragmentOutput))) {
post += " : SV_Target" + std::to_string(loc); post += " : SV_Target" + std::to_string(loc);
} else { } else {
TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute"; TINT_ICE(Writer, diagnostics_) << "invalid use of location attribute";
@ -4211,9 +4212,9 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
// stricter and therefore provides the necessary guarantees. // stricter and therefore provides the necessary guarantees.
// See discussion here: https://github.com/gpuweb/gpuweb/issues/893 // See discussion here: https://github.com/gpuweb/gpuweb/issues/893
pre += "precise "; pre += "precise ";
} else if (!attr->IsAnyOf<ast::StructMemberAlignAttribute, } else if (TINT_UNLIKELY((!attr->IsAnyOf<ast::StructMemberAlignAttribute,
ast::StructMemberOffsetAttribute, ast::StructMemberOffsetAttribute,
ast::StructMemberSizeAttribute>()) { ast::StructMemberSizeAttribute>()))) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "unhandled struct member attribute: " << attr->Name(); << "unhandled struct member attribute: " << attr->Name();
return false; return false;

View File

@ -993,7 +993,7 @@ bool GeneratorImpl::EmitTextureCall(std::ostream& out,
}; };
auto* texture = arg(Usage::kTexture)->Declaration(); auto* texture = arg(Usage::kTexture)->Declaration();
if (!texture) { if (TINT_UNLIKELY(!texture)) {
TINT_ICE(Writer, diagnostics_) << "missing texture arg"; TINT_ICE(Writer, diagnostics_) << "missing texture arg";
return false; return false;
} }
@ -1976,14 +1976,14 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
// attribute have a value of zero. // attribute have a value of zero.
const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max(); const uint32_t kInvalidBindingIndex = std::numeric_limits<uint32_t>::max();
auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t { auto get_binding_index = [&](const ast::Parameter* param) -> uint32_t {
if (!param->HasBindingPoint()) { if (TINT_UNLIKELY(!param->HasBindingPoint())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "missing binding attributes for entry point parameter"; << "missing binding attributes for entry point parameter";
return kInvalidBindingIndex; return kInvalidBindingIndex;
} }
auto* param_sem = program_->Sem().Get<sem::Parameter>(param); auto* param_sem = program_->Sem().Get<sem::Parameter>(param);
auto bp = param_sem->BindingPoint(); auto bp = param_sem->BindingPoint();
if (bp.group != 0) { if (TINT_UNLIKELY(bp.group != 0)) {
TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use " TINT_ICE(Writer, diagnostics_) << "encountered non-zero resource group index (use "
"BindingRemapper to fix)"; "BindingRemapper to fix)";
return kInvalidBindingIndex; return kInvalidBindingIndex;
@ -2026,7 +2026,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
} }
if (param->type->Is<ast::Sampler>()) { if (param->type->Is<ast::Sampler>()) {
out << " [[sampler(" << binding << ")]]"; out << " [[sampler(" << binding << ")]]";
} else if (param->type->Is<ast::Texture>()) { } else if (TINT_LIKELY(param->type->Is<ast::Texture>())) {
out << " [[texture(" << binding << ")]]"; out << " [[texture(" << binding << ")]]";
} else { } else {
TINT_ICE(Writer, diagnostics_) << "invalid handle type entry point parameter"; TINT_ICE(Writer, diagnostics_) << "invalid handle type entry point parameter";
@ -2038,7 +2038,8 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
auto& allocations = workgroup_allocations_[func_name]; auto& allocations = workgroup_allocations_[func_name];
out << " [[threadgroup(" << allocations.size() << ")]]"; out << " [[threadgroup(" << allocations.size() << ")]]";
allocations.push_back(program_->Sem().Get(ptr->type)->Size()); allocations.push_back(program_->Sem().Get(ptr->type)->Size());
} else if (sc == ast::AddressSpace::kStorage || sc == ast::AddressSpace::kUniform) { } else if (TINT_LIKELY(sc == ast::AddressSpace::kStorage ||
sc == ast::AddressSpace::kUniform)) {
uint32_t binding = get_binding_index(param); uint32_t binding = get_binding_index(param);
if (binding == kInvalidBindingIndex) { if (binding == kInvalidBindingIndex) {
return false; return false;
@ -2067,7 +2068,7 @@ bool GeneratorImpl::EmitEntryPointFunction(const ast::Function* func) {
} }
out << " [[" << name << "]]"; out << " [[" << name << "]]";
} }
if (!builtin_found) { if (TINT_UNLIKELY(!builtin_found)) {
TINT_ICE(Writer, diagnostics_) << "Unsupported entry point parameter"; TINT_ICE(Writer, diagnostics_) << "Unsupported entry point parameter";
} }
} }
@ -2530,7 +2531,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
out << "atomic_int"; out << "atomic_int";
return true; return true;
} }
if (atomic->Type()->Is<type::U32>()) { if (TINT_LIKELY(atomic->Type()->Is<type::U32>())) {
out << "atomic_uint"; out << "atomic_uint";
return true; return true;
} }
@ -2610,7 +2611,7 @@ bool GeneratorImpl::EmitType(std::ostream& out,
return true; return true;
}, },
[&](const type::Texture* tex) { [&](const type::Texture* tex) {
if (tex->Is<type::ExternalTexture>()) { if (TINT_UNLIKELY(tex->Is<type::ExternalTexture>())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "Multiplanar external texture transform was not run."; << "Multiplanar external texture transform was not run.";
return false; return false;
@ -2793,7 +2794,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
auto wgsl_offset = mem->Offset(); auto wgsl_offset = mem->Offset();
if (is_host_shareable) { if (is_host_shareable) {
if (wgsl_offset < msl_offset) { if (TINT_UNLIKELY(wgsl_offset < msl_offset)) {
// Unimplementable layout // Unimplementable layout
TINT_ICE(Writer, diagnostics_) << "Structure member WGSL offset (" << wgsl_offset TINT_ICE(Writer, diagnostics_) << "Structure member WGSL offset (" << wgsl_offset
<< ") is behind MSL offset (" << msl_offset << ")"; << ") is behind MSL offset (" << msl_offset << ")";
@ -2837,7 +2838,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
}, },
[&](const ast::LocationAttribute*) { [&](const ast::LocationAttribute*) {
auto& pipeline_stage_uses = str->PipelineStageUses(); auto& pipeline_stage_uses = str->PipelineStageUses();
if (pipeline_stage_uses.size() != 1) { if (TINT_UNLIKELY(pipeline_stage_uses.size() != 1)) {
TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses"; TINT_ICE(Writer, diagnostics_) << "invalid entry point IO struct uses";
return false; return false;
} }
@ -2851,8 +2852,8 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
} else if (pipeline_stage_uses.count( } else if (pipeline_stage_uses.count(
type::PipelineStageUsage::kFragmentInput)) { type::PipelineStageUsage::kFragmentInput)) {
out << " [[user(locn" + std::to_string(loc) + ")]]"; out << " [[user(locn" + std::to_string(loc) + ")]]";
} else if (pipeline_stage_uses.count( } else if (TINT_LIKELY(pipeline_stage_uses.count(
type::PipelineStageUsage::kFragmentOutput)) { type::PipelineStageUsage::kFragmentOutput))) {
out << " [[color(" + std::to_string(loc) + ")]]"; out << " [[color(" + std::to_string(loc) + ")]]";
} else { } else {
TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration"; TINT_ICE(Writer, diagnostics_) << "invalid use of location decoration";
@ -2898,7 +2899,7 @@ bool GeneratorImpl::EmitStructType(TextBuffer* b, const sem::Struct* str) {
if (is_host_shareable) { if (is_host_shareable) {
// Calculate new MSL offset // Calculate new MSL offset
auto size_align = MslPackedTypeSizeAndAlign(ty); auto size_align = MslPackedTypeSizeAndAlign(ty);
if (msl_offset % size_align.align) { if (TINT_UNLIKELY(msl_offset % size_align.align)) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "Misaligned MSL structure member " << ty->FriendlyName(program_->Symbols()) << "Misaligned MSL structure member " << ty->FriendlyName(program_->Symbols())
<< " " << mem_name; << " " << mem_name;
@ -3167,7 +3168,7 @@ GeneratorImpl::SizeAndAlign GeneratorImpl::MslPackedTypeSizeAndAlign(const type:
}, },
[&](const type::Array* arr) { [&](const type::Array* arr) {
if (!arr->IsStrideImplicit()) { if (TINT_UNLIKELY(!arr->IsStrideImplicit())) {
TINT_ICE(Writer, diagnostics_) TINT_ICE(Writer, diagnostics_)
<< "arrays with explicit strides should not exist past the SPIR-V reader"; << "arrays with explicit strides should not exist past the SPIR-V reader";
return SizeAndAlign{}; return SizeAndAlign{};

View File

@ -45,6 +45,7 @@
#include "src/tint/type/reference.h" #include "src/tint/type/reference.h"
#include "src/tint/type/sampled_texture.h" #include "src/tint/type/sampled_texture.h"
#include "src/tint/type/vector.h" #include "src/tint/type/vector.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/defer.h" #include "src/tint/utils/defer.h"
#include "src/tint/utils/map.h" #include "src/tint/utils/map.h"
#include "src/tint/writer/append_vector.h" #include "src/tint/writer/append_vector.h"
@ -756,7 +757,7 @@ bool Builder::GenerateGlobalVariable(const ast::Variable* v) {
} }
auto* sem = builder_.Sem().Get<sem::GlobalVariable>(v); auto* sem = builder_.Sem().Get<sem::GlobalVariable>(v);
if (!sem) { if (TINT_UNLIKELY(!sem)) {
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
<< "attempted to generate a global from a non-global variable"; << "attempted to generate a global from a non-global variable";
return false; return false;
@ -927,7 +928,7 @@ bool Builder::GenerateIndexAccessor(const ast::IndexAccessorExpression* expr, Ac
} }
// If the source is a vector, we use OpVectorExtractDynamic. // If the source is a vector, we use OpVectorExtractDynamic.
if (info->source_type->Is<type::Vector>()) { if (TINT_LIKELY(info->source_type->Is<type::Vector>())) {
if (!push_function_inst( if (!push_function_inst(
spv::Op::OpVectorExtractDynamic, spv::Op::OpVectorExtractDynamic,
{Operand(result_type_id), extract, Operand(info->source_id), Operand(idx_id)})) { {Operand(result_type_id), extract, Operand(info->source_id), Operand(idx_id)})) {
@ -949,125 +950,128 @@ bool Builder::GenerateMemberAccessor(const ast::MemberAccessorExpression* expr,
auto* expr_sem = builder_.Sem().Get(expr)->UnwrapLoad(); auto* expr_sem = builder_.Sem().Get(expr)->UnwrapLoad();
auto* expr_type = expr_sem->Type(); auto* expr_type = expr_sem->Type();
if (auto* access = expr_sem->As<sem::StructMemberAccess>()) { return Switch(
uint32_t idx = access->Member()->Index(); expr_sem, //
[&](const sem::StructMemberAccess* access) {
uint32_t idx = access->Member()->Index();
if (info->source_type->Is<type::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
if (idx_id == 0) {
return 0;
}
info->access_chain_indices.push_back(idx_id);
info->source_type = expr_type;
} else {
auto result_type_id = GenerateTypeIfNeeded(expr_type);
if (result_type_id == 0) {
return false;
}
auto extract = result_op();
auto extract_id = std::get<uint32_t>(extract);
if (!push_function_inst(
spv::Op::OpCompositeExtract,
{Operand(result_type_id), extract, Operand(info->source_id), Operand(idx)})) {
return false;
}
info->source_id = extract_id;
info->source_type = expr_type;
}
return true;
}
if (auto* swizzle = expr_sem->As<sem::Swizzle>()) {
// Single element swizzle is either an access chain or a composite extract
auto& indices = swizzle->Indices();
if (indices.Length() == 1) {
if (info->source_type->Is<type::Reference>()) { if (info->source_type->Is<type::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0])); auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(idx));
if (idx_id == 0) { if (TINT_UNLIKELY(idx_id == 0)) {
return 0; return false;
} }
info->access_chain_indices.push_back(idx_id); info->access_chain_indices.push_back(idx_id);
info->source_type = expr_type;
} else { } else {
auto result_type_id = GenerateTypeIfNeeded(expr_type); auto result_type_id = GenerateTypeIfNeeded(expr_type);
if (result_type_id == 0) { if (TINT_UNLIKELY(result_type_id == 0)) {
return 0; return false;
} }
auto extract = result_op(); auto extract = result_op();
auto extract_id = std::get<uint32_t>(extract); auto extract_id = std::get<uint32_t>(extract);
if (!push_function_inst(spv::Op::OpCompositeExtract, if (!push_function_inst(spv::Op::OpCompositeExtract,
{Operand(result_type_id), extract, Operand(info->source_id), {Operand(result_type_id), extract, Operand(info->source_id),
Operand(indices[0])})) { Operand(idx)})) {
return false; return false;
} }
info->source_id = extract_id; info->source_id = extract_id;
info->source_type = expr_type; info->source_type = expr_type;
} }
return true; return true;
} },
[&](const sem::Swizzle* swizzle) {
// Single element swizzle is either an access chain or a composite extract
auto& indices = swizzle->Indices();
if (indices.Length() == 1) {
if (info->source_type->Is<type::Reference>()) {
auto idx_id = GenerateConstantIfNeeded(ScalarConstant::U32(indices[0]));
if (TINT_UNLIKELY(idx_id == 0)) {
return false;
}
info->access_chain_indices.push_back(idx_id);
} else {
auto result_type_id = GenerateTypeIfNeeded(expr_type);
if (TINT_UNLIKELY(result_type_id == 0)) {
return false;
}
// Store the type away as it may change if we run the access chain auto extract = result_op();
auto* incoming_type = info->source_type; auto extract_id = std::get<uint32_t>(extract);
if (!push_function_inst(spv::Op::OpCompositeExtract,
{Operand(result_type_id), extract,
Operand(info->source_id), Operand(indices[0])})) {
return false;
}
// Multi-item extract is a VectorShuffle. We have to emit any existing info->source_id = extract_id;
// access chain data, then load the access chain and shuffle that. info->source_type = expr_type;
if (!info->access_chain_indices.empty()) { }
auto result_type_id = GenerateTypeIfNeeded(info->source_type); return true;
if (result_type_id == 0) {
return 0;
}
auto extract = result_op();
auto extract_id = std::get<uint32_t>(extract);
OperandList ops = {Operand(result_type_id), extract, Operand(info->source_id)};
for (auto id : info->access_chain_indices) {
ops.push_back(Operand(id));
} }
if (!push_function_inst(spv::Op::OpAccessChain, ops)) { // Store the type away as it may change if we run the access chain
auto* incoming_type = info->source_type;
// Multi-item extract is a VectorShuffle. We have to emit any existing
// access chain data, then load the access chain and shuffle that.
if (!info->access_chain_indices.empty()) {
auto result_type_id = GenerateTypeIfNeeded(info->source_type);
if (TINT_UNLIKELY(result_type_id == 0)) {
return false;
}
auto extract = result_op();
auto extract_id = std::get<uint32_t>(extract);
OperandList ops = {Operand(result_type_id), extract, Operand(info->source_id)};
for (auto id : info->access_chain_indices) {
ops.push_back(Operand(id));
}
if (!push_function_inst(spv::Op::OpAccessChain, ops)) {
return false;
}
info->source_id = GenerateLoadIfNeeded(expr_type, extract_id);
info->source_type = expr_type->UnwrapRef();
info->access_chain_indices.clear();
}
auto result_type_id = GenerateTypeIfNeeded(expr_type);
if (TINT_UNLIKELY(result_type_id == 0)) {
return false; return false;
} }
info->source_id = GenerateLoadIfNeeded(expr_type, extract_id); auto vec_id = GenerateLoadIfNeeded(incoming_type, info->source_id);
info->source_type = expr_type->UnwrapRef();
info->access_chain_indices.clear();
}
auto result_type_id = GenerateTypeIfNeeded(expr_type); auto result = result_op();
if (result_type_id == 0) { auto result_id = std::get<uint32_t>(result);
OperandList ops = {Operand(result_type_id), result, Operand(vec_id), Operand(vec_id)};
for (auto idx : indices) {
ops.push_back(Operand(idx));
}
if (!push_function_inst(spv::Op::OpVectorShuffle, ops)) {
return false;
}
info->source_id = result_id;
info->source_type = expr_type;
return true;
},
[&](Default) {
TINT_ICE(Writer, builder_.Diagnostics())
<< "unhandled member index type: " << expr_sem->TypeInfo().name;
return false; return false;
} });
auto vec_id = GenerateLoadIfNeeded(incoming_type, info->source_id);
auto result = result_op();
auto result_id = std::get<uint32_t>(result);
OperandList ops = {Operand(result_type_id), result, Operand(vec_id), Operand(vec_id)};
for (auto idx : indices) {
ops.push_back(Operand(idx));
}
if (!push_function_inst(spv::Op::OpVectorShuffle, ops)) {
return false;
}
info->source_id = result_id;
info->source_type = expr_type;
return true;
}
TINT_ICE(Writer, builder_.Diagnostics())
<< "unhandled member index type: " << expr_sem->TypeInfo().name;
return false;
} }
uint32_t Builder::GenerateAccessorExpression(const ast::Expression* expr) { uint32_t Builder::GenerateAccessorExpression(const ast::Expression* expr) {
if (!expr->IsAnyOf<ast::IndexAccessorExpression, ast::MemberAccessorExpression>()) { if (TINT_UNLIKELY(
(!expr->IsAnyOf<ast::IndexAccessorExpression, ast::MemberAccessorExpression>()))) {
TINT_ICE(Writer, builder_.Diagnostics()) << "expression is not an accessor"; TINT_ICE(Writer, builder_.Diagnostics()) << "expression is not an accessor";
return 0; return 0;
} }
@ -1448,7 +1452,7 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const type::Type* to_type,
bool is_global_init) { bool is_global_init) {
// This should not happen as we rely on constant folding to obviate // This should not happen as we rely on constant folding to obviate
// casts/conversions for module-scope variables // casts/conversions for module-scope variables
if (is_global_init) { if (TINT_UNLIKELY(is_global_init)) {
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
<< "Module-level conversions are not supported. Conversions should " << "Module-level conversions are not supported. Conversions should "
"have already been constant-folded by the FoldConstants transform."; "have already been constant-folded by the FoldConstants transform.";
@ -1565,13 +1569,13 @@ uint32_t Builder::GenerateCastOrCopyOrPassthrough(const type::Type* to_type,
} }
return result_id; return result_id;
} else if (from_type->Is<type::Matrix>() && to_type->Is<type::Matrix>()) { } else if (TINT_LIKELY(from_type->Is<type::Matrix>() && to_type->Is<type::Matrix>())) {
// SPIRV does not support matrix conversion, the only valid case is matrix identity // SPIRV does not support matrix conversion, the only valid case is matrix identity
// initializer. Matrix conversion between f32 and f16 should be transformed into vector // initializer. Matrix conversion between f32 and f16 should be transformed into vector
// conversions for each column vectors by VectorizeMatrixConversions. // conversions for each column vectors by VectorizeMatrixConversions.
auto* from_mat = from_type->As<type::Matrix>(); auto* from_mat = from_type->As<type::Matrix>();
auto* to_mat = to_type->As<type::Matrix>(); auto* to_mat = to_type->As<type::Matrix>();
if (from_mat == to_mat) { if (TINT_LIKELY(from_mat == to_mat)) {
return val_id; return val_id;
} }
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
@ -2631,7 +2635,7 @@ bool Builder::GenerateTextureBuiltin(const sem::Call* call,
// Generates the argument with the given usage, returning the operand ID // Generates the argument with the given usage, returning the operand ID
auto gen_arg = [&](Usage usage) { auto gen_arg = [&](Usage usage) {
auto* argument = arg(usage); auto* argument = arg(usage);
if (!argument) { if (TINT_UNLIKELY(!argument)) {
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
<< "missing argument " << static_cast<int>(usage); << "missing argument " << static_cast<int>(usage);
} }
@ -2639,7 +2643,7 @@ bool Builder::GenerateTextureBuiltin(const sem::Call* call,
}; };
auto* texture = arg(Usage::kTexture); auto* texture = arg(Usage::kTexture);
if (!texture) { if (TINT_UNLIKELY(!texture)) {
TINT_ICE(Writer, builder_.Diagnostics()) << "missing texture argument"; TINT_ICE(Writer, builder_.Diagnostics()) << "missing texture argument";
} }
@ -3752,7 +3756,7 @@ uint32_t Builder::GenerateTypeIfNeeded(const type::Type* type) {
} }
bool Builder::GenerateTextureType(const type::Texture* texture, const Operand& result) { bool Builder::GenerateTextureType(const type::Texture* texture, const Operand& result) {
if (texture->Is<type::ExternalTexture>()) { if (TINT_UNLIKELY(texture->Is<type::ExternalTexture>())) {
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
<< "Multiplanar external texture transform was not run."; << "Multiplanar external texture transform was not run.";
return false; return false;
@ -4008,7 +4012,7 @@ SpvBuiltIn Builder::ConvertBuiltin(ast::BuiltinValue builtin, ast::AddressSpace
case ast::BuiltinValue::kPosition: case ast::BuiltinValue::kPosition:
if (storage == ast::AddressSpace::kIn) { if (storage == ast::AddressSpace::kIn) {
return SpvBuiltInFragCoord; return SpvBuiltInFragCoord;
} else if (storage == ast::AddressSpace::kOut) { } else if (TINT_LIKELY(storage == ast::AddressSpace::kOut)) {
return SpvBuiltInPosition; return SpvBuiltInPosition;
} else { } else {
TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for builtin"; TINT_ICE(Writer, builder_.Diagnostics()) << "invalid address space for builtin";

View File

@ -194,7 +194,7 @@ class Builder {
/// Pushes a variable to the current function /// Pushes a variable to the current function
/// @param operands the variable operands /// @param operands the variable operands
void push_function_var(const OperandList& operands) { void push_function_var(const OperandList& operands) {
if (functions_.empty()) { if (TINT_UNLIKELY(functions_.empty())) {
TINT_ICE(Writer, builder_.Diagnostics()) TINT_ICE(Writer, builder_.Diagnostics())
<< "push_function_var() called without a function"; << "push_function_var() called without a function";
} }

View File

@ -77,7 +77,7 @@ void TextGenerator::TextBuffer::Append(const std::string& line) {
} }
void TextGenerator::TextBuffer::Insert(const std::string& line, size_t before, uint32_t indent) { void TextGenerator::TextBuffer::Insert(const std::string& line, size_t before, uint32_t indent) {
if (before >= lines.size()) { if (TINT_UNLIKELY(before >= lines.size())) {
diag::List d; diag::List d;
TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n" TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
<< " before:" << before << "\n" << " before:" << before << "\n"
@ -96,7 +96,7 @@ void TextGenerator::TextBuffer::Append(const TextBuffer& tb) {
} }
void TextGenerator::TextBuffer::Insert(const TextBuffer& tb, size_t before, uint32_t indent) { void TextGenerator::TextBuffer::Insert(const TextBuffer& tb, size_t before, uint32_t indent) {
if (before >= lines.size()) { if (TINT_UNLIKELY(before >= lines.size())) {
diag::List d; diag::List d;
TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n" TINT_ICE(Writer, d) << "TextBuffer::Insert() called with before >= lines.size()\n"
<< " before:" << before << "\n" << " before:" << before << "\n"

View File

@ -224,7 +224,7 @@ bool GeneratorImpl::EmitCall(std::ostream& out, const ast::CallExpression* expr)
if (!EmitExpression(out, expr->target.name)) { if (!EmitExpression(out, expr->target.name)) {
return false; return false;
} }
} else if (expr->target.type) { } else if (TINT_LIKELY(expr->target.type)) {
if (!EmitType(out, expr->target.type)) { if (!EmitType(out, expr->target.type)) {
return false; return false;
} }