101e04c3fSmrg/*
201e04c3fSmrg * Copyright © 2010 Intel Corporation
301e04c3fSmrg *
401e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a
501e04c3fSmrg * copy of this software and associated documentation files (the "Software"),
601e04c3fSmrg * to deal in the Software without restriction, including without limitation
701e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
801e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the
901e04c3fSmrg * Software is furnished to do so, subject to the following conditions:
1001e04c3fSmrg *
1101e04c3fSmrg * The above copyright notice and this permission notice (including the next
1201e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the
1301e04c3fSmrg * Software.
1401e04c3fSmrg *
1501e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1601e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1701e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
1801e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1901e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2001e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2101e04c3fSmrg * DEALINGS IN THE SOFTWARE.
2201e04c3fSmrg */
2301e04c3fSmrg
2401e04c3fSmrg/**
2501e04c3fSmrg * \file opt_if_simplification.cpp
2601e04c3fSmrg *
2701e04c3fSmrg * Moves constant branches of if statements out to the surrounding
2801e04c3fSmrg * instruction stream, and inverts if conditionals to avoid empty
2901e04c3fSmrg * "then" blocks.
3001e04c3fSmrg */
3101e04c3fSmrg
3201e04c3fSmrg#include "ir.h"
3301e04c3fSmrg
3401e04c3fSmrgnamespace {
3501e04c3fSmrg
3601e04c3fSmrgclass ir_if_simplification_visitor : public ir_hierarchical_visitor {
3701e04c3fSmrgpublic:
3801e04c3fSmrg   ir_if_simplification_visitor()
3901e04c3fSmrg   {
4001e04c3fSmrg      this->made_progress = false;
4101e04c3fSmrg   }
4201e04c3fSmrg
4301e04c3fSmrg   ir_visitor_status visit_leave(ir_if *);
4401e04c3fSmrg   ir_visitor_status visit_enter(ir_assignment *);
4501e04c3fSmrg
4601e04c3fSmrg   bool made_progress;
4701e04c3fSmrg};
4801e04c3fSmrg
4901e04c3fSmrg} /* unnamed namespace */
5001e04c3fSmrg
5101e04c3fSmrg/* We only care about the top level "if" instructions, so don't
5201e04c3fSmrg * descend into expressions.
5301e04c3fSmrg */
5401e04c3fSmrgir_visitor_status
5501e04c3fSmrgir_if_simplification_visitor::visit_enter(ir_assignment *ir)
5601e04c3fSmrg{
5701e04c3fSmrg   (void) ir;
5801e04c3fSmrg   return visit_continue_with_parent;
5901e04c3fSmrg}
6001e04c3fSmrg
6101e04c3fSmrgbool
6201e04c3fSmrgdo_if_simplification(exec_list *instructions)
6301e04c3fSmrg{
6401e04c3fSmrg   ir_if_simplification_visitor v;
6501e04c3fSmrg
6601e04c3fSmrg   v.run(instructions);
6701e04c3fSmrg   return v.made_progress;
6801e04c3fSmrg}
6901e04c3fSmrg
7001e04c3fSmrg
7101e04c3fSmrgir_visitor_status
7201e04c3fSmrgir_if_simplification_visitor::visit_leave(ir_if *ir)
7301e04c3fSmrg{
7401e04c3fSmrg   /* If the if statement has nothing on either side, remove it. */
7501e04c3fSmrg   if (ir->then_instructions.is_empty() &&
7601e04c3fSmrg       ir->else_instructions.is_empty()) {
7701e04c3fSmrg      ir->remove();
7801e04c3fSmrg      this->made_progress = true;
7901e04c3fSmrg      return visit_continue;
8001e04c3fSmrg   }
8101e04c3fSmrg
8201e04c3fSmrg   /* FINISHME: Ideally there would be a way to note that the condition results
8301e04c3fSmrg    * FINISHME: in a constant before processing both of the other subtrees.
8401e04c3fSmrg    * FINISHME: This can probably be done with some flags, but it would take
8501e04c3fSmrg    * FINISHME: some work to get right.
8601e04c3fSmrg    */
8701e04c3fSmrg   ir_constant *condition_constant =
8801e04c3fSmrg      ir->condition->constant_expression_value(ralloc_parent(ir));
8901e04c3fSmrg   if (condition_constant) {
9001e04c3fSmrg      /* Move the contents of the one branch of the conditional
9101e04c3fSmrg       * that matters out.
9201e04c3fSmrg       */
9301e04c3fSmrg      if (condition_constant->value.b[0]) {
9401e04c3fSmrg         ir->insert_before(&ir->then_instructions);
9501e04c3fSmrg      } else {
9601e04c3fSmrg         ir->insert_before(&ir->else_instructions);
9701e04c3fSmrg      }
9801e04c3fSmrg      ir->remove();
9901e04c3fSmrg      this->made_progress = true;
10001e04c3fSmrg      return visit_continue;
10101e04c3fSmrg   }
10201e04c3fSmrg
10301e04c3fSmrg   /* Turn:
10401e04c3fSmrg    *
10501e04c3fSmrg    *     if (cond) {
10601e04c3fSmrg    *     } else {
10701e04c3fSmrg    *         do_work();
10801e04c3fSmrg    *     }
10901e04c3fSmrg    *
11001e04c3fSmrg    * into :
11101e04c3fSmrg    *
11201e04c3fSmrg    *     if (!cond)
11301e04c3fSmrg    *         do_work();
11401e04c3fSmrg    *
11501e04c3fSmrg    * which avoids control flow for "else" (which is usually more
11601e04c3fSmrg    * expensive than normal operations), and the "not" can usually be
11701e04c3fSmrg    * folded into the generation of "cond" anyway.
11801e04c3fSmrg    */
11901e04c3fSmrg   if (ir->then_instructions.is_empty()) {
12001e04c3fSmrg      ir->condition = new(ralloc_parent(ir->condition))
12101e04c3fSmrg	 ir_expression(ir_unop_logic_not, ir->condition);
12201e04c3fSmrg      ir->else_instructions.move_nodes_to(&ir->then_instructions);
12301e04c3fSmrg      this->made_progress = true;
12401e04c3fSmrg   }
12501e04c3fSmrg
12601e04c3fSmrg   return visit_continue;
12701e04c3fSmrg}
128