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

@@ -218,7 +218,7 @@ struct ArrayLengthFromUniform::State {
// arrayLength(&struct_var.array_member)
// arrayLength(&array_var)
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())
<< "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member";
@@ -229,7 +229,7 @@ struct ArrayLengthFromUniform::State {
storage_buffer_expr = accessor->structure;
}
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())
<< "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member";
@@ -238,7 +238,7 @@ struct ArrayLengthFromUniform::State {
// Get the index to use for the buffer size array.
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";
break;
}

View File

@@ -480,7 +480,7 @@ struct BuiltinPolyfill::State {
uint32_t width = WidthOf(ty);
// 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())
<< "insertBits polyfill only support i32, u32, and vector of i32 or u32, got "
<< b.FriendlyName(ty);

View File

@@ -152,7 +152,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
// arrayLength(&array_var)
auto* arg = call_expr->args[0];
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())
<< "arrayLength() expected address-of, got " << arg->TypeInfo().name;
}
@@ -161,7 +161,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
storage_buffer_expr = accessor->structure;
}
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())
<< "expected form of arrayLength argument to be &array_var or "
"&struct_var.array_member";
@@ -213,7 +213,7 @@ Transform::ApplyResult CalculateArrayLength::Apply(const Program* src,
},
[&](const type::Array* arr) { return arr; });
if (!array_type) {
if (TINT_UNLIKELY(!array_type)) {
TINT_ICE(Transform, b.Diagnostics())
<< "expected form of arrayLength argument to be "
"&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.
utils::Vector<const ast::Expression*, 8> inner_struct_values;
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";
continue;
}
@@ -383,7 +383,7 @@ struct CanonicalizeEntryPointIO::State {
bool do_interpolate = func_ast->PipelineStage() != ast::PipelineStage::kFragment;
if (auto* str = inner_ret_type->As<sem::Struct>()) {
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";
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.
for (auto* global : src->AST().GlobalVariables()) {
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())
<< "ClampFragDepth doesn't know how to handle module that already use push "
"constants.";

View File

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

View File

@@ -1097,7 +1097,8 @@ struct DirectVariableAccess::State {
continue;
}
if (auto* member = std::get_if<Symbol>(&op)) {
auto* member = std::get_if<Symbol>(&op);
if (TINT_LIKELY(member)) {
ss << sym.NameFor(*member);
continue;
}
@@ -1145,7 +1146,8 @@ struct DirectVariableAccess::State {
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.
return b.MemberAccessor(expr, ctx.Clone(*member));
}

View File

@@ -187,24 +187,27 @@ struct LocalizeStructArrayAssignment::State {
std::pair<const type::Type*, ast::AddressSpace> GetOriginatingTypeAndAddressSpace(
const ast::AssignmentStatement* assign_stmt) {
auto* root_ident = src->Sem().Get(assign_stmt->lhs)->RootIdentifier();
if (!root_ident) {
if (TINT_UNLIKELY(!root_ident)) {
TINT_ICE(Transform, b.Diagnostics())
<< "Unable to determine originating variable for lhs of assignment "
"statement";
return {};
}
auto* type = root_ident->Type();
if (auto* ref = type->As<type::Reference>()) {
return {ref->StoreType(), ref->AddressSpace()};
} else if (auto* ptr = type->As<type::Pointer>()) {
return {ptr->StoreType(), ptr->AddressSpace()};
}
TINT_ICE(Transform, b.Diagnostics())
<< "Expecting to find variable of type pointer or reference on lhs "
"of assignment statement";
return {};
return Switch(
root_ident->Type(), //
[&](const type::Reference* ref) {
return std::make_pair(ref->StoreType(), ref->AddressSpace());
},
[&](const type::Pointer* ptr) {
return std::make_pair(ptr->StoreType(), ptr->AddressSpace());
},
[&](Default) {
TINT_ICE(Transform, b.Diagnostics())
<< "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) {
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())
<< "expected textureSampleBaseClampToEdge call with a "
"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
/// @returns a call expression to textureLoadExternal
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())
<< "expected textureLoad call with a texture_external to have 2 arguments, found "
<< call->Arguments().Length() << " arguments";

View File

@@ -25,6 +25,7 @@
#include "src/tint/sem/module.h"
#include "src/tint/sem/struct.h"
#include "src/tint/sem/variable.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/hashmap.h"
#include "src/tint/utils/transform.h"
@@ -433,7 +434,7 @@ struct Std140::State {
attrs.Push(b.create<ast::StrideAttribute>(arr->Stride()));
}
auto count = arr->ConstantCount();
if (!count) {
if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles types transitively used as uniform buffers.
@@ -518,7 +519,7 @@ struct Std140::State {
access.indices.Push(UniformVariable{});
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,
// this must be a pointer-let. Continue traversing from the let
// initializer.
@@ -633,7 +634,7 @@ struct Std140::State {
[&](const sem::Struct* str) { return sym.NameFor(str->Name()); },
[&](const type::Array* arr) {
auto count = arr->ConstantCount();
if (!count) {
if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and
// this method only handles types transitively used as uniform buffers.
@@ -717,7 +718,8 @@ struct Std140::State {
}, //
[&](const type::Matrix* mat) {
// 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;
// std140 decomposed matrix. Reassemble.
auto* mat_ty = CreateASTTypeFor(ctx, mat);
@@ -739,7 +741,7 @@ struct Std140::State {
auto* dst_el = b.IndexAccessor(var, i);
auto* src_el = Convert(arr->ElemType(), b.IndexAccessor(param, i));
auto count = arr->ConstantCount();
if (!count) {
if (TINT_UNLIKELY(!count)) {
// Non-constant counts should not be possible:
// * Override-expression counts can only be applied to workgroup arrays, and
// 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);
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));
return;
}
@@ -130,11 +130,12 @@ const ast::Type* Transform::CreateASTTypeFor(CloneContext& ctx, const type::Type
auto* count = ctx.Clone(override->expr->Declaration());
return ctx.dst->ty.array(el, count, std::move(attrs));
}
if (auto count = a->ConstantCount()) {
return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
auto count = a->ConstantCount();
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(1), std::move(attrs));
return ctx.dst->ty.array(el, u32(count.value()), std::move(attrs));
}
if (auto* s = ty->As<sem::Struct>()) {
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* str = func_sem->ReturnType()->As<sem::Struct>();
if (!str) {
if (TINT_UNLIKELY(!str)) {
TINT_ICE(Transform, ctx.dst->Diagnostics())
<< "Entrypoint function return type is non-struct.\n"
<< "TruncateInterstageVariables transform needs to run after "

View File

@@ -336,7 +336,8 @@ struct HoistToDeclBefore::State {
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.
// These require special care.
if (fl->Declaration()->initializer == ip) {
@@ -349,7 +350,7 @@ struct HoistToDeclBefore::State {
return true;
}
if (fl->Declaration()->continuing == ip) {
if (TINT_LIKELY(fl->Declaration()->continuing == ip)) {
// Insertion point is a for-loop continuing statement.
// 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.
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())
<< "source and destination matrix has different shape in matrix conversion";
return nullptr;

View File

@@ -128,7 +128,7 @@ Transform::ApplyResult VectorizeScalarMatrixInitializers::Apply(const Program* s
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 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/program_builder.h"
#include "src/tint/sem/variable.h"
#include "src/tint/utils/compiler_macros.h"
#include "src/tint/utils/map.h"
#include "src/tint/utils/math.h"
@@ -766,12 +767,17 @@ struct VertexPulling::State {
auto* sem = src->Sem().Get<sem::Parameter>(param);
info.type = sem->Type();
if (!sem->Location().has_value()) {
if (TINT_UNLIKELY(!sem->Location().has_value())) {
TINT_ICE(Transform, b.Diagnostics()) << "Location missing value";
return;
}
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.
if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
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)); };
}
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());
location_info[sem->Location().value()] = info;
has_locations = true;
} else if (auto* builtin =
ast::GetAttribute<ast::BuiltinAttribute>(member->attributes)) {
} else {
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.
if (builtin->builtin == ast::BuiltinValue::kVertexIndex) {
vertex_index_expr = member_expr;
@@ -826,8 +834,6 @@ struct VertexPulling::State {
instance_index_expr = member_expr;
}
members_to_clone.Push(member);
} else {
TINT_ICE(Transform, b.Diagnostics()) << "Invalid entry point parameter";
}
}