[wasm-backend] Implement more comparison features.
This implements various small features needed for DeltaBlue:
- Comparison between two references
- Comparison between a reference and a literal null
- Assigning the result of a comparison to a bool variable
- Negating a bool
- Using a bool variable in a condition
- Mentioning dynamic (directly or indirectly)
Change-Id: I74c11cb180eb59e4bea66b751eafa59908325b2e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/166623
Reviewed-by: Tess Strickland <sstrickl@google.com>
diff --git a/runtime/vm/compiler/aot/wasm_codegen.cc b/runtime/vm/compiler/aot/wasm_codegen.cc
index 388cc0f..5a1f0ec 100644
--- a/runtime/vm/compiler/aot/wasm_codegen.cc
+++ b/runtime/vm/compiler/aot/wasm_codegen.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/compiler/aot/wasm_codegen.h"
+#include "vm/object_store.h"
#define Z (zone_)
#define M (module_builder_)
@@ -191,8 +192,13 @@
}
WasmClassInfo& WasmCodegen::GetWasmClassInfo(const Class& klass) {
+ // Treat dynamic as Object.
+ Class& klass2 = Class::Handle(klass.raw());
+ if (klass.IsDynamicClass()) {
+ klass2 = Thread::Current()->isolate()->object_store()->object_class();
+ }
pair<const Class*, WasmClassInfo>* const pair =
- class_to_wasm_class_info_.Lookup(&klass);
+ class_to_wasm_class_info_.Lookup(&klass2);
// At this point all classes should have been hoisted.
// If this is not true, exit with an error even in non-debug builds.
if (pair == nullptr) {
diff --git a/runtime/vm/compiler/aot/wasm_translator.cc b/runtime/vm/compiler/aot/wasm_translator.cc
index 0fa3979..d185f16 100644
--- a/runtime/vm/compiler/aot/wasm_translator.cc
+++ b/runtime/vm/compiler/aot/wasm_translator.cc
@@ -201,6 +201,15 @@
VisitBinaryIntegerOp(instr);
}
+void WasmTranslator::VisitBooleanNegate(BooleanNegateInstr* instr) {
+ PushValue(instr->value()->definition(),
+ AbstractType::Handle(AbstractType::null()));
+ wasm_scope_->AddI32Constant(1);
+ wasm_scope_->AddIntOp(wasm::IntOp::IntegerKind::kI32,
+ wasm::IntOp::OpKind::kXor);
+ PopValue(instr);
+}
+
void WasmTranslator::VisitParameter(ParameterInstr* instr) {
// If the parameter is not the This parameter of a method, then just map
// the parameter definition to the corresponding Wasm local of type kParam.
@@ -370,6 +379,21 @@
wasm_scope_->AddStructSet(wasm_struct, wasm_field);
}
+void WasmTranslator::VisitEqualityCompare(EqualityCompareInstr* instr) {
+ PushEvalCondition(instr, /*negated=*/false);
+ PopValue(instr);
+}
+
+void WasmTranslator::VisitStrictCompare(StrictCompareInstr* instr) {
+ PushEvalCondition(instr, /*negated=*/false);
+ PopValue(instr);
+}
+
+void WasmTranslator::VisitRelationalOp(RelationalOpInstr* instr) {
+ PushEvalCondition(instr, /*negated=*/false);
+ PopValue(instr);
+}
+
intptr_t WasmTranslator::GetFallthroughPredecessorIndex(
BlockEntryInstr* target) {
intptr_t block_number = target->postorder_number();
@@ -582,8 +606,34 @@
wasm_scope_->AddIntOp(wasm::IntOp::IntegerKind::kI64, op_kind);
} else if (auto strict_comp_op =
comp->AsStrictCompare()) { // General StrictCompare === !==
- // TODO(askesc): Figure out the details.
- UNIMPLEMENTED();
+ negated ^= comp->kind() == Token::Kind::kNE_STRICT;
+ if (IsBoolValue(comp->right())) {
+ if (auto const_instr = comp->right()->definition()->AsConstant()) {
+ const Object& value = const_instr->value();
+ const bool bool_value = Bool::Cast(value).value();
+ negated ^= !bool_value;
+ PushValue(comp->left()->definition(),
+ *comp->left()->Type()->ToAbstractType());
+ } else {
+ UNIMPLEMENTED();
+ }
+ } else {
+ // To support comparison with a null constant on the right-hand side, we
+ // use the type of the left-hand side as the type hint for both operands.
+ // Alternatively, we could allow null constants without type hint and use
+ // the Object type in that case (which should be fine for comparisons).
+ PushValue(comp->left()->definition(),
+ *comp->left()->Type()->ToAbstractType());
+ PushValue(comp->right()->definition(),
+ *comp->left()->Type()->ToAbstractType());
+ wasm_scope_->AddRefEq();
+ }
+
+ if (negated) {
+ wasm_scope_->AddI32Constant(1);
+ wasm_scope_->AddIntOp(wasm::IntOp::IntegerKind::kI32,
+ wasm::IntOp::OpKind::kXor);
+ }
}
}
diff --git a/runtime/vm/compiler/aot/wasm_translator.h b/runtime/vm/compiler/aot/wasm_translator.h
index 1e2590d..bbfb1e9 100644
--- a/runtime/vm/compiler/aot/wasm_translator.h
+++ b/runtime/vm/compiler/aot/wasm_translator.h
@@ -54,6 +54,7 @@
virtual void VisitBinaryInt32Op(BinaryInt32OpInstr* instr);
virtual void VisitBinaryInt64Op(BinaryInt64OpInstr* instr);
virtual void VisitBinaryUint32Op(BinaryUint32OpInstr* instr);
+ virtual void VisitBooleanNegate(BooleanNegateInstr* instr);
virtual void VisitParameter(ParameterInstr* instr);
virtual void VisitStaticCall(StaticCallInstr* instr);
virtual void VisitDispatchTableCall(DispatchTableCallInstr* instr);
@@ -61,6 +62,9 @@
virtual void VisitAllocateObject(AllocateObjectInstr* instr);
virtual void VisitLoadField(LoadFieldInstr* instr);
virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
+ virtual void VisitEqualityCompare(EqualityCompareInstr* instr);
+ virtual void VisitStrictCompare(StrictCompareInstr* instr);
+ virtual void VisitRelationalOp(RelationalOpInstr* instr);
private:
// Traverse graph to find start locations of Wasm blocks.
diff --git a/third_party/benchmarks/DeltaBlueSimplified.dart b/third_party/benchmarks/DeltaBlueSimplified.dart
index b432577..707d9e9 100644
--- a/third_party/benchmarks/DeltaBlueSimplified.dart
+++ b/third_party/benchmarks/DeltaBlueSimplified.dart
@@ -37,7 +37,7 @@
* implementation.
*/
-main() {
+void main() {
new DeltaBlue().run();
}
@@ -90,6 +90,7 @@
Constraint(this.planner, this.strength);
+ @pragma("vm:never-inline")
bool isSatisfied();
void markUnsatisfied();
void addToGraph();
@@ -114,7 +115,7 @@
* there is one, or nil, if there isn't.
* Assume: I am not already satisfied.
*/
- Constraint satisfy(mark) {
+ Constraint satisfy(int mark) {
chooseMethod(mark);
if (!isSatisfied()) {
if (strength == REQUIRED) {
@@ -170,6 +171,7 @@
}
/// Returns true if this constraint is satisfied in the current solution.
+ @pragma("vm:never-inline")
bool isSatisfied() => satisfied;
void markInputs(int mark) {
@@ -286,6 +288,7 @@
}
/// Answer true if this constraint is satisfied in the current solution.
+ @pragma("vm:never-inline")
bool isSatisfied() => direction != NONE;
/// Mark the input variable with the given mark.
@@ -423,7 +426,7 @@
/// Removes all traces of c from this variable.
void removeConstraint(Constraint c) {
constraints.remove(c);
- if (determinedBy == c) determinedBy = null;
+ if (identical(determinedBy, c)) determinedBy = null;
}
}
@@ -739,7 +742,7 @@
dummy.prev = dummy;
}
- bool get isEmpty => dummy.next == dummy;
+ bool get isEmpty => identical(dummy.next, dummy);
void add(Constraint constraint) {
ConstraintListElement element = new ConstraintListElement(constraint);
@@ -758,7 +761,7 @@
void remove(Constraint constraint) {
for (var elem = dummy.next; elem != dummy; elem = elem.next) {
- if (elem.value == constraint) {
+ if (identical(elem.value, constraint)) {
elem.remove();
return;
}