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

Side by Side Diff: src/hydrogen.cc

Issue 6650021: Refactor construction of switch statements to avoid subgraphs. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 9 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 | « src/hydrogen.h ('k') | src/ia32/full-codegen-ia32.cc » ('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 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 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 2342 matching lines...) Expand 10 before | Expand all | Expand 10 after
2353 } 2353 }
2354 2354
2355 2355
2356 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { 2356 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) {
2357 HBasicBlock* b = graph()->CreateBasicBlock(); 2357 HBasicBlock* b = graph()->CreateBasicBlock();
2358 b->SetInitialEnvironment(env); 2358 b->SetInitialEnvironment(env);
2359 return b; 2359 return b;
2360 } 2360 }
2361 2361
2362 2362
2363 HSubgraph* HGraphBuilder::CreateEmptySubgraph() {
2364 HSubgraph* subgraph = new HSubgraph(graph());
2365 subgraph->Initialize(graph()->CreateBasicBlock());
2366 return subgraph;
2367 }
2368
2369
2370 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { 2363 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() {
2371 HBasicBlock* header = graph()->CreateBasicBlock(); 2364 HBasicBlock* header = graph()->CreateBasicBlock();
2372 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); 2365 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header);
2373 header->SetInitialEnvironment(entry_env); 2366 header->SetInitialEnvironment(entry_env);
2374 header->AttachLoopInformation(); 2367 header->AttachLoopInformation();
2375 return header; 2368 return header;
2376 } 2369 }
2377 2370
2378 2371
2379 void HGraphBuilder::VisitBlock(Block* stmt) { 2372 void HGraphBuilder::VisitBlock(Block* stmt) {
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
2507 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) { 2500 void HGraphBuilder::VisitWithEnterStatement(WithEnterStatement* stmt) {
2508 BAILOUT("WithEnterStatement"); 2501 BAILOUT("WithEnterStatement");
2509 } 2502 }
2510 2503
2511 2504
2512 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) { 2505 void HGraphBuilder::VisitWithExitStatement(WithExitStatement* stmt) {
2513 BAILOUT("WithExitStatement"); 2506 BAILOUT("WithExitStatement");
2514 } 2507 }
2515 2508
2516 2509
2517 HCompare* HGraphBuilder::BuildSwitchCompare(HSubgraph* subgraph,
2518 HValue* switch_value,
2519 CaseClause* clause) {
2520 AddToSubgraph(subgraph, clause->label());
2521 if (HasStackOverflow()) return NULL;
2522 HValue* clause_value = subgraph->exit_block()->last_environment()->Pop();
2523 HCompare* compare = new HCompare(switch_value,
2524 clause_value,
2525 Token::EQ_STRICT);
2526 compare->SetInputRepresentation(Representation::Integer32());
2527 subgraph->exit_block()->AddInstruction(compare);
2528 return compare;
2529 }
2530
2531
2532 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) { 2510 void HGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
2511 // We only optimize switch statements with smi-literal smi comparisons,
2512 // with a bounded number of clauses.
2513 const int kCaseClauseLimit = 128;
2514 ZoneList<CaseClause*>* clauses = stmt->cases();
2515 int clause_count = clauses->length();
2516 if (clause_count > kCaseClauseLimit) {
2517 BAILOUT("SwitchStatement: too many clauses");
2518 }
2519
2533 VISIT_FOR_VALUE(stmt->tag()); 2520 VISIT_FOR_VALUE(stmt->tag());
2534 // TODO(3168478): simulate added for tag should be enough. 2521 HValue* tag_value = Pop();
2535 AddSimulate(stmt->EntryId()); 2522 HBasicBlock* first_test_block = current_block();
2536 HValue* switch_value = Pop();
2537 2523
2538 ZoneList<CaseClause*>* clauses = stmt->cases(); 2524 // 1. Build all the tests, with dangling true branches. Unconditionally
2539 int num_clauses = clauses->length(); 2525 // deoptimize if we encounter a non-smi comparison.
2540 if (num_clauses == 0) return; 2526 for (int i = 0; i < clause_count; ++i) {
2541 if (num_clauses > 128) BAILOUT("SwitchStatement: too many clauses");
2542
2543 int num_smi_clauses = num_clauses;
2544 for (int i = 0; i < num_clauses; i++) {
2545 CaseClause* clause = clauses->at(i); 2527 CaseClause* clause = clauses->at(i);
2546 if (clause->is_default()) continue; 2528 if (clause->is_default()) continue;
2547 clause->RecordTypeFeedback(oracle());
2548 if (!clause->IsSmiCompare()) {
2549 if (i == 0) BAILOUT("SwitchStatement: no smi compares");
2550 // We will deoptimize if the first non-smi compare is reached.
2551 num_smi_clauses = i;
2552 break;
2553 }
2554 if (!clause->label()->IsSmiLiteral()) { 2529 if (!clause->label()->IsSmiLiteral()) {
2555 BAILOUT("SwitchStatement: non-literal switch label"); 2530 BAILOUT("SwitchStatement: non-literal switch label");
2556 } 2531 }
2532
2533 // Unconditionally deoptimize on the first non-smi compare.
2534 clause->RecordTypeFeedback(oracle());
2535 if (!clause->IsSmiCompare()) {
2536 if (current_block() == first_test_block) {
2537 // If the first test is the one that deopts and if the tag value is
2538 // a phi, we need to have some use of that phi to prevent phi
2539 // elimination from removing it. This HSimulate is such a use.
2540 Push(tag_value);
2541 AddSimulate(stmt->EntryId());
2542 Drop(1);
2543 }
2544 current_block()->Finish(new HDeoptimize());
2545 set_current_block(NULL);
2546 break;
2547 }
2548
2549 // Otherwise generate a compare and branch.
2550 VISIT_FOR_VALUE(clause->label());
2551 HValue* label_value = Pop();
2552 HCompare* compare = new HCompare(tag_value, label_value, Token::EQ_STRICT);
2553 compare->SetInputRepresentation(Representation::Integer32());
2554 ASSERT(!compare->HasSideEffects());
2555 AddInstruction(compare);
2556 HBasicBlock* body_block = graph()->CreateBasicBlock();
2557 HBasicBlock* next_test_block = graph()->CreateBasicBlock();
2558 HTest* branch = new HTest(compare, body_block, next_test_block);
2559 current_block()->Finish(branch);
2560 set_current_block(next_test_block);
2557 } 2561 }
2558 2562
2559 // The single exit block of the whole switch statement. 2563 // Save the current block for to use for the default or to join with the
2560 HBasicBlock* single_exit_block = graph_->CreateBasicBlock(); 2564 // exit. This block can be NULL if we deoptimized.
2565 HBasicBlock* last_block = current_block();
2561 2566
2562 // Build a series of empty subgraphs for the comparisons. 2567 // 2. Loop over the clauses and the linked list of tests in lockstep,
2563 // The default clause does not have a comparison subgraph. 2568 // translating the clause bodies.
2564 ZoneList<HSubgraph*> compare_graphs(num_smi_clauses); 2569 HBasicBlock* curr_test_block = first_test_block;
2565 for (int i = 0; i < num_smi_clauses; i++) { 2570 HBasicBlock* fall_through_block = NULL;
2566 if (clauses->at(i)->is_default()) { 2571 BreakAndContinueInfo break_info(stmt);
2567 compare_graphs.Add(NULL); 2572 { BreakAndContinueScope push(&break_info, this);
2568 } else { 2573 for (int i = 0; i < clause_count; ++i) {
2569 compare_graphs.Add(CreateEmptySubgraph()); 2574 CaseClause* clause = clauses->at(i);
2575
2576 // Identify the block where normal (non-fall-through) control flow
2577 // comes from.
2578 HBasicBlock* normal_block = NULL;
2579 if (clause->is_default()) {
2580 normal_block = last_block;
2581 last_block = NULL; // Cleared to indicate we've handled it.
2582 } else if (!curr_test_block->end()->IsDeoptimize()) {
2583 normal_block = curr_test_block->end()->FirstSuccessor();
2584 curr_test_block = curr_test_block->end()->SecondSuccessor();
2585 }
2586
2587 // Identify a block to emit the body into.
2588 if (normal_block == NULL) {
2589 if (fall_through_block == NULL) {
2590 // (a) Unreachable.
2591 continue;
2592 } else {
2593 // (b) Reachable only as fall through.
2594 set_current_block(fall_through_block);
2595 }
2596 } else if (fall_through_block == NULL) {
2597 // (c) Reachable only normally.
2598 set_current_block(normal_block);
2599 } else {
2600 // (d) Reachable both ways.
2601 HBasicBlock* join = CreateJoin(fall_through_block,
2602 normal_block,
2603 clause->EntryId());
2604 set_current_block(join);
2605 }
2606
2607 VisitStatements(clause->statements());
2608 CHECK_BAILOUT;
2609 fall_through_block = current_block();
2570 } 2610 }
2571 } 2611 }
2572 2612
2573 HSubgraph* prev_graph = current_subgraph_; 2613 // Create an up-to-3-way join. Use the break block if it exists since
2574 HCompare* prev_compare_inst = NULL; 2614 // it's already a join block.
2575 for (int i = 0; i < num_smi_clauses; i++) { 2615 HBasicBlock* break_block = break_info.break_block();
2576 CaseClause* clause = clauses->at(i); 2616 if (break_block == NULL) {
2577 if (clause->is_default()) continue; 2617 set_current_block(CreateJoin(fall_through_block,
2578 2618 last_block,
2579 // Finish the previous graph by connecting it to the current. 2619 stmt->ExitId()));
2580 HSubgraph* subgraph = compare_graphs.at(i);
2581 if (prev_compare_inst == NULL) {
2582 ASSERT(prev_graph == current_subgraph_);
2583 prev_graph->exit_block()->Finish(new HGoto(subgraph->entry_block()));
2584 } else {
2585 HBasicBlock* empty = graph()->CreateBasicBlock();
2586 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
2587 empty,
2588 subgraph->entry_block()));
2589 }
2590
2591 // Build instructions for current subgraph.
2592 ASSERT(clause->IsSmiCompare());
2593 prev_compare_inst = BuildSwitchCompare(subgraph, switch_value, clause);
2594 if (HasStackOverflow()) return;
2595
2596 prev_graph = subgraph;
2597 }
2598
2599 // Finish last comparison if there was at least one comparison.
2600 // last_false_block is the (empty) false-block of the last comparison. If
2601 // there are no comparisons at all (a single default clause), it is just
2602 // the last block of the current subgraph.
2603 HBasicBlock* last_false_block = current_block();
2604 if (prev_graph != current_subgraph_) {
2605 last_false_block = graph()->CreateBasicBlock();
2606 HBasicBlock* empty = graph()->CreateBasicBlock();
2607 prev_graph->exit_block()->Finish(new HTest(prev_compare_inst,
2608 empty,
2609 last_false_block));
2610 }
2611
2612 // If we have a non-smi compare clause, we deoptimize after trying
2613 // all the previous compares.
2614 if (num_smi_clauses < num_clauses) {
2615 last_false_block->Finish(new HDeoptimize);
2616 }
2617
2618 // Build statement blocks, connect them to their comparison block and
2619 // to the previous statement block, if there is a fall-through.
2620 HSubgraph* previous_subgraph = NULL;
2621 for (int i = 0; i < num_clauses; i++) {
2622 CaseClause* clause = clauses->at(i);
2623 // Subgraph for the statements of the clause is only created when
2624 // it's reachable either from the corresponding compare or as a
2625 // fall-through from previous statements.
2626 HSubgraph* subgraph = NULL;
2627
2628 if (i < num_smi_clauses) {
2629 if (clause->is_default()) {
2630 if (!last_false_block->IsFinished()) {
2631 // Default clause: Connect it to the last false block.
2632 subgraph = CreateEmptySubgraph();
2633 last_false_block->Finish(new HGoto(subgraph->entry_block()));
2634 }
2635 } else {
2636 ASSERT(clause->IsSmiCompare());
2637 // Connect with the corresponding comparison.
2638 subgraph = CreateEmptySubgraph();
2639 HBasicBlock* empty =
2640 compare_graphs.at(i)->exit_block()->end()->FirstSuccessor();
2641 empty->Finish(new HGoto(subgraph->entry_block()));
2642 }
2643 }
2644
2645 // Check for fall-through from previous statement block.
2646 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
2647 if (subgraph == NULL) subgraph = CreateEmptySubgraph();
2648 previous_subgraph->exit_block()->
2649 Finish(new HGoto(subgraph->entry_block()));
2650 }
2651
2652 if (subgraph != NULL) {
2653 BreakAndContinueInfo break_info(stmt);
2654 { BreakAndContinueScope push(&break_info, this);
2655 ADD_TO_SUBGRAPH(subgraph, clause->statements());
2656 }
2657 if (break_info.break_block() != NULL) {
2658 break_info.break_block()->SetJoinId(stmt->ExitId());
2659 break_info.break_block()->Finish(new HGoto(single_exit_block));
2660 }
2661 }
2662
2663 previous_subgraph = subgraph;
2664 }
2665
2666 // If the last statement block has a fall-through, connect it to the
2667 // single exit block.
2668 if (previous_subgraph != NULL && previous_subgraph->exit_block() != NULL) {
2669 previous_subgraph->exit_block()->Finish(new HGoto(single_exit_block));
2670 }
2671
2672 // If there is no default clause finish the last comparison's false target.
2673 if (!last_false_block->IsFinished()) {
2674 last_false_block->Finish(new HGoto(single_exit_block));
2675 }
2676
2677 if (single_exit_block->HasPredecessor()) {
2678 set_current_block(single_exit_block);
2679 } else { 2620 } else {
2680 set_current_block(NULL); 2621 if (fall_through_block != NULL) fall_through_block->Goto(break_block);
2622 if (last_block != NULL) last_block->Goto(break_block);
2623 break_block->SetJoinId(stmt->ExitId());
2624 set_current_block(break_block);
2681 } 2625 }
2682 } 2626 }
2683 2627
2628
2684 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) { 2629 bool HGraphBuilder::HasOsrEntryAt(IterationStatement* statement) {
2685 return statement->OsrEntryId() == info()->osr_ast_id(); 2630 return statement->OsrEntryId() == info()->osr_ast_id();
2686 } 2631 }
2687 2632
2688 2633
2689 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) { 2634 void HGraphBuilder::PreProcessOsrEntry(IterationStatement* statement) {
2690 if (!HasOsrEntryAt(statement)) return; 2635 if (!HasOsrEntryAt(statement)) return;
2691 2636
2692 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock(); 2637 HBasicBlock* non_osr_entry = graph()->CreateBasicBlock();
2693 HBasicBlock* osr_entry = graph()->CreateBasicBlock(); 2638 HBasicBlock* osr_entry = graph()->CreateBasicBlock();
(...skipping 3297 matching lines...) Expand 10 before | Expand all | Expand 10 after
5991 } 5936 }
5992 } 5937 }
5993 5938
5994 #ifdef DEBUG 5939 #ifdef DEBUG
5995 if (graph_ != NULL) graph_->Verify(); 5940 if (graph_ != NULL) graph_->Verify();
5996 if (allocator_ != NULL) allocator_->Verify(); 5941 if (allocator_ != NULL) allocator_->Verify();
5997 #endif 5942 #endif
5998 } 5943 }
5999 5944
6000 } } // namespace v8::internal 5945 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/hydrogen.h ('k') | src/ia32/full-codegen-ia32.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698