[validator] Move exit functional checks. Move the functional validation for `Exit*` to the functional validator. Bug: 516717234 Change-Id: Ic0ae86e64b38e5ac73649ff88cae9dfce7dff192 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/314518 Reviewed-by: James Price <jrprice@google.com> Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/src/tint/lang/core/ir/functional_validator.cc b/src/tint/lang/core/ir/functional_validator.cc index 1a36359..33bd858 100644 --- a/src/tint/lang/core/ir/functional_validator.cc +++ b/src/tint/lang/core/ir/functional_validator.cc
@@ -29,6 +29,8 @@ #include "src/tint/lang/core/intrinsic/dialect.h" #include "src/tint/lang/core/ir/discard.h" +#include "src/tint/lang/core/ir/exit_if.h" +#include "src/tint/lang/core/ir/exit_switch.h" #include "src/tint/lang/core/ir/multi_in_block.h" #include "src/tint/lang/core/ir/phony.h" #include "src/tint/lang/core/ir/type/array_count.h" @@ -1002,10 +1004,13 @@ void Functional::CheckTerminator(const Terminator* b) { tint::Switch( - b, // - [&](const ir::BreakIf* i) { CheckBreakIf(i); }, // - [&](const ir::Continue* c) { CheckContinue(c); } // - // TODO(516717234): Add TINT_ICE_ON_NO_MATCH + b, // + [&](const ir::BreakIf* i) { CheckBreakIf(i); }, // + [&](const ir::Continue* c) { CheckContinue(c); }, // + [&](const ir::Exit* e) { CheckExit(e); }, // + + [&](Default) {} // + // TODO(516717234): Add TINT_ICE_ON_NO_MATCH ); } @@ -1389,4 +1394,36 @@ } } +void Functional::CheckExit(const Exit* e) { + tint::Switch( + e, // + [&](const ir::ExitIf*) {}, // + [&](const ir::ExitLoop* l) { CheckExitLoop(l); }, // + [&](const ir::ExitSwitch*) {}, // + TINT_ICE_ON_NO_MATCH); +} + +void Functional::CheckExitLoop(const ExitLoop* l) { + const Instruction* inst = l; + const Loop* control = l->Loop(); + while (inst) { + // Found parent loop + if (inst->Block()->Parent() == control) { + if (inst->Block() == control->Continuing()) { + AddError(l) << "loop exit jumps out of continuing block"; + if (control->Continuing() != l->Block()) { + AddNote(control->Continuing()) << "in continuing block"; + } + } else if (inst->Block() == control->Initializer()) { + AddError(l) << "loop exit not permitted in loop initializer"; + if (control->Initializer() != l->Block()) { + AddNote(control->Initializer()) << "in initializer block"; + } + } + break; + } + inst = inst->Block()->Parent(); + } +} + } // namespace tint::core::ir::validator
diff --git a/src/tint/lang/core/ir/functional_validator.h b/src/tint/lang/core/ir/functional_validator.h index dfb45c7..7e45603 100644 --- a/src/tint/lang/core/ir/functional_validator.h +++ b/src/tint/lang/core/ir/functional_validator.h
@@ -40,6 +40,8 @@ #include "src/tint/lang/core/ir/convert.h" #include "src/tint/lang/core/ir/core_builtin_call.h" #include "src/tint/lang/core/ir/disassembler.h" +#include "src/tint/lang/core/ir/exit.h" +#include "src/tint/lang/core/ir/exit_loop.h" #include "src/tint/lang/core/ir/if.h" #include "src/tint/lang/core/ir/let.h" #include "src/tint/lang/core/ir/load.h" @@ -130,6 +132,8 @@ void CheckConvert(const Convert* convert); void CheckCoreBuiltinCall(const CoreBuiltinCall* call, const core::intrinsic::Overload& overload); + void CheckExit(const Exit* e); + void CheckExitLoop(const ExitLoop* l); void CheckIf(const If* if_); void CheckLet(const Let* l); void CheckLoad(const Load* l);
diff --git a/src/tint/lang/core/ir/structural_validator.cc b/src/tint/lang/core/ir/structural_validator.cc index ac73f63..8785c51 100644 --- a/src/tint/lang/core/ir/structural_validator.cc +++ b/src/tint/lang/core/ir/structural_validator.cc
@@ -2722,7 +2722,7 @@ [&](const Unary* u) { CheckUnary(u); }, // [&](const Override* o) { CheckOverride(o); }, // [&](const Var* var) { CheckVar(var); }, // - [&](const Default) { AddError(inst) << "missing validation"; }); + TINT_ICE_ON_NO_MATCH); } void Structural::CheckOverride(const Override* o) { @@ -3124,7 +3124,8 @@ [&](Default) { auto* e = t->DeepestElement()->UnwrapPtrOrRef(); tint::Switch( - e, [&](const core::type::Struct* s) { result = is_numeric(s); }, + e, // + [&](const core::type::Struct* s) { result = is_numeric(s); }, [&](Default) { result = e->IsNumericScalarOrVector(); }); }); return result; @@ -3475,7 +3476,7 @@ [&](const ir::Return* ret) { CheckReturn(ret); }, // [&](const ir::TerminateInvocation*) {}, // [&](const ir::Unreachable* u) { CheckUnreachable(u); }, // - [&](Default) { AddError(b) << "missing validation"; }); + TINT_ICE_ON_NO_MATCH); if (b->next) { AddError(b) << "must be the last instruction in the block"; @@ -3521,15 +3522,14 @@ } void Structural::CheckExit(const Exit* e) { - if (e->ControlInstruction() == nullptr) { - AddError(e) << "has no parent control instruction"; - return; - } - if (control_stack_.IsEmpty()) { AddError(e) << "found outside all control instructions"; return; } + if (e->ControlInstruction() == nullptr) { + AddError(e) << "has no parent control instruction"; + return; + } auto args = e->Args(); CheckOperandsMatchTarget(e, e->ArgsOperandOffset(), args.size(), e->ControlInstruction(), @@ -3540,7 +3540,7 @@ [&](const ir::ExitIf* i) { CheckExitIf(i); }, // [&](const ir::ExitLoop* l) { CheckExitLoop(l); }, // [&](const ir::ExitSwitch* s) { CheckExitSwitch(s); }, // - [&](Default) { AddError(e) << "missing validation"; }); + TINT_ICE_ON_NO_MATCH); } void Structural::CheckNextIteration(const NextIteration* n) { @@ -3632,27 +3632,6 @@ void Structural::CheckExitLoop(const ExitLoop* l) { CheckControlsAllowingIf(l, l->ControlInstruction()); - - const Instruction* inst = l; - const Loop* control = l->Loop(); - while (inst) { - // Found parent loop - if (inst->Block()->Parent() == control) { - if (inst->Block() == control->Continuing()) { - AddError(l) << "loop exit jumps out of continuing block"; - if (control->Continuing() != l->Block()) { - AddNote(control->Continuing()) << "in continuing block"; - } - } else if (inst->Block() == control->Initializer()) { - AddError(l) << "loop exit not permitted in loop initializer"; - if (control->Initializer() != l->Block()) { - AddNote(control->Initializer()) << "in initializer block"; - } - } - break; - } - inst = inst->Block()->Parent(); - } } void Structural::CheckLoad(const Load* l) {