Home | History | Annotate | Download | only in optimizing
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include "dead_code_elimination.h"
     18 
     19 #include "driver/compiler_options.h"
     20 #include "graph_checker.h"
     21 #include "optimizing_unit_test.h"
     22 #include "pretty_printer.h"
     23 
     24 #include "gtest/gtest.h"
     25 
     26 namespace art {
     27 
     28 class DeadCodeEliminationTest : public OptimizingUnitTest {
     29  protected:
     30   void TestCode(const std::vector<uint16_t>& data,
     31                 const std::string& expected_before,
     32                 const std::string& expected_after);
     33 };
     34 
     35 void DeadCodeEliminationTest::TestCode(const std::vector<uint16_t>& data,
     36                                        const std::string& expected_before,
     37                                        const std::string& expected_after) {
     38   HGraph* graph = CreateCFG(data);
     39   ASSERT_NE(graph, nullptr);
     40 
     41   StringPrettyPrinter printer_before(graph);
     42   printer_before.VisitInsertionOrder();
     43   std::string actual_before = printer_before.str();
     44   ASSERT_EQ(actual_before, expected_before);
     45 
     46   HDeadCodeElimination(graph, /* stats= */ nullptr, "dead_code_elimination").Run();
     47   GraphChecker graph_checker(graph);
     48   graph_checker.Run();
     49   ASSERT_TRUE(graph_checker.IsValid());
     50 
     51   StringPrettyPrinter printer_after(graph);
     52   printer_after.VisitInsertionOrder();
     53   std::string actual_after = printer_after.str();
     54   ASSERT_EQ(actual_after, expected_after);
     55 }
     56 
     57 /**
     58  * Small three-register program.
     59  *
     60  *                              16-bit
     61  *                              offset
     62  *                              ------
     63  *     v1 <- 1                  0.      const/4 v1, #+1
     64  *     v0 <- 0                  1.      const/4 v0, #+0
     65  *     if v1 >= 0 goto L1       2.      if-gez v1, +3
     66  *     v0 <- v1                 4.      move v0, v1
     67  * L1: v2 <- v0 + v1            5.      add-int v2, v0, v1
     68  *     return-void              7.      return
     69  */
     70 TEST_F(DeadCodeEliminationTest, AdditionAndConditionalJump) {
     71   const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
     72     Instruction::CONST_4 | 1 << 8 | 1 << 12,
     73     Instruction::CONST_4 | 0 << 8 | 0 << 12,
     74     Instruction::IF_GEZ | 1 << 8, 3,
     75     Instruction::MOVE | 0 << 8 | 1 << 12,
     76     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
     77     Instruction::RETURN_VOID);
     78 
     79   std::string expected_before =
     80       "BasicBlock 0, succ: 1\n"
     81       "  3: IntConstant [9, 8, 5]\n"
     82       "  4: IntConstant [8, 5]\n"
     83       "  1: SuspendCheck\n"
     84       "  2: Goto 1\n"
     85       "BasicBlock 1, pred: 0, succ: 5, 2\n"
     86       "  5: GreaterThanOrEqual(3, 4) [6]\n"
     87       "  6: If(5)\n"
     88       "BasicBlock 2, pred: 1, succ: 3\n"
     89       "  7: Goto 3\n"
     90       "BasicBlock 3, pred: 5, 2, succ: 4\n"
     91       "  8: Phi(4, 3) [9]\n"
     92       "  9: Add(8, 3)\n"
     93       "  10: ReturnVoid\n"
     94       "BasicBlock 4, pred: 3\n"
     95       "  11: Exit\n"
     96       "BasicBlock 5, pred: 1, succ: 3\n"
     97       "  0: Goto 3\n";
     98 
     99   // Expected difference after dead code elimination.
    100   diff_t expected_diff = {
    101     { "  3: IntConstant [9, 8, 5]\n",  "  3: IntConstant [8, 5]\n" },
    102     { "  8: Phi(4, 3) [9]\n",          "  8: Phi(4, 3)\n" },
    103     { "  9: Add(8, 3)\n",              removed }
    104   };
    105   std::string expected_after = Patch(expected_before, expected_diff);
    106 
    107   TestCode(data, expected_before, expected_after);
    108 }
    109 
    110 /**
    111  * Three-register program with jumps leading to the creation of many
    112  * blocks.
    113  *
    114  * The intent of this test is to ensure that all dead instructions are
    115  * actually pruned at compile-time, thanks to the (backward)
    116  * post-order traversal of the the dominator tree.
    117  *
    118  *                              16-bit
    119  *                              offset
    120  *                              ------
    121  *     v0 <- 0                   0.     const/4 v0, #+0
    122  *     v1 <- 1                   1.     const/4 v1, #+1
    123  *     v2 <- v0 + v1             2.     add-int v2, v0, v1
    124  *     goto L2                   4.     goto +4
    125  * L1: v1 <- v0 + 3              5.     add-int/lit16 v1, v0, #+3
    126  *     goto L3                   7.     goto +4
    127  * L2: v0 <- v2 + 2              8.     add-int/lit16 v0, v2, #+2
    128  *     goto L1                  10.     goto +(-5)
    129  * L3: v2 <- v1 + 4             11.     add-int/lit16 v2, v1, #+4
    130  *     return                   13.     return-void
    131  */
    132 TEST_F(DeadCodeEliminationTest, AdditionsAndInconditionalJumps) {
    133   const std::vector<uint16_t> data = THREE_REGISTERS_CODE_ITEM(
    134     Instruction::CONST_4 | 0 << 8 | 0 << 12,
    135     Instruction::CONST_4 | 1 << 8 | 1 << 12,
    136     Instruction::ADD_INT | 2 << 8, 0 | 1 << 8,
    137     Instruction::GOTO | 4 << 8,
    138     Instruction::ADD_INT_LIT16 | 1 << 8 | 0 << 12, 3,
    139     Instruction::GOTO | 4 << 8,
    140     Instruction::ADD_INT_LIT16 | 0 << 8 | 2 << 12, 2,
    141     static_cast<uint16_t>(Instruction::GOTO | 0xFFFFFFFB << 8),
    142     Instruction::ADD_INT_LIT16 | 2 << 8 | 1 << 12, 4,
    143     Instruction::RETURN_VOID);
    144 
    145   std::string expected_before =
    146       "BasicBlock 0, succ: 1\n"
    147       "  2: IntConstant [4]\n"
    148       "  3: IntConstant [4]\n"
    149       "  6: IntConstant [7]\n"
    150       "  9: IntConstant [10]\n"
    151       "  12: IntConstant [13]\n"
    152       "  0: SuspendCheck\n"
    153       "  1: Goto 1\n"
    154       "BasicBlock 1, pred: 0, succ: 3\n"
    155       "  4: Add(2, 3) [7]\n"
    156       "  5: Goto 3\n"
    157       "BasicBlock 2, pred: 3, succ: 4\n"
    158       "  10: Add(7, 9) [13]\n"
    159       "  11: Goto 4\n"
    160       "BasicBlock 3, pred: 1, succ: 2\n"
    161       "  7: Add(4, 6) [10]\n"
    162       "  8: Goto 2\n"
    163       "BasicBlock 4, pred: 2, succ: 5\n"
    164       "  13: Add(10, 12)\n"
    165       "  14: ReturnVoid\n"
    166       "BasicBlock 5, pred: 4\n"
    167       "  15: Exit\n";
    168 
    169   std::string expected_after =
    170       "BasicBlock 0, succ: 1\n"
    171       "  0: SuspendCheck\n"
    172       "  1: Goto 1\n"
    173       "BasicBlock 1, pred: 0, succ: 5\n"
    174       "  14: ReturnVoid\n"
    175       "BasicBlock 5, pred: 1\n"
    176       "  15: Exit\n";
    177 
    178   TestCode(data, expected_before, expected_after);
    179 }
    180 
    181 }  // namespace art
    182