Skip to content

Commit df2fed4

Browse files
jrpriceDawn LUCI CQ
authored andcommitted
[ir] Improve validation speed with many failures
ReserveAdditional() was being used to grow the diagnostics vector by only two slots at a time, which was triggering many copies of the diagnostics vector for modules that have many failures. Instead just let the vector grow naturally (which doubles the size when needed) and manually get the reference to the error diagnostic. Also add an early exit when iterating over instructions and errors have already been found. Fixed: 466695523 Change-Id: I8b862c8550237d29c75fa9d1a1aa150cf4fc86fa Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/280935 Commit-Queue: James Price <jrprice@google.com> Reviewed-by: dan sinclair <dsinclair@chromium.org>
1 parent d15a5db commit df2fed4

File tree

3 files changed

+41
-67
lines changed

3 files changed

+41
-67
lines changed

src/tint/lang/core/ir/validator.cc

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1705,36 +1705,45 @@ void Validator::RunStructuralSoundnessChecks() {
17051705
}
17061706

17071707
diag::Diagnostic& Validator::AddError(const Instruction* inst) {
1708-
diagnostics_.ReserveAdditional(2); // Ensure diagnostics don't resize alive after AddNote()
17091708
auto src = Disassemble().InstructionSource(inst);
17101709
auto& diag = AddError(src) << inst->FriendlyName() << ": ";
17111710

17121711
if (!block_stack_.IsEmpty()) {
17131712
AddNote(block_stack_.Back()) << "in block";
1713+
1714+
// Adding the note may trigger a resize and invalidate the error diagnostic reference, so we
1715+
// need to get a new reference to the error diagnostic here.
1716+
return *(diagnostics_.end() - 2);
17141717
}
17151718
return diag;
17161719
}
17171720

17181721
diag::Diagnostic& Validator::AddError(const Instruction* inst, size_t idx) {
1719-
diagnostics_.ReserveAdditional(2); // Ensure diagnostics don't resize alive after AddNote()
17201722
auto src =
17211723
Disassemble().OperandSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
17221724
auto& diag = AddError(src) << inst->FriendlyName() << ": ";
17231725

17241726
if (!block_stack_.IsEmpty()) {
17251727
AddNote(block_stack_.Back()) << "in block";
1728+
1729+
// Adding the note may trigger a resize and invalidate the error diagnostic reference, so we
1730+
// need to get a new reference to the error diagnostic here.
1731+
return *(diagnostics_.end() - 2);
17261732
}
17271733
return diag;
17281734
}
17291735

17301736
diag::Diagnostic& Validator::AddResultError(const Instruction* inst, size_t idx) {
1731-
diagnostics_.ReserveAdditional(2); // Ensure diagnostics don't resize alive after AddNote()
17321737
auto src =
17331738
Disassemble().ResultSource(Disassembler::IndexedValue{inst, static_cast<uint32_t>(idx)});
17341739
auto& diag = AddError(src) << inst->FriendlyName() << ": ";
17351740

17361741
if (!block_stack_.IsEmpty()) {
17371742
AddNote(block_stack_.Back()) << "in block";
1743+
1744+
// Adding the note may trigger a resize and invalidate the error diagnostic reference, so we
1745+
// need to get a new reference to the error diagnostic here.
1746+
return *(diagnostics_.end() - 2);
17381747
}
17391748
return diag;
17401749
}
@@ -3254,6 +3263,10 @@ void Validator::EndBlock() {
32543263
}
32553264

32563265
void Validator::QueueInstructions(const Instruction* inst) {
3266+
if (diagnostics_.ContainsErrors()) {
3267+
return;
3268+
}
3269+
32573270
tasks_.Push([this, inst] {
32583271
// Tasks are processed LIFO, so push the next instruction to the stack before checking the
32593272
// current instruction, which may need to add more blocks to the stack itself.

src/tint/lang/core/ir/validator_flow_control_test.cc

Lines changed: 16 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -974,17 +974,21 @@ TEST_F(IR_ValidatorTest, Continue_InLoopInit) {
974974
auto* f = b.Function("my_func", ty.void_());
975975
b.Append(f->Block(), [&] {
976976
auto* loop = b.Loop();
977-
b.Append(loop->Initializer(), [&] { b.Continue(loop); });
977+
b.Append(loop->Initializer(), [&]() {
978+
auto* if_ = b.If(true);
979+
b.Append(if_->True(), [&]() { b.Continue(loop); });
980+
b.NextIteration(loop);
981+
});
978982
b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
979983
b.Return(f);
980984
});
981985

982986
auto res = ir::Validate(mod);
983987
ASSERT_NE(res, Success);
984988
EXPECT_THAT(res.Failure().reason,
985-
testing::HasSubstr(R"(:5:9 error: continue: must only be called from loop body
986-
continue # -> $B4
987-
^^^^^^^^
989+
testing::HasSubstr(R"(:7:13 error: continue: must only be called from loop body
990+
continue # -> $B5
991+
^^^^^^^^
988992
)")) << res.Failure();
989993
}
990994

@@ -1005,16 +1009,20 @@ TEST_F(IR_ValidatorTest, Continue_InLoopContinuing) {
10051009
b.Append(f->Block(), [&] {
10061010
auto* loop = b.Loop();
10071011
b.Append(loop->Body(), [&] { b.ExitLoop(loop); });
1008-
b.Append(loop->Continuing(), [&] { b.Continue(loop); });
1012+
b.Append(loop->Continuing(), [&]() {
1013+
auto* if_ = b.If(true);
1014+
b.Append(if_->True(), [&]() { b.Continue(loop); });
1015+
b.NextIteration(loop);
1016+
});
10091017
b.Return(f);
10101018
});
10111019

10121020
auto res = ir::Validate(mod);
10131021
ASSERT_NE(res, Success);
10141022
EXPECT_THAT(res.Failure().reason,
1015-
testing::HasSubstr(R"(:8:9 error: continue: must only be called from loop body
1016-
continue # -> $B3
1017-
^^^^^^^^
1023+
testing::HasSubstr(R"(:10:13 error: continue: must only be called from loop body
1024+
continue # -> $B3
1025+
^^^^^^^^
10181026
)")) << res.Failure();
10191027
}
10201028

@@ -1856,28 +1864,6 @@ TEST_F(IR_ValidatorTest, ExitLoop_InvalidJumpOverLoop) {
18561864
TEST_F(IR_ValidatorTest, ExitLoop_InvalidInsideContinuing) {
18571865
auto* loop = b.Loop();
18581866

1859-
loop->Continuing()->Append(b.ExitLoop(loop));
1860-
loop->Body()->Append(b.Continue(loop));
1861-
1862-
auto* f = b.Function("my_func", ty.void_());
1863-
1864-
b.Append(f->Block(), [&] {
1865-
b.Append(loop);
1866-
b.Return(f);
1867-
});
1868-
1869-
auto res = ir::Validate(mod);
1870-
ASSERT_NE(res, Success);
1871-
EXPECT_THAT(res.Failure().reason,
1872-
testing::HasSubstr(R"(:8:9 error: exit_loop: loop exit jumps out of continuing block
1873-
exit_loop # loop_1
1874-
^^^^^^^^^
1875-
)")) << res.Failure();
1876-
}
1877-
1878-
TEST_F(IR_ValidatorTest, ExitLoop_InvalidInsideContinuingNested) {
1879-
auto* loop = b.Loop();
1880-
18811867
b.Append(loop->Continuing(), [&]() {
18821868
auto* if_ = b.If(true);
18831869
b.Append(if_->True(), [&]() { b.ExitLoop(loop); });
@@ -1906,31 +1892,6 @@ TEST_F(IR_ValidatorTest, ExitLoop_InvalidInsideContinuingNested) {
19061892
TEST_F(IR_ValidatorTest, ExitLoop_InvalidInsideInitializer) {
19071893
auto* loop = b.Loop();
19081894

1909-
loop->Initializer()->Append(b.ExitLoop(loop));
1910-
loop->Continuing()->Append(b.NextIteration(loop));
1911-
1912-
b.Append(loop->Body(), [&] { b.Continue(loop); });
1913-
1914-
auto* f = b.Function("my_func", ty.void_());
1915-
1916-
b.Append(f->Block(), [&] {
1917-
b.Append(loop);
1918-
b.Return(f);
1919-
});
1920-
1921-
auto res = ir::Validate(mod);
1922-
ASSERT_NE(res, Success);
1923-
EXPECT_THAT(
1924-
res.Failure().reason,
1925-
testing::HasSubstr(R"(:5:9 error: exit_loop: loop exit not permitted in loop initializer
1926-
exit_loop # loop_1
1927-
^^^^^^^^^
1928-
)")) << res.Failure();
1929-
}
1930-
1931-
TEST_F(IR_ValidatorTest, ExitLoop_InvalidInsideInitializerNested) {
1932-
auto* loop = b.Loop();
1933-
19341895
b.Append(loop->Initializer(), [&]() {
19351896
auto* if_ = b.If(true);
19361897
b.Append(if_->True(), [&]() { b.ExitLoop(loop); });

src/tint/utils/diagnostic/diagnostic.h

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,9 @@ class Diagnostic {
8686
/// List is a container of Diagnostic messages.
8787
class List {
8888
public:
89-
/// The iterator type for this List
90-
using iterator = VectorIterator<const Diagnostic>;
89+
/// The iterator types for this List
90+
using iterator = VectorIterator<Diagnostic>;
91+
using const_iterator = VectorIterator<const Diagnostic>;
9192

9293
/// Constructs the list with no elements.
9394
List();
@@ -186,11 +187,6 @@ class List {
186187
return Add(std::move(error));
187188
}
188189

189-
/// Ensures that the diagnostic list can fit an additional @p count diagnostics without
190-
/// resizing. This is useful for ensuring that a reference returned by the AddX() methods is not
191-
/// invalidated after another Add().
192-
void ReserveAdditional(size_t count) { entries_.Reserve(entries_.Length() + count); }
193-
194190
/// @returns true iff the diagnostic list contains errors diagnostics (or of
195191
/// higher severity).
196192
bool ContainsErrors() const { return error_count_ > 0; }
@@ -212,9 +208,13 @@ class List {
212208
/// @returns the number of entries in the list.
213209
size_t size() const { return entries_.Length(); }
214210
/// @returns the first diagnostic in the list.
215-
iterator begin() const { return entries_.begin(); }
211+
const_iterator begin() const { return entries_.begin(); }
212+
/// @returns the last diagnostic in the list.
213+
const_iterator end() const { return entries_.end(); }
214+
/// @returns the first diagnostic in the list.
215+
iterator begin() { return entries_.begin(); }
216216
/// @returns the last diagnostic in the list.
217-
iterator end() const { return entries_.end(); }
217+
iterator end() { return entries_.end(); }
218218

219219
private:
220220
Vector<Diagnostic, 0> entries_;

0 commit comments

Comments
 (0)