Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(84)

Side by Side Diff: runtime/vm/intermediate_language.cc

Issue 943273004: Fold BIT_NOT and NEGATE during constant propagation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add tests. Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | tests/language/vm/optimized_testsmi_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/intermediate_language.h" 5 #include "vm/intermediate_language.h"
6 6
7 #include "vm/bit_vector.h" 7 #include "vm/bit_vector.h"
8 #include "vm/constant_propagator.h" 8 #include "vm/constant_propagator.h"
9 #include "vm/cpu.h" 9 #include "vm/cpu.h"
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 1571 matching lines...) Expand 10 before | Expand all | Expand 10 after
1582 1582
1583 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported. 1583 case kUnboxedUint32: // Only truncating Uint32 arithmetic is supported.
1584 default: 1584 default:
1585 UNREACHABLE(); 1585 UNREACHABLE();
1586 } 1586 }
1587 1587
1588 return false; 1588 return false;
1589 } 1589 }
1590 1590
1591 1591
1592 RawInteger* UnaryIntegerOpInstr::Evaluate(const Integer& value) const {
1593 Integer& result = Integer::Handle();
1594
1595 switch (op_kind()) {
1596 case Token::kNEGATE:
1597 result = value.ArithmeticOp(Token::kMUL, Smi::Handle(Smi::New(-1)));
1598 break;
1599
1600 case Token::kBIT_NOT:
1601 if (value.IsSmi()) {
1602 result = Integer::New(~Smi::Cast(value).Value());
1603 } else if (value.IsMint()) {
1604 result = Integer::New(~Mint::Cast(value).value());
1605 }
1606 break;
1607
1608 default:
1609 UNREACHABLE();
1610 }
1611
1612 if (!result.IsNull()) {
1613 if (!IsRepresentable(result, representation())) {
1614 // If this operation is not truncating it would deoptimize on overflow.
1615 // Check that we match this behavior and don't produce a value that is
1616 // larger than something this operation can produce. We could have
1617 // specialized instructions that use this value under this assumption.
1618 return Integer::null();
1619 }
1620 result ^= result.CheckAndCanonicalize(NULL);
1621 }
1622
1623 return result.raw();
1624 }
1625
1626
1592 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left, 1627 RawInteger* BinaryIntegerOpInstr::Evaluate(const Integer& left,
1593 const Integer& right) const { 1628 const Integer& right) const {
1594 Integer& result = Integer::Handle(); 1629 Integer& result = Integer::Handle();
1595 1630
1596 switch (op_kind()) { 1631 switch (op_kind()) {
1597 case Token::kTRUNCDIV: 1632 case Token::kTRUNCDIV:
1598 case Token::kMOD: 1633 case Token::kMOD:
1599 // Check right value for zero. 1634 // Check right value for zero.
1600 if (right.AsInt64Value() == 0) { 1635 if (right.AsInt64Value() == 0) {
1601 break; // Will throw. 1636 break; // Will throw.
(...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after
2302 other_defn->IsComparison() && 2337 other_defn->IsComparison() &&
2303 (other->Type()->ToCid() == kBoolCid) && 2338 (other->Type()->ToCid() == kBoolCid) &&
2304 other_defn->HasOnlyUse(other)) { 2339 other_defn->HasOnlyUse(other)) {
2305 *negated = true; 2340 *negated = true;
2306 return other_defn; 2341 return other_defn;
2307 } 2342 }
2308 return compare; 2343 return compare;
2309 } 2344 }
2310 2345
2311 2346
2312 // Recognize the pattern (a & b) == 0 where left is a bitwise and operation 2347 static bool BindsToGivenConstant(Value* v, intptr_t expected) {
2313 // and right is a constant 0. 2348 return v->BindsToConstant() &&
2314 static bool RecognizeTestPattern(Value* left, Value* right) { 2349 v->BoundConstant().IsSmi() &&
2315 if (!right->BindsToConstant()) { 2350 (Smi::Cast(v->BoundConstant()).Value() == expected);
2351 }
2352
2353
2354 // Recognize patterns (a & b) == 0 and (a & 2^n) != 2^n.
2355 static bool RecognizeTestPattern(Value* left, Value* right, bool* negate) {
2356 if (!right->BindsToConstant() || !right->BoundConstant().IsSmi()) {
2316 return false; 2357 return false;
2317 } 2358 }
2318 2359
2319 const Object& value = right->BoundConstant(); 2360 const intptr_t value = Smi::Cast(right->BoundConstant()).Value();
2320 if (!value.IsSmi() || (Smi::Cast(value).Value() != 0)) { 2361 if ((value != 0) && !Utils::IsPowerOfTwo(value)) {
2321 return false; 2362 return false;
2322 } 2363 }
2323 2364
2324 Definition* left_defn = left->definition(); 2365
2325 return left_defn->IsBinarySmiOp() && 2366 BinarySmiOpInstr* mask_op = left->definition()->AsBinarySmiOp();
2326 (left_defn->AsBinarySmiOp()->op_kind() == Token::kBIT_AND) && 2367 if ((mask_op == NULL) ||
2327 left_defn->HasOnlyUse(left); 2368 (mask_op->op_kind() != Token::kBIT_AND) ||
2369 !mask_op->HasOnlyUse(left)) {
2370 return false;
2371 }
2372
2373 if (value == 0) {
2374 // Recognized (a & b) == 0 pattern.
2375 *negate = false;
2376 return true;
2377 }
2378
2379 // Recognize
2380 if (BindsToGivenConstant(mask_op->left(), value) ||
2381 BindsToGivenConstant(mask_op->right(), value)) {
2382 // Recognized (a & 2^n) == 2^n pattern. It's equivalent to (a & 2^n) != 0
2383 // so we need to negate original comparison.
2384 *negate = true;
2385 return true;
2386 }
2387
2388 return false;
2328 } 2389 }
2329 2390
2330 2391
2331 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) { 2392 Instruction* BranchInstr::Canonicalize(FlowGraph* flow_graph) {
2332 Isolate* isolate = flow_graph->isolate(); 2393 Isolate* isolate = flow_graph->isolate();
2333 // Only handle strict-compares. 2394 // Only handle strict-compares.
2334 if (comparison()->IsStrictCompare()) { 2395 if (comparison()->IsStrictCompare()) {
2335 bool negated = false; 2396 bool negated = false;
2336 Definition* replacement = 2397 Definition* replacement =
2337 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated); 2398 CanonicalizeStrictCompare(comparison()->AsStrictCompare(), &negated);
(...skipping 27 matching lines...) Expand all
2365 } 2426 }
2366 // Clear the comparison's temp index and ssa temp index since the 2427 // Clear the comparison's temp index and ssa temp index since the
2367 // value of the comparison is not used outside the branch anymore. 2428 // value of the comparison is not used outside the branch anymore.
2368 ASSERT(comp->input_use_list() == NULL); 2429 ASSERT(comp->input_use_list() == NULL);
2369 comp->ClearSSATempIndex(); 2430 comp->ClearSSATempIndex();
2370 comp->ClearTempIndex(); 2431 comp->ClearTempIndex();
2371 } 2432 }
2372 } else if (comparison()->IsEqualityCompare() && 2433 } else if (comparison()->IsEqualityCompare() &&
2373 comparison()->operation_cid() == kSmiCid) { 2434 comparison()->operation_cid() == kSmiCid) {
2374 BinarySmiOpInstr* bit_and = NULL; 2435 BinarySmiOpInstr* bit_and = NULL;
2375 if (RecognizeTestPattern(comparison()->left(), comparison()->right())) { 2436 bool negate = false;
2437 if (RecognizeTestPattern(comparison()->left(),
2438 comparison()->right(),
2439 &negate)) {
2376 bit_and = comparison()->left()->definition()->AsBinarySmiOp(); 2440 bit_and = comparison()->left()->definition()->AsBinarySmiOp();
2377 } else if (RecognizeTestPattern(comparison()->right(), 2441 } else if (RecognizeTestPattern(comparison()->right(),
2378 comparison()->left())) { 2442 comparison()->left(),
2443 &negate)) {
2379 bit_and = comparison()->right()->definition()->AsBinarySmiOp(); 2444 bit_and = comparison()->right()->definition()->AsBinarySmiOp();
2380 } 2445 }
2381 if (bit_and != NULL) { 2446 if (bit_and != NULL) {
2382 if (FLAG_trace_optimization) { 2447 if (FLAG_trace_optimization) {
2383 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index()); 2448 OS::Print("Merging test smi v%" Pd "\n", bit_and->ssa_temp_index());
2384 } 2449 }
2385 TestSmiInstr* test = new TestSmiInstr( 2450 TestSmiInstr* test = new TestSmiInstr(
2386 comparison()->token_pos(), 2451 comparison()->token_pos(),
2387 comparison()->kind(), 2452 negate ? Token::NegateComparison(comparison()->kind())
2453 : comparison()->kind(),
2388 bit_and->left()->Copy(isolate), 2454 bit_and->left()->Copy(isolate),
2389 bit_and->right()->Copy(isolate)); 2455 bit_and->right()->Copy(isolate));
2390 ASSERT(!CanDeoptimize()); 2456 ASSERT(!CanDeoptimize());
2391 RemoveEnvironment(); 2457 RemoveEnvironment();
2392 flow_graph->CopyDeoptTarget(this, bit_and); 2458 flow_graph->CopyDeoptTarget(this, bit_and);
2393 SetComparison(test); 2459 SetComparison(test);
2394 bit_and->RemoveFromGraph(); 2460 bit_and->RemoveFromGraph();
2395 } 2461 }
2396 } 2462 }
2397 return this; 2463 return this;
(...skipping 1122 matching lines...) Expand 10 before | Expand all | Expand 10 after
3520 case Token::kTRUNCDIV: return 0; 3586 case Token::kTRUNCDIV: return 0;
3521 case Token::kMOD: return 1; 3587 case Token::kMOD: return 1;
3522 default: UNIMPLEMENTED(); return -1; 3588 default: UNIMPLEMENTED(); return -1;
3523 } 3589 }
3524 } 3590 }
3525 3591
3526 3592
3527 #undef __ 3593 #undef __
3528 3594
3529 } // namespace dart 3595 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/intermediate_language.h ('k') | tests/language/vm/optimized_testsmi_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698