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

Side by Side Diff: src/codegen-ia32.cc

Issue 21211: Optimize comparisons with constant Smis. Evaluate comparisons of... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/toiger/
Patch Set: '' Created 11 years, 10 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 | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. 1 // Copyright 2006-2008 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 1315 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 Result right_side(this); 1326 Result right_side(this);
1327 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order. 1327 // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
1328 if (cc == greater || cc == less_equal) { 1328 if (cc == greater || cc == less_equal) {
1329 cc = ReverseCondition(cc); 1329 cc = ReverseCondition(cc);
1330 left_side = frame_->Pop(); 1330 left_side = frame_->Pop();
1331 right_side = frame_->Pop(); 1331 right_side = frame_->Pop();
1332 } else { 1332 } else {
1333 right_side = frame_->Pop(); 1333 right_side = frame_->Pop();
1334 left_side = frame_->Pop(); 1334 left_side = frame_->Pop();
1335 } 1335 }
1336 left_side.ToRegister(); 1336 // If either side is a constant smi, optimize the comparison.
1337 right_side.ToRegister(); 1337 bool left_side_constant_smi =
1338 ASSERT(left_side.is_valid()); 1338 left_side.is_constant() && left_side.handle()->IsSmi();
1339 ASSERT(right_side.is_valid()); 1339 bool right_side_constant_smi =
1340 // Check for the smi case. 1340 right_side.is_constant() && right_side.handle()->IsSmi();
1341 JumpTarget is_smi(this);
1342 Result temp = allocator_->Allocate();
1343 ASSERT(temp.is_valid());
1344 __ mov(temp.reg(), left_side.reg());
1345 __ or_(temp.reg(), Operand(right_side.reg()));
1346 __ test(temp.reg(), Immediate(kSmiTagMask));
1347 temp.Unuse();
1348 is_smi.Branch(zero, &left_side, &right_side, taken);
1349 1341
1350 // When non-smi, call out to the compare stub. "parameters" setup by 1342 if (left_side_constant_smi || right_side_constant_smi) {
1351 // calling code in edx and eax and "result" is returned in the flags. 1343 if (left_side_constant_smi && right_side_constant_smi) {
1352 if (!left_side.reg().is(eax)) { 1344 // Trivial case, comparing two constants.
1353 right_side.ToRegister(eax); 1345 int left_value = Smi::cast(*left_side.handle())->value();
1354 left_side.ToRegister(edx); 1346 int right_value = Smi::cast(*right_side.handle())->value();
1355 } else if (!right_side.reg().is(edx)) { 1347 if (left_value < right_value &&
1356 left_side.ToRegister(edx); 1348 (cc == less || cc == less_equal || cc == not_equal) ||
1357 right_side.ToRegister(eax); 1349 left_value == right_value &&
1358 } else { 1350 (cc == less_equal || cc == equal || cc == greater_equal) ||
1359 frame_->Spill(eax); // Can be multiply referenced, even now. 1351 left_value > right_value &&
1360 frame_->Spill(edx); 1352 (cc == greater || cc == greater_equal || cc == not_equal)) {
1361 __ xchg(eax, edx); 1353 // Comparison is unconditionally true.
1362 // If left_side and right_side become real (non-dummy) arguments 1354 if (true_target->is_bound()) {
1363 // to CallStub, they need to be swapped in this case. 1355 true_target->Jump();
1356 } else {
1357 true_target->Bind();
1358 }
1359 } else { // Comparison is always false.
1360 if (false_target->is_bound()) {
1361 false_target->Jump();
1362 } else {
1363 false_target->Bind();
1364 }
1365 }
1366 } else { // Only one side is a constant Smi.
1367 // If left side is a constant Smi, reverse the operands.
1368 // Since one side is a constant Smi, conversion order does not matter.
1369 if (left_side_constant_smi) {
1370 Result temp = left_side;
1371 left_side = right_side;
1372 right_side = temp;
1373 cc = ReverseCondition(cc);
1374 }
1375 // Implement comparison against a constant Smi, inlining the case
1376 // where both sides are Smis.
1377 left_side.ToRegister();
1378 ASSERT(left_side.is_valid());
1379 JumpTarget is_smi(this);
1380 __ test(left_side.reg(), Immediate(kSmiTagMask));
1381 is_smi.Branch(zero, &left_side, &right_side, taken);
1382
1383 // Setup and call the compare stub, which expects arguments in edx
1384 // and eax.
1385 CompareStub stub(cc, strict);
1386 left_side.ToRegister(eax);
1387 right_side.ToRegister(edx);
1388 Result result = frame_->CallStub(&stub, &left_side, &right_side, 0);
1389 result.ToRegister();
1390 __ cmp(result.reg(), 0);
1391 result.Unuse();
1392 true_target->Branch(cc);
1393 false_target->Jump();
1394
1395 is_smi.Bind(&left_side, &right_side);
1396 left_side.ToRegister();
1397 // Test smi equality and comparison by signed int comparison.
1398 __ cmp(Operand(left_side.reg()), Immediate(right_side.handle()));
1399 left_side.Unuse();
1400 right_side.Unuse();
1401 Branch(cc, true_target, false_target, fall_through);
1402 }
1403 } else { // Neither side is a constant Smi, normal comparison operation.
1404 left_side.ToRegister();
1405 right_side.ToRegister();
1406 ASSERT(left_side.is_valid());
1407 ASSERT(right_side.is_valid());
1408 // Check for the smi case.
1409 JumpTarget is_smi(this);
1410 Result temp = allocator_->Allocate();
1411 ASSERT(temp.is_valid());
1412 __ mov(temp.reg(), left_side.reg());
1413 __ or_(temp.reg(), Operand(right_side.reg()));
1414 __ test(temp.reg(), Immediate(kSmiTagMask));
1415 temp.Unuse();
1416 is_smi.Branch(zero, &left_side, &right_side, taken);
1417
1418 // When non-smi, call out to the compare stub. "parameters" setup by
1419 // calling code in edx and eax and "result" is returned in the flags.
1420 if (!left_side.reg().is(eax)) {
1421 right_side.ToRegister(eax);
1422 left_side.ToRegister(edx);
1423 } else if (!right_side.reg().is(edx)) {
1424 left_side.ToRegister(edx);
1425 right_side.ToRegister(eax);
1426 } else {
1427 frame_->Spill(eax); // Can be multiply referenced, even now.
1428 frame_->Spill(edx);
1429 __ xchg(eax, edx);
1430 // If left_side and right_side become real (non-dummy) arguments
1431 // to CallStub, they need to be swapped in this case.
1432 }
1433 CompareStub stub(cc, strict);
1434 Result answer = frame_->CallStub(&stub, &right_side, &left_side, 0);
1435 if (cc == equal) {
1436 __ test(answer.reg(), Operand(answer.reg()));
1437 } else {
1438 __ cmp(answer.reg(), 0);
1439 }
1440 answer.Unuse();
1441 true_target->Branch(cc);
1442 false_target->Jump();
1443
1444 is_smi.Bind(&left_side, &right_side);
1445 left_side.ToRegister();
1446 right_side.ToRegister();
1447 __ cmp(left_side.reg(), Operand(right_side.reg()));
1448 right_side.Unuse();
1449 left_side.Unuse();
1450 Branch(cc, true_target, false_target, fall_through);
1364 } 1451 }
1365 CompareStub stub(cc, strict);
1366 Result answer = frame_->CallStub(&stub, &right_side, &left_side, 0);
1367 if (cc == equal) {
1368 __ test(answer.reg(), Operand(answer.reg()));
1369 } else {
1370 __ cmp(answer.reg(), 0);
1371 }
1372 answer.Unuse();
1373 true_target->Branch(cc);
1374 false_target->Jump();
1375
1376 is_smi.Bind(&left_side, &right_side);
1377 left_side.ToRegister();
1378 right_side.ToRegister();
1379 __ cmp(left_side.reg(), Operand(right_side.reg()));
1380 right_side.Unuse();
1381 left_side.Unuse();
1382 Branch(cc, true_target, false_target, fall_through);
1383 } 1452 }
1384 1453
1385 1454
1386 void CodeGenerator::SmiComparison(Condition cc, 1455 void CodeGenerator::SmiComparison(Condition cc,
1387 Handle<Object> smi_value, 1456 Handle<Object> smi_value,
1388 bool strict) { 1457 bool strict) {
1389 // Strict only makes sense for equality comparisons. 1458 // Strict only makes sense for equality comparisons.
1390 ASSERT(!strict || cc == equal); 1459 ASSERT(!strict || cc == equal);
1391 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits)); 1460 ASSERT(is_intn(Smi::cast(*smi_value)->value(), kMaxSmiInlinedBits));
1392 1461
(...skipping 552 matching lines...) Expand 10 before | Expand all | Expand 10 after
1945 for (int i = 0; i < length; i++) { 2014 for (int i = 0; i < length; i++) {
1946 CaseClause* clause = cases->at(i); 2015 CaseClause* clause = cases->at(i);
1947 if (clause->is_default()) { 2016 if (clause->is_default()) {
1948 // Remember the default clause and compile it at the end. 2017 // Remember the default clause and compile it at the end.
1949 default_clause = clause; 2018 default_clause = clause;
1950 continue; 2019 continue;
1951 } 2020 }
1952 2021
1953 // Compile each non-default clause. 2022 // Compile each non-default clause.
1954 Comment cmnt(masm_, "[ Case clause"); 2023 Comment cmnt(masm_, "[ Case clause");
1955 // Label and compile the test.
1956 if (next_test.is_linked()) { 2024 if (next_test.is_linked()) {
1957 // Recycle the same label for each test. 2025 // Recycle the same label for each test.
1958 next_test.Bind(); 2026 next_test.Bind();
1959 next_test.Unuse(); 2027 next_test.Unuse();
1960 } 2028 }
1961 // Duplicate the switch value. 2029
1962 frame_->Dup();
1963 Load(clause->label());
1964 JumpTarget enter_body(this); 2030 JumpTarget enter_body(this);
1965 Comparison(equal, true, &enter_body, &next_test, &enter_body); 2031 // Control flow reaches this test if it is the first non-default case,
2032 // or if a previous test links to this as the next test through the
2033 // next_test JumpTarget. If so, then has_valid_frame() is true.
2034 if (has_valid_frame()) {
2035 // Duplicate the switch value.
2036 frame_->Dup();
2037 Load(clause->label());
2038 Comparison(equal, true, &enter_body, &next_test, &enter_body);
2039 }
1966 2040
1967 // Before entering the body from the test remove the switch value from 2041 bool previous_was_default = (i > 0 && cases->at(i - 1)->is_default());
1968 // the frame. 2042 // If the body is unreachable, don't compile it.
1969 frame_->Drop(); 2043 if (!enter_body.is_bound() &&
2044 !previous_was_default &&
2045 !fall_through.is_linked()) {
2046 next_test.Unuse();
2047 continue;
2048 }
2049 // Compile the body, since it is reachable from the test or a fall-through.
2050 if (next_test.is_bound()) {
2051 // The test unconditionally failed, we should go to the next test.
2052 // We still need to compile the body for the fall-through cases.
2053 // In this case, we need to jump over the body.
2054 next_test.Unuse();
2055 next_test.Jump();
2056 } else if (enter_body.is_bound()) {
2057 // Otherwise we got here by passing the test.
2058 frame_->Drop(); // The switch value is no longer needed.
2059 } else {
2060 // The tests are being skipped due to an earlier unconditional match,
2061 // and only fall-through to bodies is generating control flow.
2062 ASSERT(!has_valid_frame());
2063 }
1970 2064
1971 // Label the body so that fall through is enabled. 2065 // Label the body so that fall through is enabled.
1972 if (i > 0 && cases->at(i - 1)->is_default()) { 2066 if (previous_was_default) {
1973 // The previous case was the default. This will be the target of a 2067 // Because the default is compiled last, there is always a potential
1974 // possible backward edge. 2068 // backwards edge to here, falling through from the default.
1975 default_exit.Bind(); 2069 default_exit.Bind();
1976 } else if (fall_through.is_linked()) { 2070 } else if (fall_through.is_linked()) {
1977 // Recycle the same label for each fall through except for the default 2071 // Recycle the same label for each fall through.
1978 // case.
1979 fall_through.Bind(); 2072 fall_through.Bind();
1980 fall_through.Unuse(); 2073 fall_through.Unuse();
1981 } 2074 }
1982 VisitStatements(clause->statements()); 2075 VisitStatements(clause->statements());
1983 2076
1984 // If control flow can fall through from the body jump to the next body 2077 // If control flow can fall through from the body jump to the next body
1985 // or the end of the statement. 2078 // or the end of the statement.
1986 if (has_valid_frame()) { 2079 if (has_valid_frame()) {
1987 if (i < length - 1 && cases->at(i + 1)->is_default()) { 2080 if (i < length - 1 && cases->at(i + 1)->is_default()) {
1988 // The next case is the default. 2081 // The next case is the default.
1989 default_entry.Jump(); 2082 default_entry.Jump();
1990 } else { 2083 } else {
1991 fall_through.Jump(); 2084 fall_through.Jump();
1992 } 2085 }
1993 } 2086 }
1994 } 2087 }
1995 2088
1996 // The block at the final "test" label removes the switch value. 2089 // The block at the final "test" label removes the switch value.
1997 next_test.Bind(); 2090 if (next_test.is_linked()) {
1998 frame_->Drop(); 2091 // JumpTarget next_test could have been bound, rather than linked to,
1999 2092 // if the previous test was unconditionally false.
2000 // If there is a default clause, compile it now. 2093 next_test.Bind();
2094 }
2095 if (has_valid_frame()) {
2096 frame_->Drop();
2097 }
2098 // If there is a default clause, compile it now. If it is determined
2099 // at compile time to be unreachable, then it has no valid entry frame,
2100 // and it is not compiled.
2001 if (default_clause != NULL) { 2101 if (default_clause != NULL) {
2002 Comment cmnt(masm_, "[ Default clause"); 2102 Comment cmnt(masm_, "[ Default clause");
2003 default_entry.Bind(); 2103 default_entry.Bind();
2004 VisitStatements(default_clause->statements()); 2104 if (has_valid_frame()) {
2105 VisitStatements(default_clause->statements());
2106 }
2005 // If control flow can fall out of the default and there is a case after 2107 // If control flow can fall out of the default and there is a case after
2006 // it, jump to that case's body. 2108 // it, jump to that case's body.
2007 if (has_valid_frame() && default_exit.is_bound()) { 2109 if (has_valid_frame() && default_exit.is_bound()) {
2008 default_exit.Jump(); 2110 default_exit.Jump();
2009 } 2111 }
2010 } 2112 }
2011 2113
2012 fall_through.Bind(); 2114 fall_through.Bind();
2013 node->break_target()->Bind(); 2115 node->break_target()->Bind();
2014 } 2116 }
(...skipping 4335 matching lines...) Expand 10 before | Expand all | Expand 10 after
6350 6452
6351 // Slow-case: Go through the JavaScript implementation. 6453 // Slow-case: Go through the JavaScript implementation.
6352 __ bind(&slow); 6454 __ bind(&slow);
6353 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION); 6455 __ InvokeBuiltin(Builtins::INSTANCE_OF, JUMP_FUNCTION);
6354 } 6456 }
6355 6457
6356 6458
6357 #undef __ 6459 #undef __
6358 6460
6359 } } // namespace v8::internal 6461 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698