Index: runtime/vm/intermediate_language_x64.cc |
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc |
index a13034474da6675a27c22cbe47ef662103d0881f..fa3e7ad48004d163cd419deea81f6a60980b9633 100644 |
--- a/runtime/vm/intermediate_language_x64.cc |
+++ b/runtime/vm/intermediate_language_x64.cc |
@@ -113,6 +113,147 @@ void ReturnInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
} |
+static Condition NegateCondition(Condition condition) { |
+ switch (condition) { |
+ case EQUAL: return NOT_EQUAL; |
+ case NOT_EQUAL: return EQUAL; |
+ case LESS: return GREATER_EQUAL; |
+ case LESS_EQUAL: return GREATER; |
+ case GREATER: return LESS_EQUAL; |
+ case GREATER_EQUAL: return LESS; |
+ case BELOW: return ABOVE_EQUAL; |
+ case BELOW_EQUAL: return ABOVE; |
+ case ABOVE: return BELOW_EQUAL; |
+ case ABOVE_EQUAL: return BELOW; |
+ default: |
+ OS::Print("Error %d\n", condition); |
+ UNIMPLEMENTED(); |
+ return EQUAL; |
+ } |
+} |
+ |
+ |
+static bool BindsToSmiConstant(Value* val, intptr_t* smi_value) { |
+ if (!val->BindsToConstant()) { |
+ return false; |
+ } |
+ |
+ const Object& bound_constant = val->BoundConstant(); |
+ if (!bound_constant.IsSmi()) { |
+ return false; |
+ } |
+ |
+ *smi_value = Smi::Cast(bound_constant).Value(); |
+ return true; |
+} |
+ |
+ |
+// Detect pattern when one value is zero and another is a power of 2. |
+static bool IsPowerOfTwoKind(intptr_t v1, intptr_t v2) { |
+ return (Utils::IsPowerOfTwo(v1) && (v2 == 0)) || |
+ (Utils::IsPowerOfTwo(v2) && (v1 == 0)); |
+} |
+ |
+ |
+// Detect pattern when one value is increment of another. |
+static bool IsIncrementKind(intptr_t v1, intptr_t v2) { |
+ return ((v1 == v2 + 1) || (v1 + 1 == v2)); |
+} |
+ |
+ |
+bool IfThenElseInstr::IsSupported() { |
+ return true; |
+} |
+ |
+ |
+bool IfThenElseInstr::Supports(ComparisonInstr* comparison, |
+ Value* v1, |
+ Value* v2) { |
+ if (!(comparison->IsStrictCompare() && |
+ !comparison->AsStrictCompare()->needs_number_check()) && |
+ !(comparison->IsEqualityCompare() && |
+ (comparison->AsEqualityCompare()->receiver_class_id() == kSmiCid))) { |
+ return false; |
+ } |
+ |
+ intptr_t v1_value, v2_value; |
+ |
+ if (!BindsToSmiConstant(v1, &v1_value) || |
+ !BindsToSmiConstant(v2, &v2_value)) { |
+ return false; |
+ } |
+ |
+ if (IsPowerOfTwoKind(v1_value, v2_value) || |
+ IsIncrementKind(v1_value, v2_value)) { |
+ return true; |
+ } |
+ |
+ return false; |
+} |
+ |
+ |
+LocationSummary* IfThenElseInstr::MakeLocationSummary() const { |
+ const intptr_t kNumInputs = 2; |
+ const intptr_t kNumTemps = 0; |
+ LocationSummary* locs = |
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
+ locs->set_in(0, Location::RegisterOrConstant(left())); |
+ locs->set_in(1, Location::RegisterOrConstant(right())); |
+ // TODO(vegorov): support byte register constraints in the register allocator. |
+ locs->set_out(Location::RegisterLocation(RDX)); |
+ return locs; |
+} |
+ |
+ |
+void IfThenElseInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
+ ASSERT(locs()->out().reg() == RDX); |
+ ASSERT(Token::IsEqualityOperator(kind())); |
+ |
+ Location left = locs()->in(0); |
+ Location right = locs()->in(1); |
+ ASSERT(!left.IsConstant() || !right.IsConstant()); |
+ |
+ // Clear upper part of the out register. We are going to use setcc on it |
+ // which is a byte move. |
+ __ xorq(RDX, RDX); |
+ |
+ // Compare left and right. For now only equality comparison is supported. |
+ // TODO(vegorov): reuse code from the other comparison instructions instead of |
+ // generating it inline here. |
+ if (left.IsConstant()) { |
+ __ CompareObject(right.reg(), left.constant()); |
+ } else if (right.IsConstant()) { |
+ __ CompareObject(left.reg(), right.constant()); |
+ } else { |
+ __ cmpq(left.reg(), right.reg()); |
+ } |
+ |
+ Condition true_condition = |
+ ((kind_ == Token::kEQ_STRICT) || (kind_ == Token::kEQ)) ? EQUAL |
+ : NOT_EQUAL; |
+ |
+ const bool is_power_of_two_kind = IsPowerOfTwoKind(if_true_, if_false_); |
+ |
+ const intptr_t base = Utils::Minimum(if_true_, if_false_); |
+ |
+ if (if_true_ == base) { |
+ // We need to have zero in RDX on true_condition. |
+ true_condition = NegateCondition(true_condition); |
+ } |
+ |
+ __ setcc(true_condition, DL); |
+ |
+ if (is_power_of_two_kind) { |
+ const intptr_t shift = |
+ Utils::ShiftForPowerOfTwo(Utils::Maximum(if_true_, if_false_)); |
+ __ shlq(RDX, Immediate(shift + kSmiTagSize)); |
+ } else { |
+ ASSERT(kSmiTagSize == 1); |
+ __ leaq(RDX, Address(RDX, TIMES_2, base << kSmiTagSize)); |
+ } |
+} |
+ |
+ |
LocationSummary* ClosureCallInstr::MakeLocationSummary() const { |
const intptr_t kNumInputs = 0; |
const intptr_t kNumTemps = 1; |
@@ -3096,26 +3237,6 @@ void GotoInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
} |
-static Condition NegateCondition(Condition condition) { |
- switch (condition) { |
- case EQUAL: return NOT_EQUAL; |
- case NOT_EQUAL: return EQUAL; |
- case LESS: return GREATER_EQUAL; |
- case LESS_EQUAL: return GREATER; |
- case GREATER: return LESS_EQUAL; |
- case GREATER_EQUAL: return LESS; |
- case BELOW: return ABOVE_EQUAL; |
- case BELOW_EQUAL: return ABOVE; |
- case ABOVE: return BELOW_EQUAL; |
- case ABOVE_EQUAL: return BELOW; |
- default: |
- OS::Print("Error %d\n", condition); |
- UNIMPLEMENTED(); |
- return EQUAL; |
- } |
-} |
- |
- |
void ControlInstruction::EmitBranchOnValue(FlowGraphCompiler* compiler, |
bool value) { |
if (value && !compiler->CanFallThroughTo(true_successor())) { |