tint: Optimize sem node lookup

Add a 'NodeID' to each ast::Node which is the sequentially allocated
index of the node. Use this in sem::Info to map the AST node to the
semantic node, instead of using a std::unordered_map.

Optimised very hot code by entirely eliminating map lookups, and
dramatically reducing cache misses (lookups are usually sequentually
ordered).

Timings running
'webgpu:shader,execution,expression,call,builtin,atan2:f32:inputSource="const";vectorize="_undef_"'
with dawn/node, using SwiftShader:

    Without change: 3.22647107s
    With change:    3.10578879s

Bug: tint:1613
Change-Id: I22ec48d933b2e5f9da04494bff4e979e6f7b1982
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/96140
Commit-Queue: 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
2022-07-18 20:50:02 +00:00
committed by Dawn LUCI CQ
parent 8d73198aca
commit 4a92a3c904
192 changed files with 608 additions and 289 deletions

View File

@@ -70,7 +70,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
// This is a non-struct or a struct that is nested somewhere else, so we
// need to wrap it first.
auto* wrapper = utils::GetOrCreate(wrapper_structs, ty, [&]() {
auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(
ctx.dst->ID(), ctx.dst->AllocateNodeID());
auto wrapper_name = ctx.src->Symbols().NameFor(var->symbol) + "_block";
auto* ret = ctx.dst->create<ast::Struct>(
ctx.dst->Symbols().New(wrapper_name),
@@ -89,7 +90,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
}
} else {
// Add a block attribute to this struct directly.
auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(ctx.dst->ID());
auto* block = ctx.dst->ASTNodes().Create<SpirvBlockAttribute>(
ctx.dst->ID(), ctx.dst->AllocateNodeID());
ctx.InsertFront(str->Declaration()->attributes, block);
}
}
@@ -97,7 +99,8 @@ void AddSpirvBlockAttribute::Run(CloneContext& ctx, const DataMap&, DataMap&) co
ctx.Clone();
}
AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid) : Base(pid) {}
AddSpirvBlockAttribute::SpirvBlockAttribute::SpirvBlockAttribute(ProgramID pid, ast::NodeID nid)
: Base(pid, nid) {}
AddSpirvBlockAttribute::SpirvBlockAttribute::~SpirvBlockAttribute() = default;
std::string AddSpirvBlockAttribute::SpirvBlockAttribute::InternalName() const {
return "spirv_block";
@@ -105,7 +108,8 @@ std::string AddSpirvBlockAttribute::SpirvBlockAttribute::InternalName() const {
const AddSpirvBlockAttribute::SpirvBlockAttribute*
AddSpirvBlockAttribute::SpirvBlockAttribute::Clone(CloneContext* ctx) const {
return ctx->dst->ASTNodes().Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(ctx->dst->ID());
return ctx->dst->ASTNodes().Create<AddSpirvBlockAttribute::SpirvBlockAttribute>(
ctx->dst->ID(), ctx->dst->AllocateNodeID());
}
} // namespace tint::transform

View File

@@ -35,7 +35,8 @@ class AddSpirvBlockAttribute final : public Castable<AddSpirvBlockAttribute, Tra
public:
/// Constructor
/// @param program_id the identifier of the program that owns this node
explicit SpirvBlockAttribute(ProgramID program_id);
/// @param nid the unique node identifier
SpirvBlockAttribute(ProgramID program_id, ast::NodeID nid);
/// Destructor
~SpirvBlockAttribute() override;

View File

@@ -57,7 +57,8 @@ struct ArrayUsage {
} // namespace
CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid) : Base(pid) {}
CalculateArrayLength::BufferSizeIntrinsic::BufferSizeIntrinsic(ProgramID pid, ast::NodeID nid)
: Base(pid, nid) {}
CalculateArrayLength::BufferSizeIntrinsic::~BufferSizeIntrinsic() = default;
std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
return "intrinsic_buffer_size";
@@ -65,7 +66,8 @@ std::string CalculateArrayLength::BufferSizeIntrinsic::InternalName() const {
const CalculateArrayLength::BufferSizeIntrinsic* CalculateArrayLength::BufferSizeIntrinsic::Clone(
CloneContext* ctx) const {
return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(ctx->dst->ID());
return ctx->dst->ASTNodes().Create<CalculateArrayLength::BufferSizeIntrinsic>(
ctx->dst->ID(), ctx->dst->AllocateNodeID());
}
CalculateArrayLength::CalculateArrayLength() = default;
@@ -109,7 +111,8 @@ void CalculateArrayLength::Run(CloneContext& ctx, const DataMap&, DataMap&) cons
},
ctx.dst->ty.void_(), nullptr,
ast::AttributeList{
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID()),
ctx.dst->ASTNodes().Create<BufferSizeIntrinsic>(ctx.dst->ID(),
ctx.dst->AllocateNodeID()),
},
ast::AttributeList{}));

View File

@@ -40,7 +40,8 @@ class CalculateArrayLength final : public Castable<CalculateArrayLength, Transfo
public:
/// Constructor
/// @param program_id the identifier of the program that owns this node
explicit BufferSizeIntrinsic(ProgramID program_id);
/// @param nid the unique node identifier
BufferSizeIntrinsic(ProgramID program_id, ast::NodeID nid);
/// Destructor
~BufferSizeIntrinsic() override;

View File

@@ -202,7 +202,8 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicLoadFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad, storage_class, type);
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kLoad,
storage_class, type);
}
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
@@ -215,7 +216,8 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicStoreFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
builder->ID(), DecomposeMemoryAccess::Intrinsic::Op::kStore, storage_class, type);
builder->ID(), builder->AllocateNodeID(), DecomposeMemoryAccess::Intrinsic::Op::kStore,
storage_class, type);
}
/// @returns a DecomposeMemoryAccess::Intrinsic attribute that can be applied
@@ -270,7 +272,7 @@ DecomposeMemoryAccess::Intrinsic* IntrinsicAtomicFor(ProgramBuilder* builder,
return nullptr;
}
return builder->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
builder->ID(), op, ast::StorageClass::kStorage, type);
builder->ID(), builder->AllocateNodeID(), op, ast::StorageClass::kStorage, type);
}
/// BufferAccess describes a single storage or uniform buffer access
@@ -681,8 +683,12 @@ struct DecomposeMemoryAccess::State {
}
};
DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid, Op o, ast::StorageClass sc, DataType ty)
: Base(pid), op(o), storage_class(sc), type(ty) {}
DecomposeMemoryAccess::Intrinsic::Intrinsic(ProgramID pid,
ast::NodeID nid,
Op o,
ast::StorageClass sc,
DataType ty)
: Base(pid, nid), op(o), storage_class(sc), type(ty) {}
DecomposeMemoryAccess::Intrinsic::~Intrinsic() = default;
std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
std::stringstream ss;
@@ -771,8 +777,8 @@ std::string DecomposeMemoryAccess::Intrinsic::InternalName() const {
const DecomposeMemoryAccess::Intrinsic* DecomposeMemoryAccess::Intrinsic::Clone(
CloneContext* ctx) const {
return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(ctx->dst->ID(), op,
storage_class, type);
return ctx->dst->ASTNodes().Create<DecomposeMemoryAccess::Intrinsic>(
ctx->dst->ID(), ctx->dst->AllocateNodeID(), op, storage_class, type);
}
bool DecomposeMemoryAccess::Intrinsic::IsAtomic() const {

View File

@@ -72,11 +72,12 @@ class DecomposeMemoryAccess final : public Castable<DecomposeMemoryAccess, Trans
};
/// Constructor
/// @param program_id the identifier of the program that owns this node
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param o the op of the intrinsic
/// @param sc the storage class of the buffer
/// @param ty the data type of the intrinsic
Intrinsic(ProgramID program_id, Op o, ast::StorageClass sc, DataType ty);
Intrinsic(ProgramID pid, ast::NodeID nid, Op o, ast::StorageClass sc, DataType ty);
/// Destructor
~Intrinsic() override;

View File

@@ -273,14 +273,16 @@ struct SpirvAtomic::State {
SpirvAtomic::SpirvAtomic() = default;
SpirvAtomic::~SpirvAtomic() = default;
SpirvAtomic::Stub::Stub(ProgramID pid, sem::BuiltinType b) : Base(pid), builtin(b) {}
SpirvAtomic::Stub::Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType b)
: Base(pid, nid), builtin(b) {}
SpirvAtomic::Stub::~Stub() = default;
std::string SpirvAtomic::Stub::InternalName() const {
return "@internal(spirv-atomic " + std::string(sem::str(builtin)) + ")";
}
const SpirvAtomic::Stub* SpirvAtomic::Stub::Clone(CloneContext* ctx) const {
return ctx->dst->ASTNodes().Create<SpirvAtomic::Stub>(ctx->dst->ID(), builtin);
return ctx->dst->ASTNodes().Create<SpirvAtomic::Stub>(ctx->dst->ID(),
ctx->dst->AllocateNodeID(), builtin);
}
bool SpirvAtomic::ShouldRun(const Program* program, const DataMap&) const {

View File

@@ -43,9 +43,10 @@ class SpirvAtomic final : public Castable<SpirvAtomic, Transform> {
/// translated to an atomic builtin.
class Stub final : public Castable<Stub, ast::InternalAttribute> {
public:
/// @param program_id the identifier of the program that owns this node
/// @param pid the identifier of the program that owns this node
/// @param nid the unique node identifier
/// @param builtin the atomic builtin this stub represents
Stub(ProgramID program_id, sem::BuiltinType builtin);
Stub(ProgramID pid, ast::NodeID nid, sem::BuiltinType builtin);
/// Destructor
~Stub() override;

View File

@@ -49,14 +49,14 @@ class SpirvAtomicTest : public TransformTest {
b.Param("p1", b.ty.u32()),
},
b.ty.u32(), {b.Return(0_u)},
{b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), a)});
{b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(), a)});
b.Func(std::string{"stub_"} + sem::str(a) + "_i32",
{
b.Param("p0", b.ty.i32()),
b.Param("p1", b.ty.i32()),
},
b.ty.i32(), {b.Return(0_i)},
{b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), a)});
{b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(), a)});
}
b.Func("stub_atomicLoad_u32",
@@ -65,7 +65,8 @@ class SpirvAtomicTest : public TransformTest {
},
b.ty.u32(), {b.Return(0_u)},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), sem::BuiltinType::kAtomicLoad),
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
sem::BuiltinType::kAtomicLoad),
});
b.Func("stub_atomicLoad_i32",
{
@@ -73,7 +74,8 @@ class SpirvAtomicTest : public TransformTest {
},
b.ty.i32(), {b.Return(0_i)},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), sem::BuiltinType::kAtomicLoad),
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
sem::BuiltinType::kAtomicLoad),
});
b.Func("stub_atomicStore_u32",
@@ -83,7 +85,8 @@ class SpirvAtomicTest : public TransformTest {
},
b.ty.void_(), {},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), sem::BuiltinType::kAtomicStore),
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
sem::BuiltinType::kAtomicStore),
});
b.Func("stub_atomicStore_i32",
{
@@ -92,7 +95,8 @@ class SpirvAtomicTest : public TransformTest {
},
b.ty.void_(), {},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), sem::BuiltinType::kAtomicStore),
b.ASTNodes().Create<SpirvAtomic::Stub>(b.ID(), b.AllocateNodeID(),
sem::BuiltinType::kAtomicStore),
});
b.Func("stub_atomic_compare_exchange_weak_u32",
@@ -104,14 +108,14 @@ class SpirvAtomicTest : public TransformTest {
b.ty.u32(), {b.Return(0_u)},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(
b.ID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
});
b.Func("stub_atomic_compare_exchange_weak_i32",
{b.Param("p0", b.ty.i32()), b.Param("p1", b.ty.i32()), b.Param("p2", b.ty.i32())},
b.ty.i32(), {b.Return(0_i)},
{
b.ASTNodes().Create<SpirvAtomic::Stub>(
b.ID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
b.ID(), b.AllocateNodeID(), sem::BuiltinType::kAtomicCompareExchangeWeak),
});
// Keep this pointer alive after Transform() returns