[vm/compiler] Remove unnecessary type check from optimized switches
Switch optimization now relies on static type of the tested value,
so it is safe to omit the type check (with sound null safety) or
reduce it to a null check (without sound null safety).
TEST=co19/LanguageFeatures/Patterns/Exhaustiveness/exhaustiveness_enum_A01_t01
Fixes https://github.com/dart-lang/sdk/issues/52422
Change-Id: Ic93f4f212bee9ed3bfe5035f3c8d7535274c2f63
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/304102
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Alexander Aprelev <aam@google.com>
diff --git a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
index 28a7a39..82e88af 100644
--- a/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
+++ b/runtime/vm/compiler/frontend/kernel_binary_flowgraph.cc
@@ -5072,30 +5072,23 @@
SwitchHelper* helper,
JoinEntryInstr* join) {
const TokenPosition pos = helper->position();
-
- // We need to check that the switch variable is of the correct type.
- // If it is not, we go to [join] which is either the default case or
- // the exit of the switch statement.
-
- TargetEntryInstr* then_entry;
- TargetEntryInstr* otherwise_entry;
-
- const AbstractType& expression_type = helper->expression_type();
- ASSERT(dart::SimpleInstanceOfType(expression_type));
-
Fragment instructions;
- instructions += LoadLocal(scopes()->switch_variable);
- instructions += Constant(expression_type);
- instructions += InstanceCall(
- pos, Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
- Token::kIS, /*argument_count=*/2,
- /*checked_argument_count=*/2);
- instructions += BranchIfTrue(&then_entry, &otherwise_entry, /*negate=*/false);
- Fragment otherwise_instructions(otherwise_entry);
- otherwise_instructions += Goto(join);
+ if (!IG->null_safety()) {
+ // Without sound null safety we need to check that the switch variable is
+ // not null. If it is null, we go to [join] which is either the default
+ // case or the exit of the switch statement.
+ TargetEntryInstr* null_entry;
+ TargetEntryInstr* non_null_entry;
- instructions = Fragment(instructions.entry, then_entry);
+ instructions += LoadLocal(scopes()->switch_variable);
+ instructions += BranchIfNull(&null_entry, &non_null_entry);
+
+ Fragment null_instructions(null_entry);
+ null_instructions += Goto(join);
+
+ instructions = Fragment(instructions.entry, non_null_entry);
+ }
if (helper->is_enum_switch()) {
// For an enum switch, we need to load the enum index from the switch
@@ -5260,6 +5253,10 @@
stack.Add(
SwitchRange::Branch(range.min(), middle, lower_branch_instructions));
}
+
+ if (current_instructions.is_empty()) {
+ current_instructions = branch_instructions;
+ }
}
return Fragment(current_instructions.entry, join_instructions.current);